Account Management


Overview

The Zilliqa blockchain supports two types of accounts:

  • Non-contract - for balance transfers
  • Contract - for both balance transfers and smart contract execution

image01

While non-contract accounts simply need to record base data like balance and nonce, contract accounts also have to store smart contract code, as well as immutable and mutable states.

The diagram here shows that account data is organized according to those common to all accounts (AccountBase) and those that only contract accounts would have (Account).

note

We can distinguish a contract from non-contract account by checking if m_codeHash is NULL. We can also choose to serialize only the base fields or both the base and the contract-related fields.

Contract Account States

A transaction that requests a contract deployment triggers the generation of a new contract account and the setting up of that account's immutable and mutable states. Then, transactions that invoke transition calls on that contract account trigger the updating of the mutable states.

Immutable states are more commonly referred to as the init data, and examples of this include _scilla_version, _library, and _extlibs.

Init data is supplied to the node within the transaction body (please refer to the CreateTransaction API documentation), although the node will also eventually add more fields into init data (such as _creation_block and _this_address) during transaction processing.

Mutable states, on the other hand, are the variables that are manipulated by the Scilla interpreter as it executes a transition on the contract. The Zilliqa node provides the Scilla interpreter access to these states through the Scilla IPC server.

Account Data Storage

Storage of accounts in the Zilliqa blockchain can be quite complex to understand due to the fact that account data is spread out across several leveldb databases:

leveldb NameManaged ByKeyValue
stateAccountStoreTrieAddressAccountBase
contractCodeContractStorageAddressCode
contractInitState2ContractStorageAddressTx data field + _creation_block + _this_address
contractStateData2ContractStorageAddress.vname
Address._depth.vname
Address._type.vname
Address.vname.index1.index2...
State value
contractTrieContractStorageHash of contractStateData2 keyState value
stateRootBlockStorageLATEST_EPOCH_STATES_UPDATED
STATEROOT
Epoch number
Trie root value
stateDeltaBlockStorageTx block numberList of Account

State Tries

The state and contractTrie databases are implementations of Ethereum's Merkle Patricia Trie data structure.

A trie is a key-value data structure with a root hash and hashes along each key-value pair. The root hash is updated every time the structure is updated (e.g., by adding another key-value pair).

Please see this Medium article for how the trie structure evolves (specifically, where the root node is) as you add transactions one-by-one.

The trie provides the ability to prove that a specific key-value pair exists within the structure without the requesting party needing to know the rest of the structure. All the requesting party needs is the hash of the key-value pair at the particular time that the structure is being evaluated. For example, the contractTrie database supports requests from the GetStateProof API, which requests for proof of a particular state for an account at a specific Tx block.

The contractTrie database was implemented in order to support bridging between the Zilliqa and Ethereum blockchains. While the contract state trie is useful for the blockchain bridging aspect, it is not vital to the normal operation of the Zilliqa protocol, i.e., it has no impact on the normal transaction processing, consensus execution, and account state updating. Therefore, it does not need to be discussed further at present.

The state database, on the other hand, is used to store the AccountBase portion of the account data.

State Trie Library

Zilliqa uses Ethereum's GenericTrieDB library for the trie structure. The GenericTrieDB class contains a TraceableDB member, which manages the loading from or saving to disk (i.e., to the levelDB database) of the trie structure.

image02

The basic usage will involve:

  1. Calling init() to reset the root to NULL
  2. Calling insert() to add nodes to the trie
  3. Calling at() to access any of the added nodes
  4. Calling db() to access the underlying TraceableDB member, and then either
    1. Calling commit() to save the changes to disk
    2. Calling rollback() to discard changes

This basic usage applies to the state database. In this context, a node basically refers to the Address (key) and the AccountBase (value) pair.

For the contractTrie database, the usage is slightly more complex due to the fact that separate tries are maintained for a maximum of NUM_DS_EPOCHS_STATE_HISTORY DS epochs. As mentioned in the previous section, we won't be going deeper into contractTrie for now.

AccountStore Class Hierarchy

The diagram below highlights the Zilliqa architecture around account and account state storage.

image03

There are essentially three account store objects in a Zilliqa node:

  • AccountStore holds the accounts that have been committed to disk (i.e., the blockchain).
  • AccountStoreTemp holds the account data that resides in transient memory and that has yet to be validated by the nodes during consensus.
  • AccountStoreAtomic also holds account data in transient memory, but only for the current transaction being executed. More precisely, it is used for contract call transactions, where multiple accounts may be updated (e.g., a chain call). After the transaction is completely processed, the contents are moved to the AccountStoreTemp object.

The rest of the account store hierarchy is composed of abstract classes:

  • AccountStoreBase contains the map of accounts in transient memory. It also provides an UpdateAccount() function for use on non-contract (i.e., payment) transactions.
  • AccountStoreSC contains most of the smart contract-related functionality, including an UpdateAccount() function for use on contract (deployment and call) transactions.
  • AccountStoreTrie contains trie management functions and the GenericTrieDB instance for the base account data and its storage in the state leveldb database.

Apart from the state leveldb database, the other account-related databases listed in the previous section are managed by the ContractStorage and BlockStorage classes.

Finally, the diagram also shows that aside from the account store classes, the ScillaIPCServer also interacts with ContractStorage whenever the Scilla Interpreter requests for state access during the execution of a contract.

State Deltas

State deltas are the differences between what's stored in disk (i.e., the blockchain) and what's changed after transaction execution for a particular account (whether non-contract or otherwise).

Transaction processing by a node does not immediately result in committing any such differences to disk. As with any distributed ledger system, all nodes in the network must first reach consensus before they update their storage in a uniform manner. Until the consensus is completed (i.e., the proposed Tx Block is accepted by all nodes), state deltas must first be managed by a node separately within its transient memory.

It should also be noted that multiple transactions could be called on the same contract (for example, several users withdrawing rewards from the Staking contract), and thus the complete set of state deltas cannot be known immediately after one transaction, but rather only after all transactions for the current Tx epoch have been processed.

Another consideration unique to Zilliqa's architecture is that shards manage their own set of transactions that are different from those of other shards. This means nodes belonging to different shards will be holding different state deltas in their transient memory during the consensus period. Therefore, in order for all nodes to arrive at the same final states, these state deltas will eventually have to be shared across shards.

As can be inferred from the previous section, state deltas are generated by getting the differences for an account between AccountStore and AccountStoreTemp.

Account and State Management During Tx Epoch

image04

Account and State Management During Node Launch

image05