Linking Corda States using StatePointer
February 13, 2020
Often while developing CorDapps we might want to have relationships between different ContractState
. While this is a common concern that we might come across while writing CorDapps, there was no formal design pattern to achieve this. Corda 4 introduced StatePointer
which establishes a formal design pattern to link one ContractState
to another.
Before diving into StatePointer, let’s first try to understand how the linking of states can be achieved in Corda. Linking of ContractState
can be done using two different ways:
- Using
StateRef
: This is achieved by introducing aStateRef
orStateAndRef
as a property to anotherContractState
. The trade-off of using this approach is that it can be used to point to a specific version of a state. If the pointed-to state is updated, the pointer doesn’t update. Thus this approach should be used for cases where one needs to point to a particular version of a state in perpetuity. - Using
linearId
: This is done by introducing alinearId
of a ContractState as a property to anotherContractState
. This approach always gives the most updated version of the ContractState known to the node. However, aslinearId
is used to point to aContractState
, this approach can only be used for pointing to aLinearState
.
A
StateRef
is a pointer to a ContractState, it encompasses a transactionId and and output index. The output index is the position of the ContractState in the output list produced by the transaction.
StatePointer
As the name suggests a StatePointer contains a pointer to a ContractState
. It can be included as a property to a ContractState
and can later be resolved to a StateAndRef
.
Note that
StatePointer
does not introduce a new feature in Corda, it just helps define a design pattern for something which was already possible in the platform.
The pointed-to state isn’t however immediately visible and it must be resolved first. The StatePointer interface defines resolve() method which can be used to resolve a pointer to its pointedConstractState.
Reference State and StatePointer
StatePointer uses the reference state feature internally. Thus any transaction having a ContractState
with a StatePointer will automatically have the pointed-to ContractState
included as a reference state. Consequently, the pointed-to ContractState
is also available to the Contract verify() method.
StatePointer uses the reference state feature of Corda 4 hence it requires mimimumPlatformVersion 4.
Any node receiving a ContractState
containing a StatePointer as part of a transaction would also store the pointed-to ContractState
in its ledger. The pointed-to ContractState, however, might not be relevant to the node and it may store it as a non-relevant state(If a receiving node is not a participant in the ContractState
, the state gets stored in its ledger with RelevancyStatus marked as NOT_RELEVANT).
StatePointer is an interface in Corda, with two concrete implementations:
- StaticPointer
- LinearPointer
StaticPointer
As the name suggests, StaticPointer can only be used to point to a specific version of the state, as it uses the StateRef
approach. If the pointed-to state is updated the StaticPointer would still point to the older version of the ContractState
.
Note that the PointedToState can be any ContractState
in case of StaticPointer.
An example of a StaticPointer could be a VehicleState pointing to ServiceState, once a service is done on a vehicle, the record could be appended to a service history list, however individual ServiceState remains unchanged.
LinearPointer
As you might easily guess, a LinearPointer uses the linearId
approach to point to a ContractState
. This means it can only be used to point to a LinearState
. Unlike StaticPointer, a LinearPointer would always point to the most updated version of the state (Recall that a linearId
can be used to query the most updated version of the LinearState
in the vault).
Please not that there is no guarantee that the most updated version of the
LinearState
would be fetch, it simply fetches the most updated version known to the querying node.
Note that the PointedToState must always be a LinearState
in case of LinearPointer.
An example of a LinearPointer could be a VehicleState pointing to LoanState, as the loan is gradually paid-off the LoanState changes, but the VehicleState would always point to the latest version of the LoanState.
Resolving StatePointer to ContractState
As already stated, the pointed-to state isn’t immediately visible and it must be resolved. Resolving a pointer returns a StateAndRef
object of the pointed-to state. A StatePointer can be resolved using the resolve() method. There are two ways of resolving a StatePointer.
- Resolving within a flow using serviceHub.
- Resolving inside a contract’s verify() method using LedgerTransaction.
Further reading
If you have come this far it means you are genuinely interested in Corda. You may consider joining us in our public slack channel if you have questions or are interested in learning more about Corda. Other ways to connect.
— Ashutosh Meher, Developer Evangelist at R3
Linking Corda States using StatePointer was originally published in Corda on Medium, where people are continuing the conversation by highlighting and responding to this story.