Linking Corda States using StatePointer

February 13, 2020
corda state pointer
Corda StatePointer

 

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:

  1. Using StateRef: This is achieved by introducing a StateRef or StateAndRef as 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.
  2. Using linearId: This is done by introducing a linearId of 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 linearId is used to point to a ContractState, this approach can only be used for pointing to a LinearState.

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.

Share: