Corda Developer Notes

These are my personal notes on the Corda Blockchain and how it works. Mainly for my own understanding and some slightly more in depth notes in places I felt were interesting. Its also a more one stop shop than the documentation so everything is in one place. I’ve watched no end of “webinars”, youtube videos, read documentation and this is the end result … summarised/condensed into what’s important.

Please forgive my typos this is more of a dump from my text notes, with minimal formatting attached.

Corda Node

A Corda node is a process running in JVM. It comprises

  • A bunch of services running with a SQL DB server
  • RPC framework for users
  • Messaging service to communicate with other nodes in the service
  • custom functionality provided by cordapps

Services include:

  • Vault – all states for a node are stored here
  • Storage service – trnasaction storage – key value storage
  • Flow State machine manager (SMM) – manages flow state machines
  • Identity Mgmt – manages various identities
  • Key Mgmt – generates keys
  • Scheduler – scheduling ops in the future
  • Network Map – optional services the node can offer – essentially a phone book of all nodes on the network can be used to lookup nodes by name or by their key
  • Notary – node can serve as a notary
  • Messaging – interface to the message queue/layer – interfaces to the other nodes
    All sat on a SQL DB which various nodes interface with

A subset of services.

Service hub – devs get access to sub layer via the flow SMM.
Corda RPC ops is accessible.
Attached web server to RPC client.

Cordapp comprises:

  • flows
  • contracts
  • states
  • services

A corda node can run multiple cordapps and cordapps can depend on one another.

What requests look like when the are sent to a node

Flow contains the business logic required to access the nodes services, create a transaction, verify a transaction.

If we want to understand how a transaction looks in Corda, we can imagine a scenario where a buyer and seller want to swap Cash for some product. A transaction between a buyer and seller (2 nodes) on Corda network looks as follows:

  • Seller sends a transaction to a Buyer with state (the item) they want to sell and the price.
  • Buyer signs and sends the SignedTransaction back to the Seller
    • The transaction has two inputs:
      • the state (item)
      • the cash owned by the buyer
    • The transaction has 3 outputs:
      • the state (item) now owned by the buyer
      • cash the seller will get
      • amount of change due
  • The Seller signs and sends the SignedTransaction back to the Buyer
  • The Buyer then sends the transaction to the Notary who validates it, attaches it’s signature, which finalises the transaction.
  • The Buyer then sends the response to the Seller who, likewise, stores the transaction in its vault

The corda node attaches the notary signature to the transaction which would be stored in the storage service. Only the relevant output states would be stored in the Vault.

The vault maintains the subjective view of the ledger for a given node and its users. Once the data is in the vault, the data can be extracted via an HTTP request/RPC Query.

Two, or more, nodes participating in a transaction would store the vault state individually.

Cordapps interface with the services to store data in the vault.

Corda Network

Networks have nodes, communicating via AMQP over TLS, theres a doorman that automates provisioning of certificates when users join the network. a Network map (phone book). One or more notary services and, optionally, one or more oracle services.

Corda is a permissioned network. Certificates should be obtained from a root authority. If its good, its in the nodes folder, and the node can connect to the network and communicate successfully. No certificate, no communication.

As nodes join/leave the network, they update the Network Map service.

Cordapp provider

The cordapp provider is where new cordapps are installed to extend behaviour of the node. A node has several cordapps installed by default to handle common tasks like:

  • getting transactions and attachments from counterparties
  • upgrading contracts
  • broadcasting agreed ledger updates for recording by counterparties

Draining mode

So that we can shut down cleanly, its important in-flight flows are finished. no checkpoints should be persisted.

  • commands requiring to start new flows through RPC will be rejected
  • scheduled flows due will be ignored
  • initial P2P session messages will not be processed, so pears cannot initiate new flows involving the node
  • all other activities will proceed as usual, ensuring that the number of in-flight flows will strictly diminish The number of in-flight flows can be monitored through RPC will reduce to zero. Once it does, it is safe to shut down the node.

Notary services

A notary has three purposes

  • prevent double spends
  • validate transactions
  • time stamp transactions

Notaries provide uniqueness consensus.
If a notary never signs, the transaction is not validated.
Exception: If a transaction has no input states, then no notary signature is required.
If input states have been seen before, (stored in a map), the notary does not validate the transaction. If non-of the inputs have been seen before, they’re entered into a map and the current transaction ID input ref and requesting peer into the map. Then the notary signs the transaction and finality is reached for the transaction.

If a state reference supplied is already used in the map, the notary will not sign the transaction. The input states must be unique and unseen before.

Two types of notary exist – notifying and non-notifying. the verifying notary will need to see the transaction to verify it. A non-verifying notary does not need to see the transaction to verify it. The downside is that you leak a bit of data (with a verifying notary), the upside is you get a better assurance of correctness of the data. If you trust the party your working with you don’t need to use the verifying notary.

Continuations and Fibers

Continuation – an object that represents a computation that can be suspended/paused and resumed.

Fiber – behaves like a thread but is scheduled and managed by the java runtime or user code, rather than the kernel. It is also lightweight in terms of memory and switching costs.

A fiber = a continuation + a scheduler. Quasar offers the continuations, and the JDK already has a very good (ForkJoinPool) scheduler. So Quasar just adds continuations.

Servers now experience a larger number of concurrent connections and they spend a lot of their time waiting fro IO. Developers have two options. Write easy to write/read code which just assigns a single thread per socket. Or they write asynchronous code thats hard to read/write and debug, and difficult to work with.

Fibers try to resolve some of the difficulties exposed by asynchronous code.

Key Idea of fibers: the language run time can make some assumptions that make it more suitable for schedulers than the OS, which makes it more suitable than the OS scheduler.

Fiber class implemented in Java, behaves like a thread, so fibers implement a similar interface to Thread.

If you want to write a simple web server, you do it as you normally would assigning a new fiber for each connection. Under the hood, the fibers work asynchronously IO and performs as asynchronous IO. Blocking is generally bad.

Fibers also open the door to new, interesting programming models; Channels, Actors, Synchronous programming.

Another thing fibers offer is the ability to serialise them when they’re blocked. This can enable you to tear-down the JVM when the fiber is blocked, move the running fiber closer to the data.

From the Corda documentation:

We use continuations for the following reasons:

* It allows us to write code that is free of callbacks, that looks like ordinary sequential code.
* A suspended continuation takes far less memory than a suspended thread. It can be as low as a few hundred bytes. In contrast a suspended Java thread stack can easily be 1mb in size.
* It frees the developer from thinking (much) about persistence and serialisation.

See https://www.youtube.com/watch?v=9GlTc59XctE for more info

Corda States

States in Corda represent states as they exist in a State Machine. In a multistage flow, they represent the start, intermediate and end states.

Corda Flows

Corda Flows are where we begin to write Cordapps.

A StateMachineManager manages how flows are executed.

Flows can be triggered via SchedulableFlows. Add @SchedulableFlow to the Flow

Flows can be triggered via the RPC client API. They can also be triggered directly via the node’s RPC API from your app code (in which case they need to be annotated with StartableByRPC).

It’s possible for a flow to be of both types.

Call CordaRPCOps.startFlowDynamic to start a flow.

Call CordaRPCOps.startTrackedFlowDynamic to start a tracked flow.

Starting a flow returns a FlowHandle used to observe the result. It contains a permanent identifier for the flow: StateMachineRunId.

A flow typically has a ProgressTracker which can be used to maintain the progress state through a transaction. This involves a line of code like:

progressTracker.currentStep = RECEIVING

These steps are defined and included as a set of states for a progress tracker.

ProgressTracker.Step RECEIVING = new ProgressTracker.Step("Waiting for info");
ProgressTracker progressTracker = new ProgressTracker(RECEIVING);

Transactions often need communication between two parties. For this a FlowSession can be used. Its similar to a Session in HTTP.

Flows are shared and updated by the various parties involved in a transaction. E.g. a buyer and seller each update the Flow to indicate what stage a transaction is up to before it is finalised.

Finalising a transaction sends the transaction to a Notary.

SubFlows exist so that independent Flows can also be tracked for a given process.

CollectSignatureFlow will handle getting other nodes involved in a transaction to complete their parts and send SignedTransactions back to the Initiator.

Flows can be suspended. Clearly it makes sense to do this at various checkpoints more than at others. To introduce a checkpoint, simply add the @Suspendable annotation to segments of code in your transaction.

A flow is suspended when calling either receive, send orsendAndReceive.

Writing Contracts

A smart contract is the executable code that validates changes to state objects in transactions. State objects are the data held on the ledger, which represent the current state of an instance of a contract, and are used as inputs and outputs of transactions.

Commands can be included in transactions as additional data to verify the transaction.

States can be issued at one point in time and transacted on at a later point in time.

Contracts

Smart contracts implement the Contract interface. You could also extend OnLedgerAsset.

To implement a contract we must implement a verify() method, which either completes correctly or throws an exception.

State

A State is a class that stores data thats checked by a Contract.

States implement a ContractState interface. One subclass is OwnableState.

Commands

Validation logic of a contract may very depending on the stage of a state’s lifecycle. Commands are additional data used by contracts that aren’t represented by states that exist permanently in the ledger. This helps clarify the intent of a transaction.

A command does not need to contain data. Sometimes data is included that is not relevant to the input/output but used to verify rules relating to the transaction/state.

A command is associated with some data which may not be relevant to State.

By the time the contract runs, the signatures have already been checked.

A command is simply a data structure with a list of attached public keys. Each key has a signature proving the corresponding private key was used to sign. Contracts don’t interact directly with signatures.

Verify Function (of a Contract)

The verify() function, verifies a set of state transitions (a transaction). Given a class representing a transaction.

verify() takes a class representing a transaction and if the function returns then the transaction is considered acceptable. If it throws an exception, the transaction is rejected.

A transaction can have multiple input and output states of differing types. The set of contracts to run is decided by taking code references inside each state. Each contract is run only once.

A simple transaction could smart contract could have one input state and one output state, processed by a contract.