External Refs:
-ºKey Conceptsº
- @[https://docs.corda.net/_static/corda-technical-whitepaper.pdf]
- @[https://www.youtube.com/watch?v=CKRfVlwRl2M&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N]
- @[https://docs.corda.net/key-concepts.html]
(network, ledger, Identity,
States, Contracts, TXs, Flows, Consensus,
Notaries, Time-windows, Oracles, Nodes,..
-ºTradeoffsº
@[https://docs.corda.net/key-concepts-tradeoffs.html]:
Permissioned vs. permissionless
Point-to-point vs. global broadcasts
UTXO vs. account model
Code-is-law vs. existing legal systems
Build vs. re-use
- Corda sample (tutorial refs):
@[https://github.com/corda/samples]
- Corda Bootcamp 19 - Running our CorDapp:
https://www.youtube.com/watch?v=BmRMQsJSDMg&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N&index=19
https://www.youtube.com/watch?v=udaL_5n8kjU&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N&index=20
- Asset Trading(irs-demo):
@[https://docs.corda.net/running-the-demos.html#irs-demo]
- SIMM and Portfolio Demo(aka the Initial Margin Agreement Demo)
@[https://docs.corda.net/running-the-demos.html#simm-demo]
- JAVA TEMPLATE :@[https://github.com/corda/cordapp-template-java]
- KOTLIN TEMPLATE :@[https://github.com/corda/cordapp-template-kotlin]
- Hello World! :@[https://docs.corda.net/tutorial-cordapp.html]
- Building a CorDapp :@[https://docs.corda.net/cordapp-build-systems.html]
- API Docs :@[https://docs.corda.net/api-index.html]
- Official Cheatsheet:@[https://docs.corda.net/cheat-sheet.html]
- Flow cookbook :@[https://docs.corda.net/flow-cookbook.html]
@[how to perform common flow tasks]
- Sample CorDapps :@[https://www.corda.net/samples/]
Official Cheatsheet
@[https://docs.corda.net/_images/cheatsheet.jpg]
@[https://docs.corda.net/docs/corda-os/4.4/cheat-sheet.html]
┌───────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────┐
│QºRUNNING CORDA:º │ │QºFLOWSº │
│ a.Set up your dev envirnoment │ │ FlowLogic │
│ @[https://docs.corda.net/getting-set-up.html] │ │ The actions executed by one side of a flow │
│ b.Clone the template app in Kotlin|Java │ │ .initiateFlow(Party) │
│ git clone │ │ Initiates communication between two flows. │
│ ${GITHUB}/corda/cordapp-template-kotlin] │ │ FlowSession.end(Party,Any)/FlowSession.receive(Party) │
│ c.Check out the latest version(e.g. V2) │ │ Sends data to/receives data from the specified │
│ cd cordapp-template-kotlin │ │ counterparty │
│ git checkout release-V2 │ │ .subFlow(FlowLogic˂R˃, Boolean) │
│ d.Deploy the nodes │ │ Invokes a sub-flow that may return a result │
│ ./gradlew clean deployNodes │ │ .serviceHub │
│ e.Run the nodes │ │ Provides access to the node's services │
│ $ sh kotlin─source/build/nodes/runnodes │ └────────────────────────────────────────────────────────┘
│ │ ┌──────────────────────────────────────────────────────┐
│QºSTATES:º │ │QºFLOW ANNOTATIONSº │
│ ºContractStateº │ │ º@InitiatingFlowº │
│ - The base class for on-ledger states │ │ A flow that is started directly │
│ representing a SHARED fact (1+ parties) │ │ º@InitiatingBy(KClass)º │
│ º.participantsº │ │ A flow that is only started by a message from │
│ The parties for which this state is relevant │ │ an InitiatingFlow │
│ └ºLinearStateº (extends ContractState) │ │ º@StartableByRPCº │
│ represents State evolving over time │ │ Allows the flow to be started via RPC by the node's │
│ .linearId │ │ owner │
│ An ID shared by all evolutions of the 'shared fact' │ └──────────────────────────────────────────────────────┘
│ └ºOwnableStateº (extends ContractState) │
│ State representing fungible assets (cash, oil,...) │ ┌───────────────────────────────────────────────────┐
│ º.ownerº │ │QºSERVICE HUBº │
│ The state's current owner │ │ º.networkMapCacheº │
│ .withNewOwner(AbstractParty) │ │ Provides info on other nodes on the network │
│ Creates a copy of the state with a new owner │ │ (notaries,...) │
│ │ │ º.vaultServiceº │
│QºCONTRACTS:º │ │ Stores the node's current and historic states │
│ ºContractº Establishes which transactions are valid │ │ º.validatedTransactionsº │
│ for a given state │ │ Stores all the transactions seen by the node │
│ └º.verifyº(LedgerTransaction) │ │ º.keyManagementServiceº │
│ Throws an exception if the TX is invalid │ │ Manages the node's digital signing keys │
│ │ │ º.myInfoº │
│QºTRANSACTIONSº │ │ Other information about the node │
│ ºTransactionBuilderº │ │ º.clockº │
│ A mutable container for building a general TX │ │ Provides access to the node's internal time/date │
│ └º.withItemsº(varag Any) │ └───────────────────────────────────────────────────┘
│ Adds items (states, commands...) to the builder │ ┌────────────────────────────────────────────────────┐
│ ºServiceHub.signInitialTransaction(º │ │QºPROVIDING AN APIº │
│ BºTransactionBuilderº │ │ a. Subclass BºWebServerPluginRegistryº │
│ º)º │ │ class MyWebPlugin : WebServerPluginRegistry( │
│ Converts the builder to a signed transaction │ │ {...} │
│ ºSignedTransactionº │ │ b. Override webApis │
│ An inmutable transaction plus its associated │ │ override val webApis = listOf(Function(::MyApi))│
│ digital signatures │ │ c. Register the fully qualified class name of the │
│ └º.verifyRequiredSignatures()º │ │ plugin under .../src/main/resources/META-INF/ \ │
│ Verify all the transaction's required signatures │ │ /services/WebPluginRegistry │
│ └º.verifySignaturesExcept(vararg List˂PublicKey˃)º │ └────────────────────────────────────────────────────┘
│ Verify all the transaction's required signatures │
│ except those listed │
│ └º.verify(ServiceHub, boolean)º │
│ Verify the transaction │
│ └º.toLedgerTransaction(ServiceHub, boolean)º │
│ Resolve transaction into a LedgerTransaction for │
│ extra verification │
│ ºServiceHub.addSignature(SignedTransaction)º │
│ Add a digital signature to the transaction │
└───────────────────────────────────────────────────────┘
Who is Who
(Forcibly incomplete but still quite pertinent list of core people)
Richard Gendal Brown, current CTO @[https://gendal.me/"]
Mike Hearn, @[https://github.com/mikehearn]
Clinton Alexander
Andras Slemmer
Ross Nicoll
Shams Asari
Chris Rankin
Matthew Nesbit
Andrius Dagys
josecoll
Katelyn Baker
Rick Parker
Joel Dudley
Andrzej Cichocki
Michele Sollecito
Patrick Kuo
Viktor Kolomeyko
Tudor Malene
Konstantinos Chalkias
szymonsztuka
...
Hello World!
@[https://docs.corda.net/tutorial-cordapp.html]
@[https://github.com/corda/samples]
IOUs contract between nodes.
Rules:
- The IOU’s value is strictly positive
- A node is not trying to issue an IOU to itself
Nodes: Notary + PartyA + PartyB + PartyC
$ git clone https://github.com/corda/samples
$ cd samples/cordapp-example
RºWARNº: Use JDK 1.8
/
│...
├─ gradle*
├─ clients/src/main
│Oº└─ kotlin/com/example/server º Simple (Spring+Kotlin) REST API
│Oº│ ├─ MainController.kt º Middleware between external clients
│Oº│ ├─ NodeRPCConnection.kt º and Corda Network
│Oº│ └─ Server.kt º
│ └─ resources
│ (index.html, ºjs, ºproperties)
├─ config (log4j2.xml)
...
├─ contracts-kotlin
│ ├ build.gradle
│ └ src/main/kotlin/com/example
│ └ example
│ Bº├ contract/IOUContract.ktº ← Rules goberning state evolution,
│ │ invoqued as part of TXs in the context
│ │ of a flow.
│ Bº├ schema /IOUSchema.kt º
│ Bº└ state /IOUState.kt º ← shared fact by 1+ parties
├─ lib/quasar.jar ← rewrites flows to be checkpointable
...
└─ workflows-kotlin
├── build.gradle
Bº └── src/integrationTest/kotlin/com/example/DriverBasedTests.ktº
├ main/kotlin/com/example/flow/ExampleFlow.kt ← Allow parties to initiate a
│ new TX/pause/responde/...
└ test/kotlin/com/example
├── NodeDriver.kt
├── contract/IOUContractTests.kt
└── flow/IOUFlowTests.kt
$º./gradlew deployNodesº
Will create
$ workflows-kotlin/build/nodes/node"I"
$ "runnodes" shell script for running all the nodes simultaneously
. node"I"
├── additional-node-infos //
├── certificates
├── corda.jar // The Corda node runtime
├── cordapps // The node's CorDapps
│ ├── corda-finance-contracts-4.1.jar
│ ├── corda-finance-workflows-4.1.jar
│ └── cordapp-example-0.1.jar
├── drivers
├── logs
├── network-parameters
├── node.conf // The node's configuration file
├── nodeInfo- // The hash will be different each time you generate a node
└── persistence.mv.db // The node's database
Running the CorDapp:
$ workflows-kotlin/build/nodes/runnodes
For each party A/B/C, start the Spring Boot server in its own terminal like:
$ ./gradlew runParty"X"Server
→ ...
→ ______ __
→ / ____/ _________/ /___ _
→ / / __ / ___/ __ / __ `/ Top tip: never say "oops", instead
→ / /___ /_/ / / / /_/ / /_/ / always say "Ah, Interesting!"
→ \____/ /_/ \__,_/\__,_/
→
→ --- Corda Open Source corda-4.1 (4157c25) ------------
→
→ Logs can be found in : .../cordapp-example/workflows-kotlin/build/nodes/PartyA/logs
→ Database connection url is : jdbc:h2:tcp://localhost:59472/node
→ Incoming connection address : localhost:10005
→ Listening on port : 10005
→ Loaded CorDapps : corda-finance-corda-4.1, cordapp-example-0.1, corda-core-corda-4.1
→ Node for "PartyA" started up and registered in 38.59 sec
→
→
→ Welcome to the Corda interactive shell.
→ Useful commands include 'help' to see what is available, and 'bye' to shut down the node.
→
→ Fri Mar 02 17:34:02 GMT 2018˃˃˃
→
→
Check status like http://localhost:[?????]/api/status
50005
50006
50007
Spring Boot server exposed API endpoints:
/api/example/me
/api/example/peers
/api/example/create-iou
- create an IOU between PartyA and PartyB like:
curl -X PUT \
'http://localhost:50005/api/example/create-iou?iouValue=1⅋partyName=O=PartyB,L=New%20York,C=US'
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^
ºOnce the process is complete, both nodes will have a signed, notarised copy of the IOU. PartyC will not.º
- Check correct creation in both peers like:
PartyA's vault → http://localhost:50005/api/example/ious
PartyB's vault → http://localhost:50006/api/example/ious
- Check that C is not affected:
PartyC's vault → http://localhost:50007/api/example/ious
Via the interactive shell:
PartyA shell ˃˃˃ flow list
→ com.example.flow.ExampleFlow$Initiator
→ net.corda.core.flows.ContractUpgradeFlow$Authorise
→ net.corda.core.flows.ContractUpgradeFlow$Deauthorise
→ net.corda.core.flows.ContractUpgradeFlow$Initiate
→ net.corda.finance.flows.CashExitFlow
→ net.corda.finance.flows.CashIssueAndPaymentFlow
→ net.corda.finance.flows.CashIssueFlow
→ net.corda.finance.flows.CashPaymentFlow
→ net.corda.finance.internal.CashConfigDataFlow
create a new IOU like:
PartyA shell ˃˃˃ flow start ExampleFlow$Initiator iouValue: 50, otherParty: "O=PartyB,L=New York,C=US"
→ OK Generating transaction based on new IOU.
→ OK Verifying contract constraints.
→ OK Signing transaction with our private key.
→ OK Gathering the counterparty's signature.
→ OK Collecting signatures from counterparties.
→ OK Verifying collected signatures.
→ OK Obtaining notary signature and recording transaction.
→ OK Requesting signature by notary service
→ Requesting signature by Notary service
→ Validating response from Notary service
→ OK Broadcasting transaction to participants
→ OK Done
Display full list of available operations:
PartyA shell ˃˃˃ run vaultQuery contractStateType: com.example.state.IOUState
Change node location:
(Automatic in Corda 4 with Corda_Service_Map?)
STEP 1) Deploy
$ ./gradlew deployNodes # (No changes here)
$ cd .../workflows-kotlin/build/nodes
$ vim node.conf # update its p2pAddress matching that of the node
Distribute new node-info files amongst nodes:
$ java -jar network-bootstrapper.jar workflows-kotlin/build/nodes
^^^^^^^^^^^^^^^^^^^^^^^^
network bootstrapper tool
network bootstrapper tool
distribute files locally
"Copy/move" folders to their corresponding machines
- After starting each node, they will "see" one another
Corda vs Ethereum vs Fabric: Programming Patterns
- Corda States ussually represent the internal state of an Ethereum contract
(balance, state-machine,...) but are external to the contract.
For example in Corda the "money" in a user balance is represented by an
OwnableState. This state can come from periodic wage payment, a credit,
and bond-payment, ... but the state itself ignores it.
In Ethereum the money is "embedded" in an ERC20 SmartContract token.
(Actually the ERC20 token is blind about who/what invoqued valid
TX to its public methods).
- While it's possible in Ethereum to develop storage contracts representing
only state and external contracts manipulating such state, it's up to
the desire and skills of the developer.
- Corda contracts "approximatelly" maps to the Ethereum contract logic that
governs the state evolution. The main differences are:
- Ethereum the "next state value" is defined the execution of functions
defined inside the published smart-contract. In Corda "next state value"
is calculated before calling the contract and the contract limits to
check that the transaction inputs and espected output are compatible
with the defined logic in the contract throwing an exception and
reverting the transaction flow otherwise.
- In Ethereum the required signarutes are defined by "manual" code
in the contract executing the transactions. In Corda, the required
signatures are defined while building the Transactions, and corda
flows are used to sign the transactions "outside" the contract logic.
- Ethereum contract code is stored in the blockchain.
Corda contract code is not stored in the blockchain (the vault in
Corda terminology). It consist in JVM code stored on the nodes.
Only the states are stored in the blockchain. Corda Contract Code
is protected by digital signatures, permissioning, ....
- Since states and contracts are independent in Corda, a Corda
contract can "consume" different types of input states and validate
different types of output states. (This is also theorically possible
in Ethereum by beeing careful of splitting states and logic but
again is up to each developer will and skills).
- Transactions in Ethereum are signed "at will" by clients as
a way to invoque methods on published smart-contract.
Transactions in Corda are build with the help of a TransactionBuilder
in the context of a flow.
- Transactions in Corda can be associated with TimeWindows where
the transaction execution will be valid. There is no such concept
in Ethereum.
- External files and data can be attached to a Corda Transaction
and used by the Contract to make extra checks during the validation
process. This attached data is inmutable but is not part of the
final vault of consumed/unconsumed states.
Ethereum has no concept of external attached transaction data.
- Both Ethereum and Corda will use "Oracles" to obtain events/facts
from the "outside" world. Corda can also use attached data in
the Transaction.
- Corda TX ordering is defined by a Notary. Each new TX can define
a new notary with different characteristics.
Ethereum TX ordering is defined by the consensus (PoW, PoS, PoA,...)
Building Blocks
NODE CERTs PRE-SETUP
node → node : generates key pair
+ certificate signing request
node → doorman: Certificate signing request.
doorman → doorman: signs (or delegate sign) cert.
doorman → node : (root-authority-signed) certificate CERT1
node → node : creates and signs (using CERT1) two more certs:
- TLS certificate
- Signing-certificate (.../certificates/ºnode-TLSº
well-known-to-peers identity)
-ºOptionallyºuse Node CERT to create:
- well-known identities.
- confidential identitiesºfor individual transactionsº
The certificate chain linking a confidential identity to
a well-known node identity or real-world legal identity
is only distributed on a need-to-know basis.
This ensures that even if an attacker gets access to an
unencrypted transaction, they cannot identify the transaction’s
participants without additional information.
node → node : builds node-info-record
address well-known-identity
node → network: register node-info-record
map srv
...
node → ??? : establish TLS session using certificate
NODE LAYOUT
- A Corda network is a peer-to-peer network of nodes.
- node-to-node communication uses encrypted TLS + AMQP/1.0
in a point-to-point approach (vs broadcasts or gossip)
┌───────────────────────────────┬──┐
│ºpermissioning doorman serviceº│ │
├───────────────────────────────┘ │
│- Signs/rejects CSRs for nodeTLS │
└─────────────────────────────↓────┘
once a Node has received a valid
Net interface with X.509 (the CSR has been signed),
other nodes in a ºclient RPCº it will be able to register itself
ºrunning flowº (user/pass auth) to the Network Map Service
↕ ↕ [[0ba845f3-579d-491c-b580-9f9803808117?]]
┌────────┬──────────╨──────────────────────╨────┐ |
│CORDA │─ TLS │ ┌──v──────────────────┬┐
│JVM NODE│ certificate │ │ºNetwork map serviceº││
├────────┘ @.../certificates/ºnode─TLSº ←── ├─────────────────────┘│
│ UNIQUE well-known-to-peers ID ^^^^^ │ │-maps nodes TLS to │
│ - IP │ │ IP addresses │
│ - Current time as tracked by node │ │-Shared by all nodes │
│ - Information on other nodes on the │ └──────────────────────┘
│ network │
│ @2┌───────────────────────────────────────┤ ┌─────────────────────────────┬─────┐
│ │ºSTORAGE SRVº │ │ºNotary Pool Network Serviceº│ │
│ │─ stores [TXs, attachements, │ ├─────────────────────────────┘ │
│ │ flow─checkpoints] │ │- similar to the Fabric "orderer" │
│ ├───────────────────────────────────────┤ │ or a Bitcoin miner, gets in │
│ │ºVAULTº │ │ charge of validating and │
│ │─stores relevant current/historic │ │ ordering TXs/state change. │
│ │ state sequences │ │ ("applies consensus") │
│ │ │ │- Keeps a list of un-spent output │
│ ├───────────────────────────────────────┤ │ states to assure that no │
│ │ºPLUGIN REGISTRYº │ │ double-spents are commited │
│ │ of installed OºCorDappsº │ │ (== ºpoint of finalityº) │
│ │- Preinstaled plugins exists for: │ │ │
│ │ - Retrieving TXs/attachments from │ │- issuance/genesis TXs are the only│
│ │ counterparties. │ │ not-notarized TX since they do │
│ │ - Upgrading contracts │ │ NOT consume any input state. │
│ │ - Boradcasting agreed ledger updates │ │ │
│ │ for recording counterparties │ │-ºA network can have several º │
│ ├───────────────────────────────────────┤ │ ºnotary pools,ºeach running a │
│ ┊XXX Service ┊ │ different consensus algorithm │
│ ┊ ┊ │ (high-speed vs BFT vs ...) │
│ ┊ ┊ │ │
│ ├───────────────────────────────────────┤ │- The TX proporser will choose │
│ │ºSERVICE HUBº │ │ which notary to use. │
│ │ of installed OºCorDappsº │ └───────────────────────────────────┘
│ │ ← net/corda/core/node/ServiceHub.kt
└───────┴──↑────────────────────────────────────┘
┌───────┘
└─ allows the node's flows to call upon the node's other services
· providing next services:
· .networkMapCache: Info on other nodes on the network and the
· services they offer (notaries,...)
· .vaultService : Access to the contents of the vault (current
· and historic states)
· .validatedTransactions: Stores all the Transactions seen by the node
· .keyManagementService: generation+Access to node's signing keypairs
· .myInfo: Information about the node itself
· .clock: Internal time/date of the node
└ ºFULL LIST OF NODE SERVICESº
net/corda/core/node/services
o vault/QueryCriteria.kt o NetworkMapCache.kt
o vault/QueryCriteriaUtils.kt o NetworkParametersService.kt
o AttachmentStorage.kt o PartyInfo.kt
o ContractUpgradeService.kt o TimeWindowChecker.kt
o CordaService.kt o TransactionStorage.kt
o IdentityService.kt o TransactionVerifierService.kt
o KeyManagementService.kt o VaultService.kt
┌──────────────────┬─────────────────────────────────┐
VAULT SCHEMA: ┌─┤º(CONTRACT) STATEº│ │
┌─────────────────────────┐ │ ├──────────────────┘ │
│ CONSUMED │ ºNONº │ │ │@[https://docs.corda.net/api-states.html] │
│ HISTORICAL │ CONSUMED │ │ │@KeepForDJVM │
│ºINMUTABLEº │ºINMUTABLEº│ │ │@CordaSerializable │
│º STATES º │ºSTATES º│ │ │interface ContractState { │
│─────────────┼───────────│ │ │ val participants: List˂AbstractParty˃ │
│ B0→B1 → B_head ←──┘ │} │
│A0─→A1→A2→A3 → A_head │ │@[https://docs.corda.net/key-concepts-states.html] │
│ C0→C1 → C_head │ │─ *1: ContractState.kt@Github │
└─────────────────────────┘ │─ inmutable fact known by one or more Corda nodes │
- Vault-queries over │ at a specific point in time │
current/historical states. │ │
│Example OºI owe youºstate: │
│ ┌────────────────────────────────────┐ │
│ │─ IOU.contract.ref ←─── reference to contract │
│ │─ participants=[Alice,Bob] │ governing │
│ │─ IOU.state.props │ (validating)│
│ │ (From,To) : (Alice ,Bob) │ state │
│ │ (Amount,Paid): (10$ , 5$) │ evolution │
│ │ (Due,Penalty): (2017─03─01,20%) │ │
│ └────────────────────────────────────┘ │
└────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────────────────────────────┐
│BºIn CORDA a TX associates 1+ input states to 1+ (expected) output states through 1+ Contractsº│
└───────────────────────────────────────────────────────────────────────────────────────────────┘
Common States:
┌─────────────────────────────────────────────┐┌─────────────────────────────────────────────┐┌────────────────────────────────────┐
│"EVOLVING" LINEARSTATE ││"OWNABLE" STATE ││"FUNGIBLE" State │
│@KeepForDJVM ││@KeepForDJVM ││(there is an expectation that │
│interface LinearState : ContractState { ││data class B*CommandAndState*( ││ "these things" can be split/merged)│
│ * except at issuance/termination. ││ val command: CommandData, ││@KeepForDJVM │
│ */ ││ val ownableState: OwnableState ││interface FungibleState˂T : Any˃ : │
│ valºlinearId: UniqueIdentifierº ││) ││ ContractState { │
│ ^^^^^^^^ ││@KeepForDJVM ││ val amount: Amount˂T˃ │
│ Verify methods should check that ││interface OwnableState : ContractState { ││} │
│ one input and one output share the id││ val owner: AbstractParty │└──^─────────────────────────────────┘
│ ││ fun withNewOwner(newOwner: AbstractParty)│ │
│} ││ : B*CommandAndState* │← Fungible Asset
└─────────────────────────────────────────────┘│} │
└─────────────────────────────────────────────┘
@1:@[https://github.com/corda/corda/blob/master/core/src/main/kotlin/net/corda/core/contracts/ContractState.kt]
@2 @[https://github.com/corda/corda/tree/master/node/src/main/kotlin/net/corda/node/services]
ºTHE LEDGERº
@[https://docs.corda.net/key-concepts-ledger.html]
- The ledger is subjective from each peer's perspective:
Each peer only sees a subset of facts on the ledger
- Two peers are always guaranteed to see the exact same version
of any on-ledger facts they share
- We can think of the ledger from each node's point of view
as the set of all the current (i.e. non-historic) states
that it is aware of.
ºSTATE EVOLUTION THROUGH LedgerTransactions (TX Proposals)º
@[https://docs.corda.net/api─transactions.html]
Reference States 1+ ←───┐ ┌─── A ºTransactionBuilderºis used to instantiate a new TX
(Corda 4.0+) │ Notary │ ─ It's done in the context of a flow to get access to
─ Similar to input │ 1 │ node information (real input states, parties, notaries, ...)
states but are │ ^ │
NOT consumed │ │ │ - Te built TX becomes inmutable once signed
- Think of ref. data │ │ │ by any involved party.
like rates, external │ │ │
status, oracles,... │ │ │
│ ↓ ↓
StateAndRef 1+ ←───→1 GºLedgerTransactionº 1 ←→ 1+ TransactionState
(Input state │ ----------------- (ouput state
to be consumed) │ - opt.TimeWindow to be procuded)
│ - start/end/before Pairs the output state
CommandWithParties 1+ ←─┘ after/around with a contract and a notary
------------------ - opt.attachments:@3 ^ ^^^^^^^^
jar files(hashes) │
used in verification │
(calendars, legal doc,)│
│
val signers: List˂PublicKeys˃ // Required signers │ - For security reasons only the class name
val signingParties: List˂Party˃// Resolved identi. │ is included to avoid inserting false dependencies
val value: T │ in party nodes.
(clarifies the TX intention │
Ex: [TransferCash,PayCoupon]) │
┌─────────────────────────────────────────────────┘
↓
ºContractº: Verify set of rules → Continue or Throw ºEx:º
^^^^^^^^^^^^^^^^^^^ class FungibleAssetContract : Contract {
REF: @[https://docs.corda.net/api-contracts.html] ...
Ex: Rule 1: Has one cash input and one cash output override fun verify(tx: LedgerTransaction) {
Rule 2: Has a transfer commadn val command = txGº.commandsº.
Rule 3: Cash in == cash out ºrequireSingleCommandº˂Commands˃()
Rule 4: Input cash's onwer is a required signer when (command.value) {
is Commands.Issue -˃ {
interface Contract { // Issuance verification logic.
@Throws(IllegalArgumentException::class) }
fun verify(tx: GºLedgerTransactionº) is Commands.Transfer -˃ {
^ ^^^^^^^^^^^^^^^^^^^^^^^ // Transfer verification logic.
} │ It's just a proposal until }
│ verified and accepted by Notary }
│ The verify method has all the info }
│ from the TX (inputs/outpus/commands) override val legalContractReference: SecureHash =
│ and also all the recognised signers SecureHash.sha256("X contract hash")
│ (tx.signingParties) }
│
- tx.verifies() will call all associated contracts verify.
-ºcontract verify execute in a sandbox and must be idempotentº
ºTX classification 1º ºTX classification 2º
-ºissuancesº(zero inputs) - Notary-change: used to change a state's notary
-ºexits º(have zero outputs) - General : any other.
- For fungible assets/states they
can also merge/split inputs.
@3 extracted from:
- TX.Command list: @[https://docs.corda.net/api-contract-constraints.html]
Indicates the operation executed on the initial The app version used by a transaction is defined by its attachments.
ledger state (purchase, sale, ...) The JAR containing the state and contract classes optional dependencies,
┌─→ Each command indicates the list of required signer. are all attached to the transaction.
· The union of all required signer (pub.keys) in all - Nodes will download this JAR from other nodes if they haven’t seen
· Command List it the TX total required signers. it before, so it can be used for verification.
·
·CONSENSUS
·- A transaction proposal will only be committed if:
· - It doesn't contain double─spends
· (checked by the Notary that contains the
· full list of unspent ouputs)
· - It is contractually valid
└── It is signed by the required parties
Note: Corda design separates correctness consensus
from uniqueness consensus.
FLOWS
-@[https://docs.corda.net/key-concepts-flows.html]
@[https://www.youtube.com/watch?v=2ZrRWVktqpE&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N&index=16]
-º"Everything (All built transactions) happen in the context of a flow"º
-ºFlows automate the process of agreeing ledger updatesº
-ºA NODE OPERATOR WILL INSTALL ONE OR MORE FLOWS IN A NODEº
-ºDevelopers will implement the InitiatingFlow (party A),InitiatedBy (CounterParty B)º
┌───────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌───┐
Node Rº─│PROPOSE├─┤CHECK ├─┤SIGN │──┐º·················Rº┌────┐º·····Rº┌─┤RECORD├──┐º········→ │END│
A │UPDATE │ │UPDATE│ │UPDATE│Rº│º Rº^º Rº│º ^ │UPDATE│Rº│º └───┘
└───────┘ └──────┘ └──────┘Rº│º Rº│º Rº│º │ └──────┘Rº│º
tx. Rº│º Rº│º Rº│º │ Rº│º
Rº│º Rº│º Rº│º │ Rº│º
Rºvº┌──────┐ ┌──────┐Rº│º Rº│º │ Rºvº┌──────┐ ┌───┐
Node ····························Rº└─┤CHECK ├─┤SIGN ├──┘º·Rº│º·······│·········Rº└─┤RECORD├→º│END│
B │UPDATE│ │UPDATE│ Rº│º │ │UPDATE│ └───┘
└──────┘ └──────┘ Rº│º │ └──────┘
Rº│º │
Rº│º │
v┌──────┐│ ┌───┐
Notary ······················································Rº└┤SIGN ├┘º····················→ │END│
Pool │UPDATE│ └───┘
└──────┘
└───────────────────────── sequence of steps that tells each node how to achieve ───────────────────┘
a specific ledger update (issuing, settling,...)
OºUnlike contracts, flows do not execute in a sandbox (access to net, disk, time, ...)º
- Once a given business process has been encapsulated in a flow
and installed on the node as part of a CorDapp, the node's
owner can instruct the node to kick off this business process
at any time using an RPC call. The flow abstracts all the
networking, I/O and concurrency issues away from the node owner.
-ºFlows may last days, across node restarts and even upgrades.º
- Flow Initiator: Builds new TX (choose notary), signs,
verify (run its contract), gather counterparty's signature, finalize TX:
- It will use the ºservice Hubº to have access to past states from the vault, identities,
nodes, ... and then fulfill an initial LedgerTransaction (TX proposal)
@InitiateBy(TwoPartyFlow.class)
public class TwoPartyFlowResponder extends FlowLogic˂Void˃ {
private final FlowSession counterPartySession;
public TwoPartyFlowResponder(FlowSession counterPartySession) { ...}
@Suspendable
public Void call() throws FlowException {
ServiceHubºSHº= getServiceHub();
List˂StateAndRef˂HouseState˃˃ statesFromVault =
ºSHº.getVaultService().queryBy(HouseState.class).getStates();
...
Party alice =ºSHº.getNetworkMapCache().getNodeByLegalName(cordaX500Name01);
}
counterPartySession.send(...);
return;
}
*Flow Testing*
To create a mock network at:
REF @[https://www.youtube.com/watch?v=46X55zv6dUY&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N&index=17]
@[https://www.youtube.com/watch?v=xjhLFLPOEFg&list=PLi1PppB3-YrVq5Qy_RM9Qidq0eh-nL11N&index=18]
public class FlowTests {
private MockNetwork network;
private StartedMockNode nodeA;
private StartedMockNode nodeB;
@Before
public void setup() {
network = new MockNetwork(ImmutableList.of("java bootcamp"));
nodeA = network.createPartyNdoe(legalName: "....");
nodeB = network.createPartyNdoe(legalName: "....");
network.runNetwork();
}
@Test
public void transactionConstructedByFlowUsesCorrectNotary() throws Exception {
TokenIssueFloe flow = new TokenIssueFlow(nodeB.getInfo().getLegalIdentities().get(0));
CordaFuture˂SignedTransaction˃ future = nodeA.startFlow(flow);
network.runNetwork();
SignedTransaction signedTransaction = future.get();
assertEquals( 1, signedTransaction.getTx().getOutputStates().size());
TransactionState output = signedTransaction.getTx().getOutputs().get(0);
assertEquals(network.getNotaryNodes().get(0).getInfo().getLegalIdentities().get(0),
output....);
}
}
*override Flow* TODO
@[https://docs.corda.net/flow-overriding.html]
Contract catalogue
@[https://docs.corda.net/contract-catalogue.html]
It provides a number of contracts supplied with Corda, covering:
-ºcore functionalityº
- examples modeling complex contracts like:
- Cash
- Commodity
- Commercial paper
- Interest rate swap
- Obligation
- Can contain legal prose text
BUILT-IN
SUBFLOWS
@[https://docs.corda.net/flow-library.html]
("BUILDING BLOCKS")
- provides a number of built-int flows supplied with Corda,
covering someºcore functionalityº:
┌──────────────────────────┬──────────────────────────────┐
│ SubFlow │ should be used to │
├──────────────────────────┼──────────────────────────────┤
│ CollectSignaturesFlow │ collect TXs required signs. │
│ SignTransactionFlow │ │
│ SendTransactionFlow │ │
│ ReceiveTransactionFlow │ │
│ FinalityFlow │ verify/notarise/record a TX │
│ ResolveTransactionsFlow │ verify inputs chain to TX │
│ ContractUpgradeFlow │ change a state's contract │
│ NotaryChangeFlow │ change a state's notary │
└──────────────────────────┴──────────────────────────────┘
ºExample ussage:º
┌───────────────────────────────────────┬───────────────────────────────────────────────────────────┐
│(Initiator)Party starts │ Counterparty │
│'CollectSignatures'─Subflow │ │
├───────────────────────────────────────┼───────────────────────────────────────────────────────────┤
│val fullySignedTx: SignedTransaction = │val counterParty_SignTransactionFlow:ºSignTransactionFlowº=│
│ subFlow( │ object : SignTransactionFlow(counterparty) { │
│ ºCollectSignaturesFlowº( │ override │
│ twiceSignedTx, │ fun checkTransaction(stx: SignedTransaction) = │
│ SIGS_GATHERING. │ requireThat { │
│ .childProgressTracker() │ // ... checking ... │
│ ) │ if (stx_has_dependencies) │
│ ) │ subFlow( │
│ │ ResolveTransactionsFlow( │
│ │ twiceSignedTx, counterparty)) │
│ │ │
│ │ subFlow( │
│ │ ResolveTransactionsFlow( │
│ │ setOf(ourStateRef.txhash), counterparty)) │
│ │ │
│ │ val outputState = │
│ │ stx.tx.outputsOfType˂DummyState˃().single() │
│ │ assert(outputState.magicNumber == 777) │
│ │ } │
│ │ } │
│ │subFlow(counterParty_SignTransactionFlow) │
└───────────────────────────────────────┴───────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────┐
│val additionalParties: Set˂Party˃ = setOf(regulator│
│val notarisedTx1: SignedTransaction = │
│ subFlow( │
│ ºFinalityFlowº( // ← Finalizing Flow │
│ listOf(fullySignedTx), │
│ additionalParties /*optional*/, │
│ FINALISATION.childProgressTracker()) │
│ ).single() │
└───────────────────────────────────────────────────┘
(Flow) ProgressTracker
- allows to see the flow's progress visually
in our node's CRaSH shell.
ID_OTHER_NODES → SENDING_AND_RECEIVING_DATA → EXTRACTING_VAULT_STATES → OTHER_TX_COMPONENTS
→TX_BUILDING→TX_SIGNING→TX_VERIFICATION→SIGS_GATHERING→VERIFYING_SIGS→FINALISATION
progressTracker.currentStep = ...
ORACLES
SERVICES
- A fact can be included in a TX as part of a command
- An oracle is a (network) service that will only sign the TX if the included
fact is true
- Upon request, an oracle provide commands that encapsulate a specific fact
(e.g, the exchange rate at time x) and list the oracle as a required signer.
- To sign a transaction, the only information the oracle needs to see is their
embedded command. Providing any additional transaction data to the oracle would
constitute a privacy leak. Similarly, a non-validating notary only needs to see
a transaction's input states.
To combat this, the transaction proposer(s) uses a Merkle tree to "tear off"
any parts of the transaction that the oracle/notary doesn't need to see before
presenting it to them for signing. A Merkle tree is a well-known cryptographic
scheme that is commonly used to provide proofs of inclusion and data integrity.
The advantage of a Merkle tree is that the parts of the transaction that were
torn off when presenting the transaction to the oracle cannot later be changed
without also invalidating the oracle's digital signature.
Programming API
Corda dApp
┌────────────────────────────────────────────────────────────────┐ ┌────────────────────────────────────────────────────────────┐
│OºCorDappº │ │─ AOºCorDappºmay also need to define two types of plugins: │
│─ installed at the level of the individual node │ │ ─ºCordaPluginRegistryºsubclasses overwriting: │
│ (rather than on the network itself) │ │ ─ customizeSerialization: set of the classes │
│─ provide the node with new business processes │ │ to be whitelisted for │
│ by defining new flows on the node │ │ object serialisation │
│ (started by the node owner). │ │ ─ requiredSchemas @1 : set of the MappedSchemas │
│─ Drives the process of negotiating a specific │ │ to use for persistence and │
│ │ │ vault queries │
│- CorDapp JARs (see What is a CorDapp?) that contain classes │ │ ─ºWebServerPluginRegistryºsubclasses, that can overwrite: │
│ implementing the Contract interface are automatically loaded │ │ ─ webApis :JAX─RS annotated REST │
│ into the AttachmentStorage of a node, and made available as │ │ access classes list. │
│ contractAttachments. │ │ ─ staticServeDirs*2: map of static web content to │
│ They are retrievable by hash using │ │ virtual paths │
│ AttachmentStorage.openAttachment. These JARs can either be │ │ (static web content itself should │
│ installed on the node or will be automatically fetched over │ │ be placed inside src/main/resources)│
│ the network when receiving a transaction. │ │ │
│ REF:@[https://docs.corda.net/api-contract-constraints.html] │ │☞ must be added also to (resources/META─INF/services/) │
│ │ │ net.corda.core.node.CordaPluginRegistry │
│┌──────────────────────────────────────────────────────────────┐│ │☞ must be added also to (resources/META─INF/services/) │
││developers will usually define: ││ │ net.corda.webserver.services.WebServerPluginRegistry │
││─ºFlowsº subclassinGºFlowLogicº ││ └────────────────────────────────────────────────────────────┘
││ @[https://docs.corda.net/api─flows.html] ││
││ ││
││─ºStatesº implementinGºContractStateº ││
││ States can change through aprobed ││
││ signature trees ││
││ ││
││─ºContractsºimplementinGºContractº logic ││
││ @[https://docs.corda.net/api─contracts.html] ││
││ ││
││─ºServicesº subclassinGºSingletonSerializationTokenº ││
││ ││
││─ºSerialisationºimplementinGºSerializationWhitelistº ││
││ ºwhitelist º ││
│└──────────────────────────────────────────────────────────────┘│
└────────────────────────────────────────────────────────────────┘
RºWARN:º The obvious way to write a CorDapp is to put all you
states, contracts, flows and support code into a single Java module.
This will work but it will effectively publish your entire app onto
the ledger. That has two problems:
- (1) it is inefficient,
- (2) it means changes to your flows or other parts of the
app will be seen by the ledger as a "new app", which may
end up requiring essentially unnecessary upgrade procedures.
- It’s better to split your app into multiple modules:
- one which contains just states, contracts and core data types.
- another which contains the rest of the app. See Modules.
Project layout
SHOULD BE SPLIT INTO TWO MODULES:
──────────────────────────────────────────
1ºcordapp─contracts─statesºmodule/CorDapp
contracts and states sent over the wire
main ─ java ─ com.template
├── TemplateContract.java
└── TemplateState.java
────────────────────────────────────────────
2ºcordapp module/CorDapp: remaining classesº
main ─ java
│ └─ com.template
│ ├ TemplateFlow.java (inherits FlowLogic)
│ ├ TemplateSerializationWhitelist.java
│ ├ (testing env)TemplateApi.java
│ ├ (testing env)TemplateClient.java
│ └ (testing env)TemplateWebPlugin.java
│
└─ resources
├─META─INF
│ └─services
│ ├net.corda.core.serialization.SerializationWhitelist
│ └net.corda.webserver.services.WebServerPluginRegistry
├─ certificates
└─ templateWeb
test ─ java ─ com.template
ContractTests.java
FlowTests.java
NodeDriver.java
integrationTest
└─ java ─ com.template
DriverBasedTest.java
API Core Types
-@[https://docs.corda.net/api-core-types.html]
ºSecureHashº:
- Any object that needs to be identified by its hash
should implement the NamedByHash interface (TXs, attachments,..)
ºinterface NamedByHashº{ ← only defines a single sealed subclass:
val id: SecureHash SecureHash.SHA256
} (and utility methods to instantiate/parse it)
ºCompositeKeyº:
@[https://github.com/corda/corda/blob/master/core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt]
- Allows for complex signature scenarios.
- Uses public-key composition to organise
the various public keys into a tree data
structure, storing the cryptographic
pub.key primitives in its leaves and the
composition logic in the intermediary
nodes.
- Every intermediary node specifies a
threshold of how many child signatures
it requires.
OR(1)
├── Charlie
└── (2)AND
│
├── Alice (w:2)
├── Bob (w:1)
└── Mike (w:1)
│*Signature verification is performed in two stages:
│ Given a list of signatures, each signature is verified against the expected content.
│- public keys corresponding to the signatures are matched against
│ the leaves of the composite key tree in question, and the total combined
│ weight of all children is calculated for every intermediary node.
│- If all thresholds are satisfied, the composite key requirement is considered
│ to be met.
VAULTS QUERIES API
- @[https://docs.corda.net/api-vault-query.html]
The majority of query requirements can be satisfied by using the Vault Query API,
which is exposed via the VaultQueryService for use directly by flows.
(See also helper methods).
-ºVault.Pageº: use for returning results, object contains:
- states as a List of «StateAndRef» (page number and size defined by [PageSpecification])
- states metadata as a List of [Vault.StateMetadata] held in the Vault States table.
- total number of results available if [PageSpecification] supplied (otherwise returns -1)
- status types used in this query: UNCONSUMED, CONSUMED, ALL
- other results (aggregate functions with/without using value groups)
- ˂˂QueryCriteria˃˃ provides mechanisms for specifying filtering,
including (AND, OR), (LESS|GREATER)_(THAN|THAN_OR_EQUAL), (NOT_)EQUAL,
(NOT_)LIKE, (IS_|NOT_)NULL, (NOT_)IN, Standard SQL-92 aggregate functs
(SUM, AVG, MIN, MAX, COUNT)
ºONE-TIME VS STREAM QUERYº
┌────────────────────────────────────────┐ ┌───────────────────────────────────────────┐
│ONE─TIME─QUERY │ │STREAM (snapshot + Observable stream) QUERY│
├────────────────────────────────────────┤ ├───────────────────────────────────────────┤
│fun ˂T : ContractState ˃ _queryBy( │ │fun ˂T : ContractState ˃ _trackBy(/ │
│ criteria: QueryCriteria /*filters*/,│ │ criteria: QueryCriteria /* filters */, │
│ paging: PageSpecification, │ │ paging: PageSpecification, │
│ sorting: Sort, │ │ sorting: Sort, │
│ contractType: Class˂out T ˃): │ │ contractType: Class˂out T ˃): │
│ Vault.Page˂T ˃ │ │ DataFeed˂ │
│ │ │ Vault.Page˂T ˃ /*"snapshot"*/, │
│ │ │ Vault.Update /* Observable */ ˃ │
└────────────────────────────────────────┘ └───────────────────────────────────────────┘
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Streaming updates are only filtered
based on contract-type and state-status
(UNCONSUMED, CONSUMED, ALL). They will not
respect any other criteria that the
initial query has been filtered by.
˂˂QueryCriteria˃˃ existing implmentations ºwhich CAN BE CHAINED TOGETHERº to define advanced filters
-ºVaultQueryCriteria:ºfilter on attributes within the Vault states table:
- status (UNCONSUMED, CONSUMED)
- state reference(s)
- contract state type(s)
- notaries
- soft locked states
- timestamps (RECORDED, CONSUMED)
-ºFungibleAssetQueryCriteria:ºfilter on attributes defined in FungibleAsset contract state:
- participants(s)
- owner(s)
- quantity
- issuer party(s) and/or reference(s)
-ºLinearStateQueryCriteria:º filter on attributes defined in «LinearState» and «DealState» contract state
- participant(s)
- linearId(s)
- dealRef(s)
-ºVaultCustomQueryCriteria:º
- provides the means to specify one or many arbitrary expressions on attributes
- defined by a custom contract state that implements its own schema.
- See the Builder object in QueryCriteriaUtils for a complete specification of the DSL.
STATE PERSISTENCE
(VAULTS) Examples:
Ex.1:ºcustom queryº
val generalCriteria = VaultQueryCriteria(Vault.StateStatus.ALL)
val results = builder {
val currencyIndex = PersistentCashState::currency.equal(USD.currencyCode)
val quantityIndex = PersistentCashState::pennies.greaterThanOrEqual(10L)
val customCriteria1 = VaultCustomQueryCriteria(currencyIndex)
val customCriteria2 = VaultCustomQueryCriteria(quantityIndex)
val criteria = generalCriteria.and(customCriteria1.and(customCriteria2))
vaultQuerySvc.queryBy˂Cash.State˃(criteria)
}
Ex.2:ºQuery for all unconsumed states (simplest query possible)º
(UNCOSUMED STATE BY DEFAULT)
----------------------------------------------------------------
val sortAttribute = SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID)
----------------------------------------------------------------
// recorded in time interval:
val timeIntervalFilter = TimeCondition(
QueryCriteria.TimeInstantType.RECORDED,
ColumnPredicate.Between(TODAY, TODAY.plus(30, ChronoUnit.DAYS)) )
----------------------------------------------------------------
VaultQueryCriteria FILTER:
// state reference list: | // set of contract state: | // by notary: | // by recorded time interval
val criteria = VaultQueryCriteria | val criteria = VaultQueryCriteria | val criteria = VaultQueryCriteria | val criteria = VaultQueryCriteria
( | ( | ( | (
stateRefs = listOf( | contractStateTypes = setOf( | notaryName = listOf(CASH_NOTARY.name) | timeCondition = timeIntervalFilter
stateRefs.first(), | Cash.State::class.java, | ) | )
stateRefs.last() ) | DealState::class.java)
) | )
----------------------------------------------------------------
LinearStateQueryCriteria FILTER:
// (unconsumed states) + set of participants:
val criteria = LinearStateQueryCriteria
(
participants = listOf(MEGA_CORP, MINI_CORP)
)
----------------------------------------------------------------
Reading query results:
val results = vaultQuerySvc.queryBy˂DummyLinearContract.State˃ (
criteria,
Sort(setOf(
Sort.SortColumn(sortAttribute, Sort.Direction.ASC)
) ),
paging = PageSpecification(DEFAULT_PAGE_NUM, 10)
)
val states = result.states
val metadata = result.statesMetadata
Ex.3:ºLinearState and DealState queries using LinearStateQueryCriteriaº
val linearIds = issuedStates.states.map
{ it.state.data.linearId }.toList()
val vaultCriteria = VaultQueryCriteria(status = Vault.StateStatus.ALL)
val linearStateCriteria = LinearStateQueryCriteria
(
status = Vault.StateStatus.ALL, // CONSUMED and UNCOSUMED
linearId = listOf(linearIds.first(), linearIds.last())
dealRef = listOf("456", "789"), // by deals references:
participants = parties,
)
val results = vaultQuerySvc.queryBy˂LinearState˃(
linearStateCriteria and vaultCriteria )
Ex.4:ºFungibleAssetQueryCriteriaº
val fungibleAssetCriteria = FungibleAssetQueryCriteria(
quantity = builder { greaterThan(2500L) }, // filter by minimum quantity
issuerPartyName = listOf(BOC),
)
// Cash.State inherits from ˂FungibleAsset˂*˃˃
val results = vaultQuerySvc.queryBy˂Cash.State˃(fungibleAssetCriteria)
----------------------------------------------------------------------
AGGREGATE FUNCTION
AGGREGATIONS ON CASH USING VARIOUS FUNCTIONS | AGGREGATIONS ON CASH GROUPED BY CURRENCY FOR VARIOUS FUNCTIONS:
--------------------------------------------------------------------------+----------------------------------------------------------------
val sum = builder { CashSchemaV1.PersistentCashState::pennies.sum() } | val sum = builder { CashSchemaV1.PersistentCashState::
val sumCriteria = VaultCustomQueryCriteria(sum) | pennies.sum(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) }
| val sumCriteria = VaultCustomQueryCriteria(sum)
val count = builder { CashSchemaV1.PersistentCashState::pennies.count() } |
val countCriteria = VaultCustomQueryCriteria(count) | val max = builder { CashSchemaV1.PersistentCashState::
| pennies.max(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) }
val max = builder { CashSchemaV1.PersistentCashState::pennies.max() } | val maxCriteria = VaultCustomQueryCriteria(max)
val maxCriteria = VaultCustomQueryCriteria(max) |
| val min = builder { CashSchemaV1.PersistentCashState::
val min = builder { CashSchemaV1.PersistentCashState::pennies.min() } | pennies.min(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) }
val minCriteria = VaultCustomQueryCriteria(min) | val minCriteria = VaultCustomQueryCriteria(min)
|
val avg = builder { CashSchemaV1.PersistentCashState::pennies.avg() } | val avg = builder { CashSchemaV1.PersistentCashState::
val avgCriteria = VaultCustomQueryCriteria(avg) | pennies.avg(groupByColumns = listOf(CashSchemaV1.PersistentCashState::currency)) }
| val avgCriteria = VaultCustomQueryCriteria(avg)
val results = vaultQuerySvc.queryBy˂FungibleAsset˂*˃˃(
sumCriteria .and(countCriteria) .and(maxCriteria) .and(minCriteria) .and(avgCriteria) )
val (snapshot, updates) = vaultQuerySvc.trackBy/* stream/observable queries */˂FungibleAsset˃(...)
Transaction API
- @[https://docs.corda.net/api-transactions.html]
//*BUILD NEW TRANSACTION:*
valBºtxBuilderº: TransactionBuilder = // ← Instantiate TransactionBuilder
TransactionBuilder(General, specificNotary)
val 01ourStateAndRef: StateAndRef˂DummyState˃ = // ← Create TX the input
serviceHub.toStateAndRef˂DummyState˃(ourStateRef) // (Refs. to previous outputs)
val ourStateRef: StateRef = // ←
StateRef(
SecureHash.sha256("DummyTransactionHash"), 0)
valº02ourOutput:ºDummyState = DummyState() // ← Create Outputs
val ourOtherOutput: DummyState =
02ourOutput.copy(magicNumber = 77)
//*CREATE THE COMMAND*
valOºcommandData:ºDummyContract.Commands.Create =
DummyContract.Commands.Create()
valGºrequiredSignersº:List˂PublicKey˃ = listOf(
serviceHub.legalIdentityKey,
counterparty.owningKey
)
valº03ourCommand:ºCommand˂DummyContract.Commands.Create˃
= Command(OºcommandDataº, GºrequiredSignersº)
//*ADDING ATTACHEMENTS*
valºourAttachmentº: SecureHash =
SecureHash.sha256("DummyAttachment")
//*SET TIMEWINDOW*
valº04ourTimeWindow:ºTimeWindow =
TimeWindow.between(Instant.MIN, Instant.MAX)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Other examples:
//TimeWindow.fromOnly(Instant.MIN)
//TimeWindow.untilOnly(Instant.MAX)
BºtxBuilderº.withItems(
01ourStateAndRef, 02ourOutput, 03ourCommand, 04ourTimeWindow)
val onceSignedTx: SignedTransaction = // sign TX with legal id key.
serviceHub.signInitialTransaction(BºtxBuilderº)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Alternatively use another key:
// val otherKey: PublicKey = serviceHub.
// keyManagementService.freshKey()
// val onceSignedTx2: SignedTransaction = serviceHub.signInitialTransaction(txBuilder, otherKey)
ºLedgerTransaction sent to Contract::verify(...):º TODO:(0)
@CordaSerializable
class LedgerTransaction(
override val inputs: List˂StateAndRef˂*˃˃,
outputs: List˂TransactionState˂ContractState˃˃,
/** Arbitrary data passed to the program of each input state. */
// NOTE: AuthenticatedObject pairs a command with a list of signers.
val commands: List˂AuthenticatedObject˂CommandData˃,
val attachments: List˂Attachment˃,
override val id: SecureHash, // for original serialised-Wire-TX
notary: Party?,
signers: List˂PublicKey˃,
timeWindow: TimeWindow?,
type: TransactionType
) : BaseTransaction(inputs, outputs, notary, signers, type, timeWindow) {
...
}
FLOWS API
- @[https://docs.corda.net/api-flows.html]
-ºService Hub APIº
@[https://docs.corda.net/api-service-hub.html]
(Accesible inside the FlowLogic::call())
- networkMapCache : Provides information on other nodes on the network
- identityService : Allows to resolve anonymous identities to well-known identities
- attachments : Gives access to the node's attachments
- validatedTransactions: Gives access to the TX stored in the node
- vaultService : Stores node's current and historic states
- keyManagementService : Manages signing TXs and generating public keys
- myInfo : Other information about the node
- clock : Provides access to node's internal time+date
- Additional, ServiceHub exposes the following properties:
- loadState : resolve a StateRef into a TransactionState
- toStateAndRef : resolve a StateRef into a StateAndRef
- signInitialTransaction: signs TransactionBuilder → SignedTransaction
- createSignature : create signature to a SignedTransaction
- addSignature : add signatures to a SignedTransaction
- legalIdentityKey : node's legal identity key
- notaryIdentityKey : notary identity key
- any flow that started by a SchedulableState must be annotated with:
- @SchedulableFlow :If started by an SchedulableState
- @InitiatedBy :Indicates that responds to messages
- @InitiatingFlow :Indicates that can be started "manually"
- @StartableByRPC : Add RPC control
class Initiator(val arg1: Boolean, │ class Responder(val otherParty: Party):
val arg2: Int, │ FlowLogic˂Unit˃() { ... }
val counterparty: Party):
FlowLogic˂SignedTransaction˃() {
@Suspendable // ← serializable+restart.
override fun call() {
val NMC = serviceHub.networkMapCache
val x500Name = X500Name(
"CN=NodeA,O=NodeA,L=London,C=UK")
//*Retrieve counterparties legal identities {*
val namedCounterparty: Party? =
NMC.getNodeByLegalName (x500Name )?.legalIdentity
val keyedCounterparty: Party? =
NMC.getNodeByLegalIdentityKey(dummyPubKey)?.legalIdentity
val firstCounterparty: Party =
NMC.partyNodes[0] .legalIdentity
//*}*
//*find nodes providing a specific service *
val regulator: Party = // could be a regulator, oracle,...
NMC.getNodesWithService(ServiceType.regulator)[0]
.legalIdentity
val packet2: UntrustworthyData˂Boolean˃ =
sendAndReceive˂Boolean˃(regulator /*counterparty*/, "payload")
val boolean: Boolean = packet2.unwrap
{ untrustedData -˃ ... return checkedAndTrustedData }
}
}
PERSISTENCE API
@[https://docs.corda.net/api-persistence.html]
- Allows to sync vault contractStates (or just parts) to an
external DDBB to allow complex SQL queries not possible with
the vault-query-API.
- ORM makes use of standard JPA-annotations mapping to table rows
The node will take charge of automatically sync the state when
updated in the local vault as part of a TX.
- By default an H2 database is used using JDBC.
STEPS:
1) ContractState will implement Gº˂˂QueryableState˃˃º
to allows querying the state in the node's database using custom attributes
interface GºQueryableStateº: ContractState {
fun supportedSchemas(): Iterable˂OºMappedSchemaº˃
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ Nodes have an internal
schemas can evolve represents a given ←Bº˂˂SchemaService˃˃º config/customization
in the DDBB relational schema point for ORM which decides what data
with a list of persist for a given OºMappedSchemaº
classes that can
be used in the generated
object graph to config.
the ORM tool. The constructor
will accepts a list of all
JPA entity classes for the
provided schema in MappedTypes
fun generateMappedObject(schema:OºMappedSchemaº): PersistentState
^^^^^^^^^^^^^^^^^^^^
Once the schema is selected the BºSchemaServiceº
will delegate here to generate a corresponding
representation (mapped object). The mapped object
should be an instance of a PersistentState subclass,
to facilitate ORM, and marked as a JPA 2.1 Entity
with a defined table name and having Kotlin-properties
(getters/setters) annotated to SQL columns and types.
Additional entities can be included to model complex
collections, ...
}
interface BºSchemaServiceº {
data class SchemaOptions(val databaseSchema: String? = null, val tablePrefix: String? = null)
val schemaOptions: Map˂OºMappedSchemaº, SchemaOptions˃
fun selectSchemas(state: ContractState): Iterable˂OºMappedSchemaº˃
fun generateMappedObject(state: ContractState, schema: MappedSchema): PersistentState
}
- OºMappedSchemaº implementation at:
@[https://github.com/corda/corda/blob/master/core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt]
open class OºMappedSchemaº(
schemaFamily: Class˂*˃,
val version: Int,
val mappedTypes: Iterable˂Class˂*˃˃) {
valºnameº: String = schemaFamily.name
open val migrationResource: String? = null ← Opt classpath containing ddbb changes for [mappedTypes]
...
}
ºCustom schema registrationº
- The node bootstrap process will scan for states that
implement the Queryable state interface.
Tables are then created as specified by the MappedSchema
identified by each state’s supportedSchemas method.
ºFor testing purposesº it is necessary to manually register
the packages containing custom schemas as follows:
- Tests using MockNetwork and MockNode must explicitly
register packages using the cordappPackages parameter of MockNetwork
- Tests using MockServices must explicitly
register packages using the cordappPackages parameter of the MockServices
makeTestDatabaseAndMockServices() helper method.
(Kotlin) Example:
package net.corda.finance.schemas
import net.corda.core.identity.AbstractParty
import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
import net.corda.core.contracts.MAX_ISSUER_REF_SIZE
import org.hibernate.annotations.Type
import javax.persistence.*
object CashSchema
@CordaSerializable
object CashSchemaV1 : MappedSchema(schemaFamily = CashSchema.javaClass, version = 1, mappedTypes = listOf(PersistentCashState::class.java))
{
override val migrationResource = "cash.changelog-master"
@Entity
@Table(name = "contract_cash_states", indexes = [Index(name = "ccy_code_idx", columnList = "ccy_code"), Index(name = "pennies_idx", columnList = "pennies")])
class PersistentCashState(
@Column(name = "owner_name", nullable = true)
var owner: AbstractParty?,
@Column(name = "pennies", nullable = false)
var pennies: Long,
@Column(name = "ccy_code", length = 3, nullable = false)
var currency: String,
@Column(name = "issuer_key_hash", length = MAX_HASH_HEX_SIZE, nullable = false)
var issuerPartyHash: String,
@Column(name = "issuer_ref", length = MAX_ISSUER_REF_SIZE, nullable = false)
@Type(type = "corda-wrapper-binary")
var issuerRef: ByteArray
) : PersistentState()
}
ºPersisting Hierarchical (relationships) Dataº
- Discouraged. See official doc for more info
ºIdentity mappingº
Schema entity attributes defined by identity types
(AbstractParty, Party, AnonymousParty) are automatically processed.
- only the X500Name is persisted (for non well-known id.) or null.
- identity keys are never persisted:
- Developers should use the IdentityService to resolve:
X500-identity-names → keys
ºJDBC sessionº
- direct JDBC connection(==session) is also allowed:
val nativeQuery = "SELECT v.transaction_id, v.output_index FROM vault_states v WHERE v.state_status = 0"
database.transaction {
val jdbcSession = services.jdbcSession() // ← Use ServiceHub to get the JDBC connection
val prepStatement = jdbcSession.prepareStatement(nativeQuery)
val rs = prepStatement.executeQuery()
JDBC sessions can be used in flows and services (see “Writing flows”).
*JPA Support
- Direct JPA is also available to flows through the withEntityManager method.
which can used to persist and query entities which inherit from MappedSchema.
- particularly useful if off-ledger data must be maintained in conjunction
with on-ledger state data.
- See oficial docs for examples.
DDBB table nomenclature
- node_ prefixed tables are private to Corda
and should not be directly accessed at all.
- contract_ prefixed tables are generated by apps
and designed to be queried by end users, GUIs, tools etc.
Error Ctrl
requireThat
DSL Example
(illegal arg error)
replacing IllegalArgumentException
requireThat {
"No inputs should be consumed @ Issue" using (tx.inputs.isEmpty())
"Only one output state permitted" using (tx.outputs.size == 1)
val out = tx.outputs.single() as XState
"sender == recipient not allowed" using (out.sender != out.recipient)
"All participants must be signers" using (command.signers.containsAll(out.participants))
"X's value must be ˃0 " using (out.x.value ˃ 0)
}
Understanding source
net.corda.core
@[https://github.com/corda/corda]
º./core/src/main/kotlin/net/corda/core/identity/PartyAndCertificate.kt º
º./core/src/main/kotlin/net/corda/core/identity/Party.kt º
./core/src/main/kotlin/net/corda/core/identity/CordaX500Name.kt
./core/src/main/kotlin/net/corda/core/identity/IdentityUtils.kt
./core/src/main/kotlin/net/corda/core/identity/AnonymousParty.kt
º./core/src/main/kotlin/net/corda/core/identity/AbstractParty.kt º
./core/src/main/kotlin/net/corda/core/KeepForDJVM.kt
./core/src/main/kotlin/net/corda/core/CordaInternal.kt
./core/src/main/kotlin/net/corda/core/crypto/DigitalSignature.kt
./core/src/main/kotlin/net/corda/core/crypto/SignableData.kt
./core/src/main/kotlin/net/corda/core/crypto/MerkleTree.kt
./core/src/main/kotlin/net/corda/core/crypto/CompositeKey.kt
./core/src/main/kotlin/net/corda/core/crypto/CompositeKeyFactory.kt
./core/src/main/kotlin/net/corda/core/crypto/SignatureScheme.kt
./core/src/main/kotlin/net/corda/core/crypto/TransactionSignature.kt
./core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt
./core/src/main/kotlin/net/corda/core/crypto/CordaSecurityProvider.kt
./core/src/main/kotlin/net/corda/core/crypto/SignatureMetadata.kt
./core/src/main/kotlin/net/corda/core/crypto/CompositeSignaturesWithKeys.kt
./core/src/main/kotlin/net/corda/core/crypto/NullKeys.kt
./core/src/main/kotlin/net/corda/core/crypto/CryptoUtils.kt
./core/src/main/kotlin/net/corda/core/crypto/PartialMerkleTree.kt
./core/src/main/kotlin/net/corda/core/crypto/CompositeSignature.kt
./core/src/main/kotlin/net/corda/core/crypto/SignedData.kt
./core/src/main/kotlin/net/corda/core/crypto/Crypto.kt
./core/src/main/kotlin/net/corda/core/flows/NotaryWireFormat.kt
º./core/src/main/kotlin/net/corda/core/flows/InitiatedBy.kt º
./core/src/main/kotlin/net/corda/core/flows/FlowLogicRef.kt
./core/src/main/kotlin/net/corda/core/flows/ReceiveTransactionFlow.kt
./core/src/main/kotlin/net/corda/core/flows/SchedulableFlow.kt
./core/src/main/kotlin/net/corda/core/flows/FinalityFlow.kt
./core/src/main/kotlin/net/corda/core/flows/FlowException.kt
º./core/src/main/kotlin/net/corda/core/flows/InitiatingFlow.ktº
./core/src/main/kotlin/net/corda/core/flows/NotaryError.kt
./core/src/main/kotlin/net/corda/core/flows/StartableByService.kt
./core/src/main/kotlin/net/corda/core/flows/NotaryChangeFlow.kt
./core/src/main/kotlin/net/corda/core/flows/CollectSignaturesFlow.kt
./core/src/main/kotlin/net/corda/core/flows/StateMachineRunId.kt
./core/src/main/kotlin/net/corda/core/flows/ContractUpgradeFlow.kt
./core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt
./core/src/main/kotlin/net/corda/core/flows/FlowInitiator.kt
./core/src/main/kotlin/net/corda/core/flows/FlowStackSnapshot.kt
./core/src/main/kotlin/net/corda/core/flows/FlowSession.kt
./core/src/main/kotlin/net/corda/core/flows/AbstractStateReplacementFlow.kt
./core/src/main/kotlin/net/corda/core/flows/StartableByRPC.kt
º./core/src/main/kotlin/net/corda/core/flows/FlowLogic.kt º
./core/src/main/kotlin/net/corda/core/flows/NotaryFlow.kt
./core/src/main/kotlin/net/corda/core/flows/WithReferencedStatesFlow.kt
./core/src/main/kotlin/net/corda/core/CordaOID.kt
./core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt
./core/src/main/kotlin/net/corda/core/transactions/NotaryChangeTransactions.kt
./core/src/main/kotlin/net/corda/core/transactions/ContractUpgradeTransactions.kt
./core/src/main/kotlin/net/corda/core/transactions/TransactionWithSignatures.kt
./core/src/main/kotlin/net/corda/core/transactions/BaseTransaction.kt
./core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt
./core/src/main/kotlin/net/corda/core/transactions/BaseTransactions.kt
./core/src/main/kotlin/net/corda/core/transactions/SignedTransaction.kt
./core/src/main/kotlin/net/corda/core/transactions/MerkleTransaction.kt
º./core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt º
º./core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.ktº
./core/src/main/kotlin/net/corda/core/DoNotImplement.kt
./core/src/main/kotlin/net/corda/core/ClientRelevantError.kt
./core/src/main/kotlin/net/corda/core/CordaException.kt
./core/src/main/kotlin/net/corda/core/context/Trace.kt
./core/src/main/kotlin/net/corda/core/context/InvocationContext.kt
./core/src/main/kotlin/net/corda/core/utilities/...
º./core/src/main/kotlin/net/corda/core/utilities/ProgressTracker.kt º
./core/src/main/kotlin/net/corda/core/contracts/FungibleState.kt
º./core/src/main/kotlin/net/corda/core/contracts/ContractState.kt º
./core/src/main/kotlin/net/corda/core/node/services/vault/QueryCriteriaUtils.kt
º./core/src/main/kotlin/net/corda/core/node/services/vault/QueryCriteria.kt º
./core/src/main/kotlin/net/corda/core/node/services/PartyInfo.kt
./core/src/main/kotlin/net/corda/core/node/services/TransactionStorage.kt
./core/src/main/kotlin/net/corda/core/node/services/NetworkParametersService.kt
./core/src/main/kotlin/net/corda/core/node/services/TransactionVerifierService.kt
./core/src/main/kotlin/net/corda/core/node/services/KeyManagementService.kt
./core/src/main/kotlin/net/corda/core/node/services/NetworkMapCache.kt
./core/src/main/kotlin/net/corda/core/node/NodeInfo.kt
./core/src/main/kotlin/net/corda/core/node/ServiceHub.kt
./core/src/main/kotlin/net/corda/core/node/NetworkParameters.kt
./core/src/main/kotlin/net/corda/core/node/AppServiceHub.kt
./core/src/main/kotlin/net/corda/core/schemas/CommonSchema.kt
./core/src/main/kotlin/net/corda/core/schemas/PersistentTypes.kt
./core/src/main/kotlin/net/corda/core/cordapp/CordappProvider.kt
./core/src/main/kotlin/net/corda/core/cordapp/CordappConfig.kt
º./core/src/main/kotlin/net/corda/core/cordapp/Cordapp.kt º
./core/src/main/kotlin/net/corda/core/cordapp/CordappContext.kt
./core/src/main/kotlin/net/corda/core/cordapp/CordappInfo.kt
./core/src/main/kotlin/net/corda/core/cordapp/ConfigException.kt
./core/src/main/kotlin/net/corda/core/concurrent/ConcurrencyUtils.kt
./core/src/main/kotlin/net/corda/core/concurrent/CordaFuture.kt
./core/src/main/kotlin/net/corda/core/messaging/RPCOps.kt
./core/src/main/kotlin/net/corda/core/messaging/ClientRpcSslOptions.kt
./core/src/main/kotlin/net/corda/core/messaging/RPCReturnsObservables.kt
./core/src/main/kotlin/net/corda/core/messaging/CordaRPCOps.kt
./core/src/main/kotlin/net/corda/core/messaging/Messaging.kt
./core/src/main/kotlin/net/corda/core/messaging/FlowHandle.kt
./core/src/main/kotlin/net/corda/core/Utils.kt
./core/src/main/kotlin/net/corda/core/StubOutForDJVM.kt
...
DevOps
UUID: 0ba845f3-579d-491c-b580-9f9803808117
(X.509)IDENTITIES
https://docs.corda.net/key-concepts-identity.html
- Identities can represent node/legal/service identities
- Signed by the Doorman or a well known identity
- Well known identities are published in the network map
- Confidential identities are only shared on a need to know basis
-ºConfidential identitiesº are only ºshared on a need to know basisº:
Although there are several elements to the Corda transaction
privacy model, including ensuring that transactions are only
shared with those who need to see them, and planned use of
Intel SGX TEE, it is important to provide defense in depth
against privacy breaches.
Confidential identities are used to ensure that even if a
third party gets access to an unencrypted transaction, they
cannot identify the participants without additional information.
PERMISSIONING
-@[https://docs.corda.net/permissioning.html]
This certificate maps a well-known node identity to:
A real-world legal identity
The network operator enforces rules regarding the information that nodes must provide and the know-your-customer processes they must undergo before being granted this certificate.
│ºCERTIFICATE HIERARCHYº │ "project"/certificates file
│ │
│*network─root CA: ─ Can be deleted after initial registration ─────────── network─root─truststore.jks
│ │ │
│ └─ºroot network CAº: ─ defines the extent of a compatibility zone ─────────────────────── truststore.jks
│ │ ─ do NOT contain a role extension │
│ └─ºdoorman CAº: ─ issued/signed by root─network─CA │
│ │ ─ used day─to─day key signing to reduce the . │
│ │ risk of the root─CA private key being compromised.│
│ ├─ºnode CAº: ─ issued/signed by doorman─CA ───────────────────── nodekeystore.jks
│ │ │ ─ uses to issue/sign its identity keys │ sslkeystore.jks
│ │ │ ─ and TLS certificates │ └┬┘
│ │ │ ─ One by node, can issue child certificates │ jks:Java keystore format
│ │ │ ─ Maps to a legal identity │ (may change to support
│ │ │ ─ can set their own role flags on certificates │ PKCS#12 keystores in
│ │ │ ─ X509 Name Constrain guarantees uniqueness │ a future)
│ │ │ in the network │
│ │ └─ºLegal Identityº: ─ issued/signed by some node─CA │
│ │ and TLS certs │
│ │ │
│ │ │ ┌────────────────────────────────────────────────┐
│ │ └GºConfidential º: ─ issued/signed legal identity │ºCORDA CERTIFICATE ROLE EXTENSIONº │
│ │ Gºidentity certsº ─ Only applies to TX parties │─ custom X.509v3 extension specifying the role │
│ │ ^^^^^^^^^^^^^^ (not used by notaries) │ the certificate relates to. │
│ │ Party certs are marked as │ ─ OID is set to 1.3.6.1.4.1.50530.1.1 │
│ │ either a well known legal │ ─ non─critical │
│ │ or a confidential identity │ (can be ignore "outside Corda") │
│ │ │ ─ A single ASN.1 integer used to tag the role:│
│ └─*Service Identity: Well known (public) identity of │ ─ Doorman │
│ a clustered service (notary,...) │ ─ Network map │
│ ─ Service identity │
┌─────────────────────────────────────────────────────────────────┐ │ (used in distributed notaries) │
│ºkey pairs and certificates restrictionsº │ │ ─ Node certificate authority │
│ ─ certificates must follow the X.509v3 standard │ │ (can issue TLS and identity certs) │
│ │ │ ─ Transport layer security │
│ ─ The TLS certificates must follow the TLS v1.2 standard │ │ ─ Well─known legal identity │
│ │ │ ─ Confidential legal identity │
│ ─ The root network CA, doorman CA, and node CA keys, │ └────────────────────────────────────────────────┘
│ as well as the node TLS keys, must follow one of the following│ ┌─────────────────────────────────────┐
│ schemes: │ │The certificate chain linking a │
│ ─ ECDSA using the NIST P─256 curve (secp256r1) │ │Gºconfidential identityºto a node │
│ ─ ECDSA using the Koblitz k1 curve (secp256k1) │ │or legal identity is only provided │
│ ─ RSA with 3072─bit key size or higher │ │on a need─to─know─basis. │
│ │ │This ensures that even if an attacker│
│ ─ Node CA certificates must have the basic constraints extension│ │gets access to an unencrypted TX, │
│ set to true │ │they cannot identify the TX's │
│ │ │participants without additional info │
│ ─ The TLS certificates must have the basic constraints extension│ └─────────────────────────────────────┘
│ set to false │
│ │
│ºNOTE:ºIn a typical installation, node administrators need not be│
│ aware of these, only if PKI is managed by external tools │
└─────────────────────────────────────────────────────────────────┘
Network map
Service
@[https://docs.corda.net/network-map.html]
- network map == ºcollection of signed-by-node NodeInfo (hashed?) objects (reachable nodes)º
+ parameters file with settings that all nodes need to agree on to remain in sync
- A node can receive NodeInfo objects from:
- A network map server (HTTP protocol - Corda 4.0+)
- .../additional-node-infos directory @ local noe
_ _ _____ _______ _____ ____ _ __
| \ | | ____|_ _\ \ / / _ \| _ \| |/ /
| \| | _| | | \ \ /\ / / | | | |_) | ' /
| |\ | |___ | | \ V V /| |_| | _ ˂| . \
|_| \_|_____| |_| \_/\_/ \___/|_| \_\_|\_\
____ _ ____ _ __ __ _____ _____ _____ ____ ____
| _ \ / \ | _ \ / \ | \/ | ____|_ _| ____| _ \/ ___|
| |_) / _ \ | |_) | / _ \ | |\/| | _| | | | _| | |_) \___ \
| __/ ___ \| _ | / ___ \| | | | |___ | | | |___| _ | ___) |
|_| /_/ \_\_| \_\/_/ \_\_| |_|_____| |_| |_____|_| \_\____/
notaries :
maxMessageSize : (in bytes) of an individual message sent over the wire.
- attachments may be fragmented for streaming transfer,
- however, an individual transaction or flow message may
not be larger than this value.
maxTransactionSize :(in bytes) for the TX object and its attachments.
modifiedTime : time when network parameters were last modified
by the compatibility zone operator.
epoch : Version number of the network parameters.
Starting from 1, increment whenever any parameter change.
minimumPlatformVersion:
whitelistedContractImplementations:
whitelisted versions of contract code.
For each contract-class there is a list of SHA-256-hashes
of the approved CorDapp jar versions containing that contract.
Read more about Zone constraints here API: Contract Constraints
eventHorizon :- Time after which nodes are considered to be unresponsive
and removed from network map.
- Nodes republish their NodeInfo on a regular interval.
Network map treats that as a heartbeat from the node.
packageOwnership :- network-wide java package list that were
successfully claimed (signed) by their owners.
- An owned contract in a JAR that is not
signed by the rightful owner is most likely
a sign of malicious behaviour:
- The transaction verification logic will throw
an exception when this happens.
Read more about Package ownership here
Package namespace ownership.
Setting Up
Getting Set Up:@[https://docs.corda.net/getting-set-up.html]
ºCordApp Exampleº
$ git clone @[https://github.com/corda/cordapp-example]
$ cd cordapp-example
$ gradlew deployNodes
$ ./kotlin-source/build/nodes/runnodes.sh
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- (Wait until all the terminal windows display either
"Webserver started up in XX.X sec" or "Node for "NodeC"
started up and registered in XX.XX sec")
- Test front end at @[http://localhost:10007/web/example/]
Docker Image
@[https://docs.corda.net/head/docker-image.html]
ºSummaryº
Package
namespace
Ownership (4.0+)
@[https://docs.corda.net/design/data-model-upgrades/package-namespace-ownership.html]
Monitoring
Nodes
@[https://medium.com/corda/monitoring-corda-nodes-part-1-3316d26d8fda]
Releases
Ext.Links
@[https://docs.corda.net/release-notes.html] Release notes
@[https://docs.corda.net/changelog.html] Changelog
@[https://docs.corda.net/codestyle.html] Code style guide
@[https://docs.corda.net/testing.html] Testing Corda
Training:
@[https://github.com/corda/corda-training-materials]
4.2
- Corda Enterprise 4.2 - new features explained
@[https://www.youtube.com/watch?v=ydMMb1wcCT0&list=PLi1PppB3-YrVeHKIhNxm3_4NvO0AFSvWr]
4.0/4.1
@[https://docs.corda.r3.com/releases/4.0/release-notes.html]
@[https://docs.corda.net/release-notes.html#corda-4-1]
- 150 Issues Fixed
- minimum JDK: 8u171 (fixes certain ZIP compression bugs)
- Kotlin: 1.2.71
- Gradle: 4.10.1
- Work on wire and API stability
- Corda 3 States/apps transparently usable
UPDATE:
- Upgrading Apps:@[https://docs.corda.net/app-upgrade-notes.html]
- Upgrading node:@[https://docs.corda.net/node-upgrade-notes.html]
- WARN:ºdata model improvements are changes to the consensus rulesº
To use apps that benefit from them, all nodes in a compatibility zone
must be upgraded and the zone must be enforcing that upgrade.
Changes for developers in Corda 4
_ reference input states
- CorDapps-Signature-constraints
- State pointers
- New GUI network builder tool
- build Docker images for local deployment
- remotely control Microsoft Azure to
create a test network in the cloud.
- JPA access in flows and services
- Previously only jdbcConnection API was offered
on FlowLogic.
- Security upgrades
- Sealed JARs ensures JARs cannot define classes
in each other's packages, thus ensuring Java's
package-private visibility feature works.
- The Gradle plugins now seal your JARs by default.
- BelongsToContract annotation:
CorDapps are currently expected to verify that
the right contract is named in each state object.
ºThis manual step is easy to missº, which would make
the app less secure in a network where you trade
with potentially malicious counterparties.
The platform now handles this for you by allowing
you to annotate states with which contract governs them.
- If states are inner classes of a contract class,
this association is automatic.
- Two-sided FinalityFlow and SwapIdentitiesFlow.
- FinalityFlow SwapIdentitiesFlow in API Corda ˂4.0
was insecure because nodes
would accept any finalised TX,
outside of the context of a containing flow.
- This would allow TXs to be sent to a
node bypassing things like business network
membership checks.
- Package namespace ownership:
- Corda 4 allows app developers to register their
keys and Java package namespaces with the zone operator.
- Any JAR that defines classes in these namespaces will
have to be signed by those keys.
- opt-in feature: designed to eliminate potential confusion
that could arise if a malicious developer created classes
in other people's package namespaces
- Network parameters in TXs
- TX now have the ºcurrently valid signed NetworkParameters fileº
attached to each TX.
- allows future introspection of states to ascertain
what was the accepted global state of the network
at the time they were notarised.
- new signatures must be working with the current globally
accepted parameters. The notary signing a TX will check
that it does indeed reference the current in-force network
parameters, meaning that old (and superseded) network
parameters can not be used to create new TXs.
- RPC upgrades:
- AMQP/1.0 is now default serialization framework across all of Corda
(checkpointing aside) replacing older Kryo implementation.
- Class synthesis:
- RPC framework supports the "class carpenter" feature.
Clients can now freely download and deserialise objects,
(contract states,...) without having the class files
in the local CLASSPATH. They will be synthesised on the fly.
(Used, for example, by the Blob Inspector tool)
- SSL.
- Preview of deterministic Deterministic JVM
- Out of the box a standard JVM is not fully deterministic
- Configurable flow responders
- It is possible for flows in one app to subclass and
take over flows from another allowing to ºcreate shared flow logicº
Ex:
- a site-specific app could be developed that causes TX
details to be converted to a PDF and sent to a particular printer.
inappropriate to put into shared business logic, but suitable to
put into a user-specific app developed themselves.
- Target/minimum platform versions in dApp spec
- added to JAR manifest.
- target version: which version of the platform the app was tested against.
"" We recommend that maintained applications always try and target
the latest version of the platform"""
- ºSetting a target version does not imply your app requires a node º
ºof that version, merely that it's been tested against that versionº
ºand can handle any opt-in changes. º
- minimum version: if running node is too old, the app won't be loaded.
- Developers can set it when starting to use new features and APIs.
DevOps
- Official Docker images based on Ubuntu andºuses the Azul Zulu spin of Java 8º
(Other tools will follow)
- Auto-acceptance for network parameters updates
- Automatic error codes
ºErrors generated in Corda are now hashed to produce a º
ºunique error code that can be used to perform a lookup into a knowledge base.º
Ex:
[ERROR] 2018-12-19T17:18:39,199Z ... [errorCode=ºwuxa6fº, moreInformationAt=https://errors.corda.net/OS/4.0/*wuxa6f*]
- new command line handling framework.
- Improved, coloured help output.
-ºCommon options have been standardisedº
- bash/zsh auto completion files.
- Liquibase for database schema upgrades on node bootstrap.
- Ability to pre-validate configuration files
No need to start the rest of the node.
$ java -jar corda-4.0.jar validate-configuration
- backpressure flow-control for notaries
- Nodes will be ordered to back off if a notary is getting too busy
and app flows will pause to give time for the load spike to pass.
- Retirement of non-elliptic Diffie-Hellman for TLS
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 family of ciphers is retired
See also:
- What's new with Corda Enterprise 4:
https://www.r3.com/wp-content/uploads/2019/05/CordaEnterprise4_Enhancements_FS.pdf
https://docs.corda.net/app-upgrade-notes.html
3.0
TODO
State pointers
- Corda 4.0+
- formalize a recommended design pattern in which
ºstates may refer to other states on the ledger by StateRefº
(a pair of TX hash and output index that is sufficient to
locate any information on the global ledger).
- They work together with the reference states feature to
make it easy for data to point to the latest version of
any other piece of data, with the right version being
automatically incorporated into transactions for you.
Network
Builder
- 4.0+
- GUI network builder tool
- build Docker images for local deployment
- remotely control Microsoft Azure to
create a test network in the cloud.
Custom Node Service
@[https://docs.corda.net/node-services.html]
Extracted from @[https://docs.corda.net/api-persistence.html]
The following example illustrates the creation of a custom Corda service using a jdbcSession:
object CustomVaultQuery {
º@CordaServiceº
class Service(val services: AppServiceHub) : SingletonSerializeAsToken() {
private companion object {
private val log = contextLogger()
}
fun rebalanceCurrencyReserves(): List˂Amount˂Currency˃˃ {
val nativeQuery = """
select
cashschema.ccy_code,
sum(cashschema.pennies)
from
vault_states vaultschema
join
contract_cash_states cashschema
where
vaultschema.output_index=cashschema.output_index
and vaultschema.transaction_id=cashschema.transaction_id
and vaultschema.state_status=0
group by
cashschema.ccy_code
order by
sum(cashschema.pennies) desc
"""
log.info("SQL to execute: $nativeQuery")
val session = services.jdbcSession()
return session.prepareStatement(nativeQuery).use { prepStatement -˃
prepStatement.executeQuery().use { rs -˃
val topUpLimits: MutableList˂Amount˂Currency˃˃ = mutableListOf()
while (rs.next()) {
val currencyStr = rs.getString(1)
val amount = rs.getLong(2)
log.info("$currencyStr : $amount")
topUpLimits.add(Amount(amount, Currency.getInstance(currencyStr)))
}
topUpLimits
}
}
}
}
}
which is then referenced within a custom flow:
@Suspendable
@Throws(CashException::class)
override fun call(): List˂SignedTransaction˃ {
progressTracker.currentStep = AWAITING_REQUEST
val topupRequest = otherPartySession.receive˂TopupRequest˃().unwrap {
it
}
val customVaultQueryService = serviceHub.cordaService(CustomVaultQuery.Service::class.java)
val reserveLimits = customVaultQueryService.rebalanceCurrencyReserves()
val txns: List˂SignedTransaction˃ = reserveLimits.map { amount -˃
// request asset issue
logger.info("Requesting currency issue $amount")
val txn = issueCashTo(amount, topupRequest.issueToParty, topupRequest.issuerPartyRef, topupRequest.notaryParty)
progressTracker.currentStep = SENDING_TOP_UP_ISSUE_REQUEST
return@map txn.stx
}
otherPartySession.send(txns)
return txns
}
For examples on testing @CordaService implementations,
see the oracle example @[https://docs.corda.net/oracles.html]
Financial
Models
- https://docs.corda.net/financial-model.html
Corda provides a large standard library of data types used in
financial applications and contract state objects.
These provide a common language for states and contracts.
Amount
Financial states (LinearState, DealState, FungibleAsset)
- Interest rate swaps contract: https://docs.corda.net/contract-irs.html
API Contract
constraints
@[https://docs.corda.net/api-contract-constraints.html]
Reasons for Contract Constraints
Contract constraints solve two problems faced by any decentralised ledger that supports evolution of data and code:
- Controlling and agreeing upon upgrades
- Preventing attacks
Upgrades and security are intimately related because if an attacker can “
upgrade” your data to a version of an app that gives them a back door, they
would be able to do things like print money or edit states in any way they
want. That’s why it’s important for participants of a state to agree on what
kind of upgrades will be allowed.
Every state on the ledger contains the fully qualified class name of a
Contract implementation, and also a constraint. This constraint specifies
which versions of an application can be used to provide the named class, when
the transaction is built. New versions released after a transaction is signed
and finalised won’t affect prior transactions because the old code is attached to it.
ºImplicit vs Explicit Contract upgradesº
Constraints are not the only way to manage upgrades to transactions.
There are two ways of handling upgrades to a smart contract in Corda:
- Implicit: By pre-authorising multiple implementations of the contract ahead
of time, using constraints.
- Explicit: By creating a special contract upgrade transaction and getting
all participants of a state to sign it using the contract upgrade flows.
Corda supports several types of constraints to cover a wide set of client requirements:
- Hash constraint:
- Compatibility zone whitelisted (or CZ whitelisted) constraint:
- Signature constraint: allows app issuers to express the complex social
and business relationships that arise around code ownership.
- Always accept constraint: insecure but convenient for testing.
(See official doc for more info)
CorDapps
Signature
constraints
- Corda 4.0+
- CorDapps built by the corda-gradle-plugins are now signed
and sealed JAR files by default.
- signing can be configured or disabled with the default
Corda-development-certificate.
- When an app is signed, that automatically activates the use
of signature constraints:
- allow states to express what contract logic governs
them socially, as in
º"any contract JAR signed by a threshold of these N keys is suitable"º,
rather than just by hash or via zone whitelist rules (Corda ˂4.0)
ClientRPC-API
@[https://docs.corda.net/tutorial-clientrpc-api.html]
Tec.Radar
Corda Network
@[https://corda.network/]
- Live Version 2018-12
- publicly-available internet of Corda nodes
operated by network participants.
- Corda Network enables interoperability
not possible with separate, isolated Corda networks,
allowing participants to move cash, digital assets,
and identity data from one application or business-line
to another.
- Business network operators also benefit by being able
to access network-wide services, and reuse the
trust root and network services, instead of building and
managing their own.
-ºA common trust root surrounds all TXs,º
andºa consistent set of network parametersº
ensures all participants may transact with each other.
- Governed by an independent, not-for-profit foundation.
- Spring 2019: transitional board of participants elected
- until democratic elections are held a year later.
- supports many sub-groups of participants running
particular CorDapps (knowns as "business networks"),
- Each sub-groups will often have a co-ordinating party
(the 'business network operator') who manages the
distribution of the app and rules, including membership,
for its use.
ºKey servicesº
- Identity Service
- Controls admissions of participants into Corda Network.
- The service receives certificate signing requests (CSRs)
from prospective network participants, reviews and
validates/rejects the CSRs.
- Once a valid X509 node cert. is received the node will
be able to register itself with the Network Map Service.
ºNetwork Map Serviceº
- accepts:
- digitally signed documents describing
- network routing
- information from nodes
- makes its info. available to all Corda Network nodes.
ºNotary Serviceº
- and the latter is provided byºone or moreºNotary Services.
- Business network operators and network participants may choose to enter
into legal agreements which rely on the presence of such digital signatures
when determining whether a transaction to which they are party, or upon the
details of which they otherwise rely, is to be treated as 'confirmed' in
accordance with the terms of the underlying agreement.
ºSupport Service is also providedº
Unordered
Deterministic JVM
@[https://docs.corda.net/key-concepts-djvm.html]
- Preview in 4.0
Debugging a Cordapp
@[https://docs.corda.net/debugging-a-cordapp.html?highlight=debug]
Derivative Contracts
From corda doc:
... an "Interest Rate Swap contract" or "Equity OTC Option" are
expected to be storaged as the same "Derivative contract" in DDBB
schema
STATE API
Other defined State Interfaces:
ºinterface Scheduledº
ºinterface SchedulableStateº: ContractState ← allows to schedule future actions for the state (payment on date) (see Event scheduling)
ºinterface CommandDataº
ºinterface MoveCommandº: CommandData
ºinterface Contractº
ºinterface UpgradedContractº˂in OldState : ContractState, out NewState : ContractState˃ : Contract
ºinterface UpgradedContractWithLegacyConstraint˂in OldState... , out NewState˃º: UpgradedContract˂OldState, NewState˃
FilteredTransaction
@[https://docs.corda.net/api/kotlin/corda/net.corda.core.transactions/-filtered-transaction/index.html]
Class representing merkleized filtered transaction.
Parameters:
- id - Merkle tree root hash.
- filteredComponentGroups - list of transaction components groups
remained after filters are applied to WireTransaction.
- groupHashes - the roots of the transaction component groups.
TX Output states
When creating a new transaction, the output states that the
transaction will propose do not exist yet, and must therefore be
created by the proposer(s) of the transaction. However, the input
states already exist as the outputs of previous transactions. We
therefore include them in the proposed transaction by reference.
Notary Clock Precision
It is assumed that the time feed for a notary is GPS/NaviStar time as
defined by the atomic clocks at the US Naval Observatory. This time
feed is extremely accurate and available globally for free.
Transaction tear-offs
https://docs.corda.net/key-concepts-tearoffs.html
PyCorda
@[https://github.com/chainhaus/pycorda]
- Python analytics framework for Corda vault and node data
- Access node and vault data for analytics using pandas DataFrames.
- Currently only works with H2 database. We'll be adding other DBs
shortly and possibly support for queryable states.
Token SDK
@[https://training.corda.net/libraries/tokens-sdk/]
@[https://www.linkedin.com/feed/update/urn:li:activity:6565198983885570049/]
HSM Support:
Corda Enterprise 4.3 Q⅋A - Hardware security module support for highly-available notaries
https://youtu.be/QDcPafpu38s
DAML vs Java
https://www.block8.com/blog/block8-rates-r3s-corda-vs-digital-assets-daml-part-one-overview-of-state-and-transactions
https://www.block8.com/blog/block8-rates-r3s-corda-vs-digital-assets-daml-part-two
https://www.block8.com/blog/block8-rates-r3s-corda-vs-digital-assets-daml-part-three