Documentation ¶
Overview ¶
Package mpt implements MPT (Merkle-Patricia Tree).
MPT stores key-value pairs and is a trie over 16-symbol alphabet. https://en.wikipedia.org/wiki/Trie Trie is a tree where values are stored in leafs and keys are paths from root to the leaf node. MPT consists of 4 type of nodes:
- Leaf node contains only value.
- Extension node contains both key and value.
- Branch node contains 2 or more children.
- Hash node is a compressed node and contains only actual node's hash. The actual node must be retrieved from 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 zero-length key - Extension node cannot have another Extension node in it's next field
Thank to these restrictions, there is a single root hash for every set of key-value pairs irregardless of the order they were added/removed with. 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 very beneficial: When we perform get/put/delete on a speficic path, every Hash node which was retreived from storage is replaced by its uncompressed form, so that subsequent hits of this not don't use storage.
Index ¶
- Constants
- Variables
- func ToNeoStorageKey(key []byte) []byte
- func ToNeoStorageValue(si *state.StorageItem) []byte
- func VerifyProof(rh util.Uint256, key []byte, proofs [][]byte) ([]byte, bool)
- type BaseNode
- type BaseNodeIface
- type BranchNode
- func (b *BranchNode) Bytes() []byte
- 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) Type() NodeType
- func (b *BranchNode) UnmarshalJSON(data []byte) error
- type ExtensionNode
- func (e *ExtensionNode) Bytes() []byte
- 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) Type() NodeType
- func (e *ExtensionNode) UnmarshalJSON(data []byte) error
- type HashNode
- func (h *HashNode) Bytes() []byte
- func (h *HashNode) DecodeBinary(r *io.BinReader)
- func (h HashNode) EncodeBinary(w *io.BinWriter)
- func (h *HashNode) Hash() util.Uint256
- func (h *HashNode) IsEmpty() bool
- func (h *HashNode) MarshalJSON() ([]byte, error)
- func (h *HashNode) Type() NodeType
- func (h *HashNode) UnmarshalJSON(data []byte) error
- type LeafNode
- func (n *LeafNode) Bytes() []byte
- 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) Type() NodeType
- func (n *LeafNode) UnmarshalJSON(data []byte) error
- type Node
- type NodeObject
- type NodeType
- type Trie
Constants ¶
const MaxKeyLength = 1125
MaxKeyLength is the max length of the extension node key.
const MaxValueLength = 1024 * 1024
MaxValueLength is a max length of a leaf node value.
Variables ¶
var ErrNotFound = errors.New("item not found")
ErrNotFound is returned when requested trie item is missing.
Functions ¶
func ToNeoStorageKey ¶
ToNeoStorageKey converts storage key to C# neo node's format. Key is expected to be at least 20 bytes in length. our format: script hash in BE + key neo format: script hash in LE + key with 0 between every 16 bytes, padded to len 16.
func ToNeoStorageValue ¶
func ToNeoStorageValue(si *state.StorageItem) []byte
ToNeoStorageValue serializes si to a C# neo node's format. It has additional version (0x00) byte at the beginning.
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.
func (*BaseNode) SetFlushed ¶
func (b *BaseNode) SetFlushed()
SetFlushed sets 'flushed' flag to true for this node.
type BaseNodeIface ¶
type BaseNodeIface interface { Hash() util.Uint256 Type() NodeType Bytes() []byte IsFlushed() bool SetFlushed() }
BaseNodeIface abstracts away basic Node functions.
type BranchNode ¶
BranchNode represents MPT's branch node.
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 BaseNode interface.
func (*BranchNode) MarshalJSON ¶
func (b *BranchNode) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*BranchNode) UnmarshalJSON ¶
func (b *BranchNode) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type ExtensionNode ¶
type ExtensionNode struct { BaseNode // contains filtered or unexported fields }
ExtensionNode represents MPT's extension node.
func NewExtensionNode ¶
func NewExtensionNode(key []byte, next Node) *ExtensionNode
NewExtensionNode returns hash node with the specified key and next node. Note: because it is a part of Trie, 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) 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 json.Marshaler.
func (*ExtensionNode) UnmarshalJSON ¶
func (e *ExtensionNode) UnmarshalJSON(data []byte) error
UnmarshalJSON implements json.Unmarshaler.
type HashNode ¶
type HashNode struct {
BaseNode
}
HashNode represents MPT's hash node.
func NewHashNode ¶
NewHashNode returns 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 json.Marshaler.
func (*HashNode) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type LeafNode ¶
type LeafNode struct { BaseNode // contains filtered or unexported fields }
LeafNode represents MPT's leaf node.
func NewLeafNode ¶
NewLeafNode returns 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 json.Marshaler.
func (*LeafNode) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler.
type Node ¶
type Node interface { io.Serializable json.Marshaler json.Unmarshaler BaseNodeIface }
Node represents common interface of all MPT nodes.
type NodeObject ¶
type NodeObject struct {
Node
}
NodeObject represents 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 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, store *storage.MemCachedStore) *Trie
NewTrie returns 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. This also has the benefit, 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) Flush ¶
func (t *Trie) Flush()
Flush puts every node in the trie except Hash ones to the storage. Because we care only about block-level changes, there is no need to put every new node to storage. Normally, flush should be called with every StateRoot persist, i.e. after every block.