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:
StateRef: This is achieved by introducing a
StateAndRefas a property to another
ContractState. 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.
linearId: This is done by introducing a
linearIdof a ContractState as a property to another
ContractState. This approach always gives the most updated version of the ContractState known to the node. However, as
linearIdis used to point to a
ContractState, this approach can only be used for pointing to a
StateRefis 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.
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
StatePointerdoes 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:
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
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.
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
LinearStatewould 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
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.
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