Documentation
¶
Overview ¶
Package binprefix implements the hash tree interface by following the merkle binary prefix tree algorithm.
https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-melara.pdf
The merkle tree is stored in-memory until it reaches a certain threshold of depth where it will write the nodes in disk. A leaf is always stored on disk because of the value it holds.
Interior (Root) / \ 0 / \ 1 / \ Interior Interior / \ / \ 0 / \ 1 0 / \ 1 / \ / \ DiskNode Interior Empty Interior / \ / \ --------------/-----\-----------/------\----------- Memory Depth / 0 \ 1 0 / \ 1 / \ / \ DiskNode DiskNode DiskNode DiskNode
The drawing above demonstrates an example of a tree. Here the memory depth is set at 3 which means that every node after this level will be a disk node. It will be loaded to its in-memory type when traversing the tree. The node at prefix 00 is an example of a leaf node which is a disk node even above the memory depth level.
Documentation Last Review: 08.10.2020
Index ¶
- Constants
- type DiskNode
- func (n *DiskNode) Clone() TreeNode
- func (n *DiskNode) Delete(key *big.Int, bucket kv.Bucket) (TreeNode, error)
- func (n *DiskNode) GetHash() []byte
- func (n *DiskNode) GetType() byte
- func (n *DiskNode) Insert(key *big.Int, value []byte, bucket kv.Bucket) (TreeNode, error)
- func (n *DiskNode) Prepare(nonce []byte, prefix *big.Int, bucket kv.Bucket, fac crypto.HashFactory) ([]byte, error)
- func (n *DiskNode) Search(key *big.Int, path *Path, bucket kv.Bucket) ([]byte, error)
- func (n *DiskNode) Serialize(ctx serde.Context) ([]byte, error)
- func (n *DiskNode) Visit(fn func(TreeNode) error) error
- type EmptyNode
- func (n *EmptyNode) Clone() TreeNode
- func (n *EmptyNode) Delete(key *big.Int, b kv.Bucket) (TreeNode, error)
- func (n *EmptyNode) GetDepth() uint16
- func (n *EmptyNode) GetHash() []byte
- func (n *EmptyNode) GetPrefix() *big.Int
- func (n *EmptyNode) GetType() byte
- func (n *EmptyNode) Insert(key *big.Int, value []byte, b kv.Bucket) (TreeNode, error)
- func (n *EmptyNode) Prepare(nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory) ([]byte, error)
- func (n *EmptyNode) Search(key *big.Int, path *Path, b kv.Bucket) ([]byte, error)
- func (n *EmptyNode) Serialize(ctx serde.Context) ([]byte, error)
- func (n *EmptyNode) Visit(fn func(node TreeNode) error) error
- type EmptyNodeJSON
- type InteriorNode
- func (n *InteriorNode) Clone() TreeNode
- func (n *InteriorNode) Delete(key *big.Int, b kv.Bucket) (TreeNode, error)
- func (n *InteriorNode) GetDepth() uint16
- func (n *InteriorNode) GetHash() []byte
- func (n *InteriorNode) GetPrefix() *big.Int
- func (n *InteriorNode) GetType() byte
- func (n *InteriorNode) Insert(key *big.Int, value []byte, b kv.Bucket) (TreeNode, error)
- func (n *InteriorNode) Prepare(nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory) ([]byte, error)
- func (n *InteriorNode) Search(key *big.Int, path *Path, b kv.Bucket) ([]byte, error)
- func (n *InteriorNode) Serialize(ctx serde.Context) ([]byte, error)
- func (n *InteriorNode) Visit(fn func(TreeNode) error) error
- type InteriorNodeJSON
- type LeafNode
- func (n *LeafNode) Clone() TreeNode
- func (n *LeafNode) Delete(key *big.Int, b kv.Bucket) (TreeNode, error)
- func (n *LeafNode) GetDepth() uint16
- func (n *LeafNode) GetHash() []byte
- func (n *LeafNode) GetKey() []byte
- func (n *LeafNode) GetType() byte
- func (n *LeafNode) GetValue() []byte
- func (n *LeafNode) Insert(key *big.Int, value []byte, b kv.Bucket) (TreeNode, error)
- func (n *LeafNode) Prepare(nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory) ([]byte, error)
- func (n *LeafNode) Search(key *big.Int, path *Path, b kv.Bucket) ([]byte, error)
- func (n *LeafNode) Serialize(ctx serde.Context) ([]byte, error)
- func (n *LeafNode) Visit(fn func(TreeNode) error) error
- type LeafNodeJSON
- type MerkleTree
- func (t *MerkleTree) Commit() error
- func (t *MerkleTree) Get(key []byte) ([]byte, error)
- func (t *MerkleTree) GetPath(key []byte) (hashtree.Path, error)
- func (t *MerkleTree) GetRoot() []byte
- func (t *MerkleTree) Load() error
- func (t *MerkleTree) Stage(fn func(store.Snapshot) error) (hashtree.StagingTree, error)
- func (t *MerkleTree) WithTx(tx store.Transaction) hashtree.StagingTree
- type NodeFactory
- type NodeJSON
- type NodeKey
- type Nonce
- type Path
- type Tree
- func (t *Tree) CalculateRoot(fac crypto.HashFactory, b kv.Bucket) error
- func (t *Tree) Clone() *Tree
- func (t *Tree) Delete(key []byte, b kv.Bucket) error
- func (t *Tree) FillFromBucket(bucket kv.Bucket) error
- func (t *Tree) Insert(key, value []byte, b kv.Bucket) error
- func (t *Tree) Len() int
- func (t *Tree) Persist(b kv.Bucket) error
- func (t *Tree) Search(key []byte, path *Path, b kv.Bucket) ([]byte, error)
- type TreeNode
Constants ¶
const ( // DepthLength is the length in bytes of the binary representation of the // depth. DepthLength = 2 // MaxDepth is the maximum depth the tree should reach. It is equivalent to // the maximum key length in bytes. MaxDepth = 32 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type DiskNode ¶
type DiskNode struct {
// contains filtered or unexported fields
}
DiskNode is an implementation of a tree node which is stored on the disk.
- implements binprefix.TreeNode
func NewDiskNode ¶
NewDiskNode creates a new disk node.
func (*DiskNode) Clone ¶
Clone implements binprefix.TreeNode. It clones the disk node but both the old and the new will read the same bucket.
func (*DiskNode) Delete ¶
Delete implements binprefix.TreeNode. It loads the node and deletes the key if it exists. The whole path to the key is loaded in-memory until the tree is persisted.
func (*DiskNode) GetHash ¶
GetHash implements binprefix.TreeNode. It returns the hash of the disk node if it is set, otherwise it returns nil.
func (*DiskNode) Insert ¶
Insert implements binprefix.TreeNode. It loads the node and inserts the key/value pair using in-memory operations. The whole path to the key will be loaded and kept in-memory until the tree is persisted.
func (*DiskNode) Prepare ¶
func (n *DiskNode) Prepare(nonce []byte, prefix *big.Int, bucket kv.Bucket, fac crypto.HashFactory) ([]byte, error)
Prepare implements binprefix.TreeNode. It loads the node and calculates its hash. The subtree might be loaded in-memory if deeper hashes have not been computed yet.
func (*DiskNode) Search ¶
Search implements binprefix.TreeNode. It loads the disk node and then search for the key.
type EmptyNode ¶
type EmptyNode struct {
// contains filtered or unexported fields
}
EmptyNode is leaf node with no value.
- implements binprefix.TreeNode
func NewEmptyNode ¶
NewEmptyNode creates a new empty node.
func NewEmptyNodeWithDigest ¶
NewEmptyNodeWithDigest creates a new empty node with its digest.
func (*EmptyNode) Clone ¶
Clone implements binprefix.TreeNode. It returns a deep copy of the empty node.
func (*EmptyNode) Delete ¶
Delete implements binprefix.TreeNode. It ignores the delete as an empty node already means the key is missing.
func (*EmptyNode) Insert ¶
Insert implements binprefix.TreeNode. It replaces the empty node by a leaf node that contains the key and the value.
func (*EmptyNode) Prepare ¶
func (n *EmptyNode) Prepare( nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory, ) ([]byte, error)
Prepare implements binprefix.TreeNode. It updates the hash of the node if not already set and returns the digest.
type EmptyNodeJSON ¶
EmptyNodeJSON is the JSON representation of an empty node.
type InteriorNode ¶
type InteriorNode struct {
// contains filtered or unexported fields
}
InteriorNode is a node with two children.
- implements binprefix.TreeNode
func NewInteriorNode ¶
func NewInteriorNode(depth uint16, prefix *big.Int) *InteriorNode
NewInteriorNode creates a new interior node with two empty nodes as children.
func NewInteriorNodeWithChildren ¶
func NewInteriorNodeWithChildren( depth uint16, prefix *big.Int, hash []byte, left, right TreeNode, ) *InteriorNode
NewInteriorNodeWithChildren creates a new interior node with the two given children.
func (*InteriorNode) Clone ¶
func (n *InteriorNode) Clone() TreeNode
Clone implements binprefix.TreeNode. It returns a deep copy of the interior node.
func (*InteriorNode) Delete ¶
Delete implements binprefix.TreeNode. It deletes the leaf node associated to the key if it exists, otherwise nothing will change.
func (*InteriorNode) GetDepth ¶
func (n *InteriorNode) GetDepth() uint16
GetDepth returns the depth of the node.
func (*InteriorNode) GetHash ¶
func (n *InteriorNode) GetHash() []byte
GetHash implements binprefix.TreeNode. It returns the hash of the node.
func (*InteriorNode) GetPrefix ¶
func (n *InteriorNode) GetPrefix() *big.Int
GetPrefix returns the prefix of the node.
func (*InteriorNode) GetType ¶
func (n *InteriorNode) GetType() byte
GetType implements binprefix.TreeNode. It returns the interior node type.
func (*InteriorNode) Insert ¶
Insert implements binprefix.TreeNode. It inserts the key/value pair to the right path.
func (*InteriorNode) Prepare ¶
func (n *InteriorNode) Prepare( nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory, ) ([]byte, error)
Prepare implements binprefix.TreeNode. It updates the hash of the node if not already set and returns the digest.
func (*InteriorNode) Search ¶
Search implements binprefix.TreeNode. It recursively search for the value in the correct child.
type InteriorNodeJSON ¶
InteriorNodeJSON is the JSON representation of an interior node.
type LeafNode ¶
type LeafNode struct {
// contains filtered or unexported fields
}
LeafNode is a leaf node with a key and a value.
- implements binprefix.TreeNode
func NewLeafNode ¶
NewLeafNode creates a new leaf node.
func NewLeafNodeWithDigest ¶
NewLeafNodeWithDigest creates a new leaf node with its digest.
func (*LeafNode) Delete ¶
Delete implements binprefix.TreeNode. It removes the leaf if the key matches.
func (*LeafNode) Insert ¶
Insert implements binprefix.TreeNode. It replaces the leaf node by an interior node that contains both the current pair and the new one to insert.
func (*LeafNode) Prepare ¶
func (n *LeafNode) Prepare( nonce []byte, prefix *big.Int, b kv.Bucket, fac crypto.HashFactory, ) ([]byte, error)
Prepare implements binprefix.TreeNode. It updates the hash of the node if not already set and returns the digest.
func (*LeafNode) Search ¶
Search implements binprefix.TreeNode. It returns the value if the key matches.
type LeafNodeJSON ¶
LeafNodeJSON is the JSON representation of a leaf node.
type MerkleTree ¶
MerkleTree is an implementation of a Merkle prefix binary tree. This particular implementation assumes the keys will have the same length so that only the longest unique prefix along the path can be a leaf node.
The leafs of the tree will be stored on the disk when committing the tree. Modifications on a staged tree are done in-memory.
- implements hashtree.Tree
func NewMerkleTree ¶
func NewMerkleTree(db kv.DB, nonce Nonce) *MerkleTree
NewMerkleTree creates a new Merkle tree-based storage.
func (*MerkleTree) Commit ¶
func (t *MerkleTree) Commit() error
Commit implements hashtree.StagingTree. It writes the leaf nodes to the disk and a trade-off of other nodes.
func (*MerkleTree) Get ¶
func (t *MerkleTree) Get(key []byte) ([]byte, error)
Get implements store.Readable. It returns the value associated with the key if it exists, otherwise it returns nil.
func (*MerkleTree) GetPath ¶
func (t *MerkleTree) GetPath(key []byte) (hashtree.Path, error)
GetPath implements hashtree.Tree. It returns a path to a given key that can be used to prove the inclusion or the absence of a key.
func (*MerkleTree) GetRoot ¶
func (t *MerkleTree) GetRoot() []byte
GetRoot implements hashtree.Tree. It returns the root hash of the tree.
func (*MerkleTree) Load ¶
func (t *MerkleTree) Load() error
Load tries to read the bucket and scan it for existing leafs and populate the tree with them.
func (*MerkleTree) Stage ¶
func (t *MerkleTree) Stage(fn func(store.Snapshot) error) (hashtree.StagingTree, error)
Stage implements hashtree.Tree. It executes the callback over a clone of the current tree and returns the clone with the root calculated.
func (*MerkleTree) WithTx ¶
func (t *MerkleTree) WithTx(tx store.Transaction) hashtree.StagingTree
WithTx implements hashtree.StagingTree. It returns a tree that shares the same underlying data, but it will perform operations on the database through the transaction.
type NodeFactory ¶
type NodeFactory struct{}
NodeFactory is the factory to deserialize tree nodes.
- implements serde.Factory
func (NodeFactory) Deserialize ¶
Deserialize implements serde.Factory. It populates the tree node associated to the data if appropriate, otherwise it returns an error.
type NodeJSON ¶
type NodeJSON struct { Leaf *LeafNodeJSON `json:",omitempty"` Interior *InteriorNodeJSON `json:",omitempty"` Empty *EmptyNodeJSON `json:",omitempty"` }
NodeJSON is the wrapper around the different types of a tree node.
type Path ¶
type Path struct {
// contains filtered or unexported fields
}
Path is a path from the root to a leaf, represented as a series of interior nodes hashes. The end of the path is either a leaf with a key holding a value, or an empty node.
- implements hashtree.Path
type Tree ¶
type Tree struct {
// contains filtered or unexported fields
}
Tree is an implementation of a Merkle binary prefix tree. Due to the structure of the tree, any prefix of a longer prefix is overridden which means that the key should have the same length.
Mutable operations on the tree don't update the hash root. It can be done after a batch of operations or a single one by using the CalculateRoot function.
func (*Tree) CalculateRoot ¶
CalculateRoot updates the hashes of the tree.
func (*Tree) FillFromBucket ¶
FillFromBucket scans the bucket for leafs to insert them in the tree. It will then persist the tree to restore the memory depth limit.
func (*Tree) Persist ¶
Persist visits the whole tree and stores the leaf node in the database and replaces the node with disk nodes. Depending on the parameter, it also stores intermediate nodes on the disk.
type TreeNode ¶
type TreeNode interface { serde.Message GetHash() []byte GetType() byte Search(key *big.Int, path *Path, bucket kv.Bucket) ([]byte, error) Insert(key *big.Int, value []byte, bucket kv.Bucket) (TreeNode, error) Delete(key *big.Int, bucket kv.Bucket) (TreeNode, error) Prepare(nonce []byte, prefix *big.Int, bucket kv.Bucket, fac crypto.HashFactory) ([]byte, error) Visit(func(node TreeNode) error) error Clone() TreeNode }
TreeNode is the interface for the different types of nodes of a Merkle tree.