Background

  1. The entire execution world state for Flow can be represented by a map: map[RegisterID]RegisterValue , where RegisterID is composed with Account/Key, such as “account_a/public_storage”; and RegisterValue are encoded byte slice used by FVM.
  2. The transactions in each block read and write the execution world state, and executing them produces register updates.
  3. In order to create a hash of the world state, all the registers are added to a mtrie, where register values are stored on leaf nodes, interim nodes are created for hashing different branches, and the hash of the root node is the hash of the world state, which act as a proof for the world state.
  4. Since mtrie stores register values on leaf nodes in memory, the memory usage grows linearly to the total size of register values, which creates a scaling bottleneck.

Storehouse benefit

  1. The idea of storehouse is to store register values onto disk, so that memory usage will grow much slower since only interim nodes will be stored in memory for proof generation.
  2. Another benefit is that since register values are separated from the trie, reading register values will become faster, especially for hot registers. That’s because reading registers from the trie will have to traverse the trie with the hash of the register, whereas registers can be indexed in the storehouse, and querying it hit at most 1 DB query.

Storehouse Design

  1. RegisterStore + RegisterlessTrie
  2. Finalized blocks and UnFinalized Forks

Correctness requirement

  1. Atomicity
  2. Consistency
  3. Isolation
  4. Durability

Write-ahead-log Design