Learn about the state within the context of TimestampVM.
Blockchains can be defined as follows:
A linked-list where each list element consists of a block
Implementations of blockchains, while adhering to the functionality above from a white-box perspective, are defined much more like databases than regular linked lists themselves. In fact, this is what TimestampVM utilizes! By utilizing a general database, TimestampVM is able to store blocks (and thus, store its blockchain) while also being able to store additional data such as pending blocks.
Below is the definition of the State struct which is used to maintain the state of the TimestampVM:
State in this context acts like the database of TimestampVM. Within State, we are managing two different data structures:
db: a byte-based mapping which maps bytes to bytes. This is where finalized (that is, accepted blocks are stored)
verified_blocks: a hashmap which maps block numbers to their respective blocks. This is where all verified, but pending blocks are stored
While one could have guessed the functionalities of db and verified_blocks from their respective types subnet::rpc::database::Database + Send + Sync and HashMap<ids::Id, Block>, it is not immediately clear why we are wrapping these fields with Read/Write locks and Arc pointers. However, as we'll see soon when we examine the Block data structure, blocks need access to the VM state so they can add themselves to state. This is due to the SetPrefernce function of SnowmanVM interface, which states:
Set Preference
The VM implements the function SetPreference(blkID ids.ID) to allow the consensus engine to notify the VM which block is currently preferred to be accepted. The VM should use this information to set the head of its blockchain. Most importantly, when the consensus engine calls BuildBlock, the VM should be sure to build on top of the block that is the most recently set preference.
Note: SetPreference will always be called with a block that has no verified children.
Therefore, when building a Rust-based VM (or a VM in any supported language), the VM itself is only responsible for tracking the ID of the most recent finalized block; blocks bear the responsibility of storing themselves in VM state. As a result, we will need to wrap the db and verified_blocks fields with the following:
An Arc pointer so that whenever we clone the State structure, the cloned versions of db and verified_blocks are still pointing to the same data structures in memory. This allows for multiple Blocks to share the same db and verified_blocks
A read/write lock (that is, RwLock) so that we safely utilize concurrency in our VM