Documentation ¶
Overview ¶
Package mpt implements MPT (Merkle-Patricia Trie).
An MPT stores key-value pairs and is a trie over 16-symbol alphabet. https://en.wikipedia.org/wiki/Trie A trie is a tree where values are stored in leafs and keys are paths from the root to the leaf node. An MPT consists of 4 types of nodes:
- Leaf node only contains a value.
- Extension node contains both a key and a value.
- Branch node contains 2 or more children.
- Hash node is a compressed node and only contains the actual node's hash. The actual node must be retrieved from the storage or over the network.
As an example here is a trie containing 3 pairs: - 0x1201 -> val1 - 0x1203 -> val2 - 0x1224 -> val3 - 0x12 -> val4
ExtensionNode(0x0102), Next _______________________| | BranchNode [0, 1, 2, ...], Last -> Leaf(val4) | | | ExtensionNode [0x04], Next -> Leaf(val3) | BranchNode [0, 1, 2, 3, ...], Last -> HashNode(nil) | | | Leaf(val2) | Leaf(val1)
There are 3 invariants that this implementation has: - Branch node cannot have <= 1 children - Extension node cannot have a zero-length key - Extension node cannot have another Extension node in its next field
Thanks to these restrictions, there is a single root hash for every set of key-value pairs irregardless of the order they were added/removed in. The actual trie structure can vary because of node -> HashNode compressing.
There is also one optimization which cost us almost nothing in terms of complexity but is quite beneficial: When we perform get/put/delete on a specific path, every Hash node which was retrieved from the storage is replaced by its uncompressed form, so that subsequent hits of this don't need to access the storage.
Index ¶
- Constants
- Variables
- func GetChildrenPaths(path []byte, node Node) map[util.Uint256][][]byte
- func IsActiveValue(v []byte) bool
- func VerifyProof(rh util.Uint256, key []byte, proofs [][]byte) ([]byte, bool)
- type BaseNode
- type BaseNodeIface
- type Batch
- type Billet
- type BranchNode
- func (b *BranchNode) Bytes() []byte
- func (b *BranchNode) Clone() Node
- func (b *BranchNode) DecodeBinary(r *io.BinReader)
- func (b *BranchNode) EncodeBinary(w *io.BinWriter)
- func (b *BranchNode) Hash() util.Uint256
- func (b *BranchNode) MarshalJSON() ([]byte, error)
- func (b *BranchNode) Size() int
- func (b *BranchNode) Type() NodeType
- func (b *BranchNode) UnmarshalJSON(data []byte) error
- type EmptyNode
- func (e EmptyNode) Bytes() []byte
- func (EmptyNode) Clone() Node
- func (e EmptyNode) DecodeBinary(*io.BinReader)
- func (e EmptyNode) EncodeBinary(*io.BinWriter)
- func (e EmptyNode) Hash() util.Uint256
- func (e EmptyNode) MarshalJSON() ([]byte, error)
- func (EmptyNode) Size() int
- func (e EmptyNode) Type() NodeType
- func (e EmptyNode) UnmarshalJSON(bytes []byte) error
- type ExtensionNode
- func (e *ExtensionNode) Bytes() []byte
- func (e *ExtensionNode) Clone() Node
- func (e *ExtensionNode) DecodeBinary(r *io.BinReader)
- func (e ExtensionNode) EncodeBinary(w *io.BinWriter)
- func (e *ExtensionNode) Hash() util.Uint256
- func (e *ExtensionNode) MarshalJSON() ([]byte, error)
- func (e *ExtensionNode) Size() int
- func (e ExtensionNode) Type() NodeType
- func (e *ExtensionNode) UnmarshalJSON(data []byte) error
- type HashNode
- func (h *HashNode) Bytes() []byte
- func (h *HashNode) Clone() Node
- func (h *HashNode) DecodeBinary(r *io.BinReader)
- func (h HashNode) EncodeBinary(w *io.BinWriter)
- func (h *HashNode) Hash() util.Uint256
- func (h *HashNode) MarshalJSON() ([]byte, error)
- func (h *HashNode) Size() int
- func (h *HashNode) Type() NodeType
- func (h *HashNode) UnmarshalJSON(data []byte) error
- type LeafNode
- func (n *LeafNode) Bytes() []byte
- func (n *LeafNode) Clone() Node
- func (n *LeafNode) DecodeBinary(r *io.BinReader)
- func (n LeafNode) EncodeBinary(w *io.BinWriter)
- func (n *LeafNode) Hash() util.Uint256
- func (n *LeafNode) MarshalJSON() ([]byte, error)
- func (n *LeafNode) Size() int
- func (n LeafNode) Type() NodeType
- func (n *LeafNode) UnmarshalJSON(data []byte) error
- type Node
- type NodeObject
- type NodeType
- type Trie
- func (t *Trie) Collapse(depth int)
- func (t *Trie) Delete(key []byte) error
- func (t *Trie) Find(prefix, from []byte, maxNum int) ([]storage.KeyValue, error)
- func (t *Trie) Flush(index uint32)
- func (t *Trie) Get(key []byte) ([]byte, error)
- func (t *Trie) GetProof(key []byte) ([][]byte, error)
- func (t *Trie) Put(key, value []byte) error
- func (t *Trie) PutBatch(b Batch) (int, error)
- func (t *Trie) StateRoot() util.Uint256
- type TrieMode
- type TrieStore
- func (m *TrieStore) Close() error
- func (m *TrieStore) Get(key []byte) ([]byte, error)
- func (m *TrieStore) PutChangeSet(puts map[string][]byte, stor map[string][]byte) error
- func (m *TrieStore) Seek(rng storage.SeekRange, f func(k, v []byte) bool)
- func (m *TrieStore) SeekGC(rng storage.SeekRange, keep func(k, v []byte) bool) error
Constants ¶
const ( // MaxKeyLength is the max length of the key to put in the trie // before transforming to nibbles. MaxKeyLength = maxPathLength / 2 )
const MaxValueLength = 3 + limits.MaxStorageValueLen + 1
MaxValueLength is the max length of a leaf node value.
Variables ¶
var ErrNotFound = errors.New("item not found")
ErrNotFound is returned when the requested trie item is missing.
var ( // ErrRestoreFailed is returned when replacing HashNode by its "unhashed" // candidate fails. ErrRestoreFailed = errors.New("failed to restore MPT node") )
Functions ¶
func GetChildrenPaths ¶ added in v0.97.3
GetChildrenPaths returns a set of paths to the node's children who are non-empty HashNodes based on the node's path.
func IsActiveValue ¶ added in v0.98.2
Types ¶
type BaseNode ¶
type BaseNode struct {
// contains filtered or unexported fields
}
BaseNode implements basic things every node needs like caching hash and serialized representation. It's a basic node building block intended to be included into all node types.
type BaseNodeIface ¶
BaseNodeIface abstracts away basic Node functions.
type Batch ¶ added in v0.93.0
type Batch struct {
// contains filtered or unexported fields
}
Batch is a batch of storage changes. It stores key-value pairs in a sorted state.
func MapToMPTBatch ¶ added in v0.98.2
MapToMPTBatch makes a Batch from an unordered set of storage changes.
type Billet ¶ added in v0.97.3
type Billet struct { TempStoragePrefix storage.KeyPrefix Store *storage.MemCachedStore // contains filtered or unexported fields }
Billet is a part of an MPT trie with missing hash nodes that need to be restored. Billet is based on the following assumptions:
- Refcount can only be incremented (we don't change the MPT structure during restore, thus don't need to decrease refcount).
- Each time a part of a Billet is completely restored, it is collapsed into HashNode.
- Any pair (node, path) must be restored only once. It's a duty of an MPT pool to manage MPT paths in order to provide this assumption.
func NewBillet ¶ added in v0.97.3
func NewBillet(rootHash util.Uint256, mode TrieMode, prefix storage.KeyPrefix, store *storage.MemCachedStore) *Billet
NewBillet returns a new billet for MPT trie restoring. It accepts a MemCachedStore to decouple storage errors from logic errors so that all storage errors are processed during `store.Persist()` at the caller. Another benefit is that every `Put` can be considered an atomic operation.
func (*Billet) GetFromStore ¶ added in v0.97.3
GetFromStore returns MPT node from the storage.
func (*Billet) RestoreHashNode ¶ added in v0.97.3
RestoreHashNode replaces HashNode located at the provided path by the specified Node and stores it. It also maintains the MPT as small as possible by collapsing those parts of the MPT that have been completely restored.
func (*Billet) Traverse ¶ added in v0.97.3
func (b *Billet) Traverse(process func(pathToNode []byte, node Node, nodeBytes []byte) bool, ignoreStorageErr bool) error
Traverse traverses MPT nodes (pre-order) starting from the billet root down to its children calling `process` for each serialised node until true is returned from `process` function. It also replaces all HashNodes to their "unhashed" counterparts until the stop condition is satisfied.
type BranchNode ¶
BranchNode represents an MPT's branch node.
func (*BranchNode) Bytes ¶
func (b *BranchNode) Bytes() []byte
Bytes implements the BaseNode interface.
func (*BranchNode) Clone ¶ added in v0.97.3
func (b *BranchNode) Clone() Node
Clone implements Node interface.
func (*BranchNode) DecodeBinary ¶
func (b *BranchNode) DecodeBinary(r *io.BinReader)
DecodeBinary implements io.Serializable.
func (*BranchNode) EncodeBinary ¶
func (b *BranchNode) EncodeBinary(w *io.BinWriter)
EncodeBinary implements io.Serializable.
func (*BranchNode) Hash ¶
func (b *BranchNode) Hash() util.Uint256
Hash implements the BaseNode interface.
func (*BranchNode) MarshalJSON ¶
func (b *BranchNode) MarshalJSON() ([]byte, error)
MarshalJSON implements the json.Marshaler.
func (*BranchNode) Size ¶ added in v0.97.2
func (b *BranchNode) Size() int
Size implements the Node interface.
func (*BranchNode) UnmarshalJSON ¶
func (b *BranchNode) UnmarshalJSON(data []byte) error
UnmarshalJSON implements the json.Unmarshaler.
type EmptyNode ¶ added in v0.97.2
type EmptyNode struct{}
EmptyNode represents an empty node.
func (EmptyNode) DecodeBinary ¶ added in v0.97.2
DecodeBinary implements the io.Serializable interface.
func (EmptyNode) EncodeBinary ¶ added in v0.97.2
EncodeBinary implements the io.Serializable interface.
func (EmptyNode) MarshalJSON ¶ added in v0.97.2
MarshalJSON implements Node interface.
func (EmptyNode) UnmarshalJSON ¶ added in v0.97.2
UnmarshalJSON implements Node interface.
type ExtensionNode ¶
type ExtensionNode struct { BaseNode // contains filtered or unexported fields }
ExtensionNode represents an MPT's extension node.
func NewExtensionNode ¶
func NewExtensionNode(key []byte, next Node) *ExtensionNode
NewExtensionNode returns a hash node with the specified key and the next node. Note: since it is a part of a Trie, the key must be mangled, i.e. must contain only bytes with high half = 0.
func (*ExtensionNode) Bytes ¶
func (e *ExtensionNode) Bytes() []byte
Bytes implements BaseNode interface.
func (*ExtensionNode) Clone ¶ added in v0.97.3
func (e *ExtensionNode) Clone() Node
Clone implements Node interface.
func (*ExtensionNode) DecodeBinary ¶
func (e *ExtensionNode) DecodeBinary(r *io.BinReader)
DecodeBinary implements io.Serializable.
func (ExtensionNode) EncodeBinary ¶
func (e ExtensionNode) EncodeBinary(w *io.BinWriter)
EncodeBinary implements io.Serializable.
func (*ExtensionNode) Hash ¶
func (e *ExtensionNode) Hash() util.Uint256
Hash implements BaseNode interface.
func (*ExtensionNode) MarshalJSON ¶
func (e *ExtensionNode) MarshalJSON() ([]byte, error)
MarshalJSON implements the json.Marshaler.
func (*ExtensionNode) Size ¶ added in v0.97.2
func (e *ExtensionNode) Size() int
Size implements Node interface.
func (*ExtensionNode) UnmarshalJSON ¶
func (e *ExtensionNode) UnmarshalJSON(data []byte) error
UnmarshalJSON implements the json.Unmarshaler.
type HashNode ¶
HashNode represents an MPT's hash node.
func NewHashNode ¶
NewHashNode returns a hash node with the specified hash.
func (*HashNode) DecodeBinary ¶
DecodeBinary implements io.Serializable.
func (HashNode) EncodeBinary ¶
EncodeBinary implements io.Serializable.
func (*HashNode) MarshalJSON ¶
MarshalJSON implements the json.Marshaler.
func (*HashNode) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler.
type LeafNode ¶
type LeafNode struct { BaseNode // contains filtered or unexported fields }
LeafNode represents an MPT's leaf node.
func NewLeafNode ¶
NewLeafNode returns a hash node with the specified value.
func (*LeafNode) DecodeBinary ¶
DecodeBinary implements io.Serializable.
func (LeafNode) EncodeBinary ¶
EncodeBinary implements io.Serializable.
func (*LeafNode) MarshalJSON ¶
MarshalJSON implements the json.Marshaler.
func (*LeafNode) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler.
type Node ¶
type Node interface { io.Serializable json.Marshaler json.Unmarshaler Size() int Clone() Node BaseNodeIface }
Node represents a common interface of all MPT nodes.
func DecodeNodeWithType ¶ added in v0.78.2
DecodeNodeWithType decodes the node together with its type.
type NodeObject ¶
type NodeObject struct {
Node
}
NodeObject represents a Node together with it's type. It is used for serialization/deserialization where type info is also expected.
func (*NodeObject) DecodeBinary ¶
func (n *NodeObject) DecodeBinary(r *io.BinReader)
DecodeBinary implements io.Serializable.
func (NodeObject) EncodeBinary ¶
func (n NodeObject) EncodeBinary(w *io.BinWriter)
EncodeBinary implements io.Serializable.
func (*NodeObject) UnmarshalJSON ¶
func (n *NodeObject) UnmarshalJSON(data []byte) error
UnmarshalJSON implements the json.Unmarshaler.
type Trie ¶
type Trie struct { Store *storage.MemCachedStore // contains filtered or unexported fields }
Trie is an MPT trie storing all key-value pairs.
func NewTrie ¶
func NewTrie(root Node, mode TrieMode, store *storage.MemCachedStore) *Trie
NewTrie returns a new MPT trie. It accepts a MemCachedStore to decouple storage errors from logic errors, so that all storage errors are processed during `store.Persist()` at the caller. Another benefit is that every `Put` can be considered an atomic operation.
func (*Trie) Collapse ¶
Collapse compresses all nodes at depth n to the hash nodes. Note: this function does not perform any kind of storage flushing so `Flush()` should be called explicitly before invoking function.
func (*Trie) Find ¶ added in v0.97.3
Find returns a list of storage key-value pairs whose key is prefixed by the specified prefix starting from the specified `prefix`+`from` path (not including the item at the specified `prefix`+`from` path if so). The `maxNum` number of elements is returned at max.
func (*Trie) Flush ¶
Flush puts every node (except Hash ones) in the trie to the storage. Because we care about block-level changes only, there is no need to put every new node to the storage. Normally, flush should be called with every StateRoot persist, i.e. after every block.
func (*Trie) GetProof ¶
GetProof returns a proof that the key belongs to t. The proof consists of serialized nodes occurring on the path from the root to the leaf of key.
func (*Trie) PutBatch ¶ added in v0.93.0
PutBatch puts a batch to a trie. It is not atomic (and probably cannot be without substantial slow-down) and returns the number of elements processed. If an error is returned, the trie may be in the inconsistent state in case of storage failures. This is due to the fact that we can remove multiple children from the branch node simultaneously and won't strip the resulting branch node. However, it is used mostly after block processing to update MPT, and error is not expected.
type TrieMode ¶ added in v0.98.2
type TrieMode byte
TrieMode is the storage mode of a trie, it affects the DB scheme.
const ( // ModeAll is used to store everything. ModeAll TrieMode = 0 // ModeLatest is used to only store the latest root. ModeLatest TrieMode = 0x01 // ModeGCFlag is a flag for GC. ModeGCFlag TrieMode = 0x02 // ModeGC is used to store a set of roots with GC possible, it combines // GCFlag and Latest (because it needs RC, but it has GC enabled). ModeGC TrieMode = 0x03 )
TrieMode is the storage mode of a trie.
type TrieStore ¶ added in v0.99.0
type TrieStore struct {
// contains filtered or unexported fields
}
TrieStore is an MPT-based storage implementation for storing and retrieving historic blockchain data. TrieStore is supposed to be used within transaction script invocations only, thus only contract storage related operations are supported. All storage-related operations are being performed using historical storage data retrieved from MPT state. TrieStore is read-only and does not support put-related operations, thus, it should always be wrapped into MemCachedStore for proper puts handling. TrieStore never changes the provided backend store.
func NewTrieStore ¶ added in v0.99.0
NewTrieStore returns a new ready to use MPT-backed storage.
func (*TrieStore) Get ¶ added in v0.99.0
Get implements the Store interface. It can return errors.ErrUnsupported for unsupported operations.
func (*TrieStore) PutChangeSet ¶ added in v0.99.0
PutChangeSet implements the Store interface. It's not supported, so it always returns errors.ErrUnsupported.