State declarations are provided in a form of global|owned STATE_NAME POSTFIX :: STATE_TYPE, where POSTFIX denotes how the state is accumulated with each of the operations. The following postfixes are allowed:
| Postfix | Applicable to | Meaning |
|---|---|---|
| none | global, owned | Singular state: contract has just a single value or defined single-use-seal for the state of that time |
? | global, owned | Optional state: contract may have no state of this type - or can have a singular state. |
* | global, owned | State is a list, to which genesis and contract operations can add more item(s). The list may be empty, genesis may not assign an initial value for the state. |
+ | global, owned | State is a non-empty list, to which genesis and contract operations can add more item(s). The list can't be empty, genesis must assign an initial value for the state |
{*} | global only | State is a set, to which genesis and contract operations can add more item(s). The set may be empty, genesis may not assign an initial value for the state. |
{+} | global only | State is a non-empty set, to which genesis and contract operations can add more item(s). The set can't be empty, genesis must assign an initial value for the state |
{Key*} | global only | State is a map, to which genesis and contract operations can add more keyed item(s). The map may be empty, genesis may not assign an initial value for the state. |
{Key+} | global only | State is a non-empty map, to which genesis and contract operations can add more keyed item(s). The map can't be empty, genesis must assign an initial value for the state |
Lists, sets and maps are called state collections. Lists in case of a global state are ordered according to the consensus ordering; for owned state the data are not ordered in any specific order.
Only a part of the owned state can be known, i.e. postfix doesn't guarantee the availability of all owned state data as a part of the known contract state.
Postfix puts a requirements on the state which can or must be provided by genesis and state transitions. This is the summary of these requirements:
| Schema | Genesis | Transitions | Contract state |
|---|---|---|---|
State :: Type |
<- State |
none, |
Single, always present value |
|
none, |
none, |
Optional value of type |
|
none, |
none, |
List of values, which may be empty, ordered by consensus ordering |
|
|
none, |
List of values with at least one value |
|
none, |
none, |
Set of values, which may be empty, ordered by values |
|
|
none, |
Set of values with at least one value, ordered by values |
|
none, |
none, |
Map from keys to types, which may be empty, ordered by key value |
State{Key+} :: {Type} |
none, |
none, |
Map from keys to types, with at least one key and value |
Other confined bounds (like [T; N], [T^A..B] etc) than the above listed comprehensions are prohibited to appear in the schema state declaration. The maximum number of elements in a global state collection is always restricted to 0xFFFF, the maximum number of state items in an owned state is not bounded to any upper limit (due to inability of enforcing that restriction).
If a global state needs to be a collection type by itself (for instance to be a string), it can be declared in a usual manner, with all comprehensions allowed.
It is important to remember about the difference between collections provided as a state value type, and a state itself operating as a collection. For instance,
schema Some
global State :: [Utf8]means that the State consists of a single string, and it is replaced with new operations providing that state, while
schema Some
global State[] :: [Utf8]means that the state is list of strings which accumulate over the time. If both of the contracts are created with State := "abc" in genesis, and than receive three consequent transitions with State := "xyz", State := "klm" and State := "qrs", the resulting contract state in the first case would be State := ["abc", "xyz", "klm", "qrs"] and in the second case State := "qrs"