* Updates the states API page. * Minor fixes. * Further fixes. * Adds ToC * Addresses review feedback.
5.9 KiB
API: States
Note
Before reading this page, you should be familiar with the key concepts of key-concepts-states
.
ContractState
In Corda, states are instances of classes that implement ContractState
. The ContractState
interface is defined as follows:
../../core/src/main/kotlin/net/corda/core/contracts/ContractState.kt
ContractState
has a single field, participants
. participants
is a List
of the AbstractParty
that are considered to have a stake in the state. Among other things, the participants
will:
- Usually store the state in their vault (see below)
- Need to sign any notary-change and contract-upgrade transactions involving this state
- Receive any finalised transactions involving this state as part of
FinalityFlow
ContractState sub-interfaces
The behaviour of the state can be further customised by implementing sub-interfaces of ContractState
. The two most common sub-interfaces are:
LinearState
OwnableState
LinearState
models shared facts for which there is only one current version at any point in time. LinearState
states evolve in a straight line by superseding themselves. On the other hand, OwnableState
is meant to represent assets that can be freely split and merged over time. Cash is a good example of an OwnableState
- two existing $5 cash states can be combined into a single $10 cash state, or split into five $1 cash states. With OwnableState
, its the total amount held that is important, rather than the actual units held.
We can picture the hierarchy as follows:
LinearState
The LinearState
interface is defined as follows:
../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt
Remember that in Corda, states are immutable and can't be updated directly. Instead, we represent an evolving fact as a sequence of LinearState
states that share the same linearId
and represent an audit trail for the lifecycle of the fact over time.
When we want to extend a LinearState
chain (i.e. a sequence of states sharing a linearId
), we:
- Use the
linearId
to extract the latest state in the chain from the vault - Create a new state that has the same
linearId
- Create a transaction with:
- The current latest state in the chain as an input
- The newly-created state as an output
The new state will now become the latest state in the chain, representing the new current state of the agreement.
linearId
is of type UniqueIdentifier
, which is a combination of:
- A Java
UUID
representing a globally unique 128 bit random number - An optional external-reference string for referencing the state in external systems
OwnableState
The OwnableState
interface is defined as follows:
../../core/src/main/kotlin/net/corda/core/contracts/Structures.kt
Where:
owner
is thePublicKey
of the asset's ownerwithNewOwner(newOwner: AbstractParty)
creates an copy of the state with a new owner
Because OwnableState
models fungible assets that can be merged and split over time, OwnableState
instances do not have a linearId
. $5 of cash created by one transaction is considered to be identical to $5 of cash produced by another transaction.
Other interfaces
You can also customize your state by implementing the following interfaces:
QueryableState
, which allows the state to be queried in the node's database using custom attributes (seeapi-persistence
)SchedulableState
, which allows us to schedule future actions for the state (e.g. a coupon payment on a bond) (seeevent-scheduling
)
User-defined fields
Beyond implementing ContractState
or a sub-interface, a state is allowed to have any number of additional fields and methods. For example, here is the relatively complex definition for a state representing cash:
../../finance/src/main/kotlin/net/corda/finance/contracts/asset/Cash.kt
The vault
Whenever a node records a new transaction, it also decides whether it should store each of the transaction's output states in its vault. The default vault implementation makes the decision based on the following rules:
- If the state is an
OwnableState
, the vault will store the state if the node is the state'sowner
- Otherwise, the vault will store the state if it is one of the
participants
States that are not considered relevant are not stored in the node's vault. However, the node will still store the transactions that created the states in its transaction storage.
TransactionState
When a ContractState
is added to a TransactionBuilder
, it is wrapped in a TransactionState
:
../../core/src/main/kotlin/net/corda/core/contracts/TransactionState.kt
Where:
data
is the state to be stored on-ledgercontract
is the contract governing evolutions of this statenotary
is the notary service for this stateencumbrance
points to another state that must also appear as an input to any transaction consuming this stateconstraint
is a constraint on which contract-code attachments can be used with this state