Corda backchain verification explained
Corda does not need every node in the network to hold a copy of the entire ledger like how nodes of some blockchain technologies do. Nodes in Corda only need to agree on shared facts relevant to them. There is no single network-wide ledger. In the absence of a single global view of the ledger, nodes uses a process called “walking the chain” to verify the provenance of assets being consumed in a Corda transaction.
This blog explains how “backchains” are formed, how they figure in transaction verification, effects of long backchains and approaches to improving privacy and performance in the context of backchain verification.
Backchain verification
How transactions are linked
A transaction consists of states, commands, attachments and a time window. States can include zero or more input states, output states and reference states. Inputs are added to a transaction as a StateAndRef, a class which combines the ContractState instance of an input with its StateRef. The StateRef here is of much importance. It contains the transaction hash of the past transaction where a particular input state was produced as an output and the output index at which it was produced.
These two pieces of information from the StateRef form a link from an input state to the past transaction that produced the state as an output. These links form chains (commonly referred to as backchains) connecting each input back to an original issuance transaction. A Corda node can use these links to “walk the chain” and verify that each input was generated from a valid sequence of transactions.
Resolving and verifying transaction dependencies
A look at the code docs for SignedTransaction
class reveals that calling verify()
on it does the following:
- Checks that the transaction’s signatures are valid, optionally checks if all required signatures are present.
- Resolves inputs and attachments from the local storage
- Performs full transaction verification, including running the contracts
The verify()
check is not only called on the incoming transaction, but also on past transactions that produced the states referenced in the current transaction. Since verify()
resolves inputs and attachments from local storage, as a prior step it needs to fetch all missing transaction dependencies from the transaction proposer using the inbuilt SendTransactionFlow and ReceiveTransactionFlow.
The transaction proposer uses SendTransactionFlow to send the new transaction to the receiver and to process all subsequent requests for dependencies as the receiver walks the dependency chain.
On the receiver side the ReceiveTransactionFlow
receives the initial transaction, calls ResolveTransactionFlow
to automatically resolve its dependencies and lastly calls verify() on the SignedTransaction
instance.
Bulk fetch of transaction backchains
This Corda Enterprise feature introduced in version 4.4, optimizes transaction backchain resolution through the use of bulk requests. The Corda node configuration includes a backchainFetchBatchSize
parameter that can be used to indicate the number of states (the default is 50) that should be fetched simultaneously during backchain resolution.
Long transaction backchains
An asset modeled as a Corda state may quite likely need to live through multiple transactions before it is no longer necessary. For eg. In a naïve implementation a tokenized cash unit once issued, could have a potentially infinite number of transfers before it is redeemed. A UTXO that is a result of a long sequence of transactions, would have a long transaction backchain. Long backchains are undesirable for two reasons as outlined by Corda’s docs.
Performance: Resolution along the chain slows down significantly. As the backchain grows, a node that was previously unaware of the transaction would have to sift through a large amount of transactions during verification, hence incurring much latency from the additional I/O and compute.
Privacy: A node receiving a transaction gets the complete sequence of transactions that led to the current state of an asset. This can reveal information such as past owners of the asset, details of past exchanges/deals involving that asset etc. For example, consider the below pair of transactions. In the first transaction, E Corp buys a space ship part from R Corp for 8000 units of Star Coin. In the second transaction E Corp attempts to complete a deal for the same part with a different vendor. Here, X Corp could analyze the backchain of the Star Coin asset and find out that E Corp has previously purchased the same part for double the price offered in the current deal. This leak of past information could dampen E Corp’s chances of getting a good deal with X Corp.
Pruning long back-chains by asset re-issuance
An issuance transaction requires no inputs — hence an asset’s backchain can be severed from its current state by having a trusted issuer re-issue an asset. In this regard, Corda has out-of-the-box re-issuance flows which can be used to re-issue states with guaranteed state replacement. The re-issuance mechanism makes use of encumbrances to ensure that the deletion of the old state(which has the backchain) and the issuance of the new state happens atomically.
Improving performance and privacy
While the Corda platform itself is designed to optimize transaction privacy and performance for most cases, a CorDapp’s designers need to carefully design its elements to meet the quality requirements of their use case. This section lists a number of features and future enhancements relevant to backchain verification, which could potentially be leveraged to improve transaction privacy and performance.
Confidential identities
Participants of a transaction can generate and exchange confidential identities before constructing a transaction. Only the participants of that transaction would know the well known identity that owns a confidential identity. This means that resolution of the transaction backchain wont reveal which parties were involved in transactions that the verifying node wasn't a part of.
Using secure hardware to preserve backchain privacy
Intel SGX allows for creating private regions of memory called enclaves whose contents are protected and inaccessible to the host and any process outside the enclave. It is also possible to prove the integrity of the code running in the enclave to a remote client using a process called remote attestation. A remote client can use a key agreement protocol to establish an encrypted communication channel with the enclave.
These capabilities could potentially be used by a sender to encrypt all transaction backchain data such that only a recipient’s enclave can decrypt it and use for verifying the backchain. Thus ensuring that ledger integrity is assured without leaking information from the transaction backchain to the recipient. Corda’s technical whitepaper (p 61) and blog has more details on this privacy enhancement.
Zero knowledge proofs
Zero knowledge proofs could be used in the future to prove the validity of a transaction to a counter-party without revealing the contents of the transaction. Most references to this in the Corda context mention that this privacy upgrade will happen once ZKPs are mature enough.
Consensual states
This is a relatively new pattern which was introduced in the last CordaCon and is on the Corda 5 roadmap. It reasons that, in workflows where all of a Linear State’s participants are also signers, backchain verification, notarization and contract verification are not necessary. This programming model can potentially have significant performance and privacy benefits when applicable. This blog explains it in further detail.
Wrapping up
This post explained how StateRefs link current transaction inputs to older transaction output states thus forming a backchain which is resolved and verified along with the current transaction. It further discussed the effects of long transaction backchains on performance and privacy and lastly mentioned a number of features and future enhancements relevant to backchain verification that can be can be employed to improve transaction privacy and performance.
That's all for this post. Do leave your thoughts in the comments below and a 👏 if you found this useful. Stay tuned for more!