iavl

package module
v0.10.0-rc0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2018 License: Apache-2.0 Imports: 13 Imported by: 0

README

IAVL+ Tree

Note: Requires Go 1.8+

A versioned, snapshottable (immutable) AVL+ tree for persistent data.

The purpose of this data structure is to provide persistent storage for key-value pairs (say to store account balances) such that a deterministic merkle root hash can be computed. The tree is balanced using a variant of the AVL algorithm so all operations are O(log(n)).

Nodes of this tree are immutable and indexed by their hash. Thus any node serves as an immutable snapshot which lets us stage uncommitted transactions from the mempool cheaply, and we can instantly roll back to the last committed state to process transactions of a newly committed block (which may not be the same set of transactions as those from the mempool).

In an AVL tree, the heights of the two child subtrees of any node differ by at most one. Whenever this condition is violated upon an update, the tree is rebalanced by creating O(log(n)) new nodes that point to unmodified nodes of the old tree. In the original AVL algorithm, inner nodes can also hold key-value pairs. The AVL+ algorithm (note the plus) modifies the AVL algorithm to keep all values on leaf nodes, while only using branch-nodes to store keys. This simplifies the algorithm while keeping the merkle hash trail short.

In Ethereum, the analog is Patricia tries. There are tradeoffs. Keys do not need to be hashed prior to insertion in IAVL+ trees, so this provides faster iteration in the key space which may benefit some applications. The logic is simpler to implement, requiring only two types of nodes -- inner nodes and leaf nodes. On the other hand, while IAVL+ trees provide a deterministic merkle root hash, it depends on the order of transactions. In practice this shouldn't be a problem, since you can efficiently encode the tree structure when serializing the tree contents.

Documentation

Overview

Basic usage of VersionedTree.

import "github.com/tendermint/iavl"
import "github.com/tendermint/tmlibs/db"
...

tree := iavl.NewVersionedTree(db.NewMemDB(), 128)

tree.IsEmpty() // true

tree.Set([]byte("alice"), []byte("abc"))
tree.SaveVersion(1)

tree.Set([]byte("alice"), []byte("xyz"))
tree.Set([]byte("bob"), []byte("xyz"))
tree.SaveVersion(2)

tree.LatestVersion() // 2

tree.GetVersioned([]byte("alice"), 1) // "abc"
tree.GetVersioned([]byte("alice"), 2) // "xyz"

Proof of existence:

root := tree.Hash()
val, proof, err := tree.GetVersionedWithProof([]byte("bob"), 2) // "xyz", KeyProof, nil
proof.Verify([]byte("bob"), val, root) // nil

Proof of absence:

_, proof, err = tree.GetVersionedWithProof([]byte("tom"), 2) // nil, KeyProof, nil
proof.Verify([]byte("tom"), nil, root) // nil

Now we delete an old version:

tree.DeleteVersion(1)
tree.VersionExists(1) // false
tree.Get([]byte("alice")) // "xyz"
tree.GetVersioned([]byte("alice"), 1) // nil

Can't create a proof of absence for a version we no longer have:

_, proof, err = tree.GetVersionedWithProof([]byte("tom"), 1) // nil, nil, error

Index

Constants

View Source
const ProofOpIAVLAbsence = "iavl:a"
View Source
const ProofOpIAVLValue = "iavl:v"
View Source
const Version = "0.9.3"

Variables

View Source
var (
	// ErrInvalidProof is returned by Verify when a proof cannot be validated.
	ErrInvalidProof = fmt.Errorf("invalid proof")

	// ErrInvalidInputs is returned when the inputs passed to the function are invalid.
	ErrInvalidInputs = fmt.Errorf("invalid inputs")

	// ErrInvalidRoot is returned when the root passed in does not match the proof's.
	ErrInvalidRoot = fmt.Errorf("invalid root")
)
View Source
var ErrVersionDoesNotExist = fmt.Errorf("version does not exist")

Functions

func PrintTree added in v0.8.0

func PrintTree(tree *Tree)

func RegisterWire added in v0.8.0

func RegisterWire(cdc *amino.Codec)

func WriteDOTGraph

func WriteDOTGraph(w io.Writer, tree *Tree, paths []PathToLeaf)

Types

type IAVLAbsenceOp added in v0.11.1

type IAVLAbsenceOp struct {

	// Proof is nil for an empty tree.
	// The hash of an empty tree is nil.
	Proof *RangeProof `json:"proof"`
	// contains filtered or unexported fields
}

IAVLAbsenceOp takes a key as its only argument

If the produced root hash matches the expected hash, the proof is good.

func NewIAVLAbsenceOp added in v0.11.1

func NewIAVLAbsenceOp(key string, proof *RangeProof) IAVLAbsenceOp

func (IAVLAbsenceOp) GetKey added in v0.11.1

func (op IAVLAbsenceOp) GetKey() string

func (IAVLAbsenceOp) ProofOp added in v0.11.1

func (op IAVLAbsenceOp) ProofOp() merkle.ProofOp

func (IAVLAbsenceOp) Run added in v0.11.1

func (op IAVLAbsenceOp) Run(args [][]byte) ([][]byte, error)

func (IAVLAbsenceOp) String added in v0.11.1

func (op IAVLAbsenceOp) String() string

type IAVLValueOp added in v0.11.1

type IAVLValueOp struct {

	// To encode in ProofOp.Data
	Proof *RangeProof `json:"proof"`
	// contains filtered or unexported fields
}

IAVLValueOp takes a key and a single value as argument and produces the root hash.

If the produced root hash matches the expected hash, the proof is good.

func NewIAVLValueOp added in v0.11.1

func NewIAVLValueOp(key string, proof *RangeProof) IAVLValueOp

func (IAVLValueOp) GetKey added in v0.11.1

func (op IAVLValueOp) GetKey() string

func (IAVLValueOp) ProofOp added in v0.11.1

func (op IAVLValueOp) ProofOp() merkle.ProofOp

func (IAVLValueOp) Run added in v0.11.1

func (op IAVLValueOp) Run(args [][]byte) ([][]byte, error)

func (IAVLValueOp) String added in v0.11.1

func (op IAVLValueOp) String() string

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node represents a node in a Tree.

func MakeNode

func MakeNode(buf []byte) (node *Node, err cmn.Error)

MakeNode constructs an *Node from an encoded byte slice.

The new node doesn't have its hash saved or set. The caller must set it afterwards.

func NewNode

func NewNode(key []byte, value []byte, version int64) *Node

NewNode returns a new node from a key, value and version.

func (*Node) PathToLeaf added in v0.8.0

func (node *Node) PathToLeaf(t *Tree, key []byte) (PathToLeaf, *Node, error)

If the key does not exist, returns the path to the next leaf left of key (w/ path), except when key is less than the least item, in which case it returns a path to the least item.

func (*Node) String

func (node *Node) String() string

String returns a string representation of the node.

type PathToLeaf added in v0.8.0

type PathToLeaf []proofInnerNode

PathToLeaf represents an inner path to a leaf node. Note that the nodes are ordered such that the last one is closest to the root of the tree.

func (PathToLeaf) Index added in v0.9.1

func (pl PathToLeaf) Index() (idx int64)

returns -1 if invalid.

func (PathToLeaf) String added in v0.8.0

func (pl PathToLeaf) String() string

func (PathToLeaf) StringIndented added in v0.8.0

func (pl PathToLeaf) StringIndented(indent string) string

type RangeProof added in v0.8.0

type RangeProof struct {
	// You don't need the right path because
	// it can be derived from what we have.
	LeftPath   PathToLeaf      `json:"left_path"`
	InnerNodes []PathToLeaf    `json:"inner_nodes"`
	Leaves     []proofLeafNode `json:"leaves"`
	// contains filtered or unexported fields
}

func (*RangeProof) ComputeRootHash added in v0.9.1

func (proof *RangeProof) ComputeRootHash() []byte

ComputeRootHash computes the root hash with leaves. Returns nil if error or proof is nil. Does not verify the root hash.

func (*RangeProof) Keys added in v0.9.1

func (proof *RangeProof) Keys() (keys [][]byte)

Keys returns all the keys in the RangeProof. NOTE: The keys here may include more keys than provided by tree.GetRangeWithProof or VersionedTree.GetVersionedRangeWithProof. The keys returned there are only in the provided [startKey,endKey){limit} range. The keys returned here may include extra keys, such as: - the key before startKey if startKey is provided and doesn't exist; - the key after a queried key with tree.GetWithProof, when the key is absent.

func (*RangeProof) LeftIndex added in v0.9.1

func (proof *RangeProof) LeftIndex() int64

The index of the first leaf (of the whole tree). Returns -1 if the proof is nil.

func (*RangeProof) String added in v0.8.0

func (proof *RangeProof) String() string

String returns a string representation of the proof.

func (*RangeProof) StringIndented added in v0.8.0

func (proof *RangeProof) StringIndented(indent string) string

func (*RangeProof) Verify added in v0.8.0

func (proof *RangeProof) Verify(root []byte) error

Verify that proof is valid.

func (*RangeProof) VerifyAbsence added in v0.8.0

func (proof *RangeProof) VerifyAbsence(key []byte) error

Verify that proof is valid absence proof for key. Does not assume that the proof itself is valid. For that, use Verify(root).

func (*RangeProof) VerifyItem added in v0.8.0

func (proof *RangeProof) VerifyItem(key, value []byte) error

Also see LeftIndex(). Verify that a key has some value. Does not assume that the proof itself is valid, call Verify() first.

type Tree

type Tree struct {
	// contains filtered or unexported fields
}

Tree is a container for an immutable AVL+ Tree. Changes are performed by swapping the internal root with a new one, while the container is mutable. Note that this tree is not thread-safe.

func NewTree

func NewTree(db dbm.DB, cacheSize int) *Tree

NewTree creates both in-memory and persistent instances

func (*Tree) Get

func (t *Tree) Get(key []byte) (index int, value []byte)

Get returns the index and value of the specified key if it exists, or nil and the next index, if it doesn't.

func (*Tree) Get64 added in v0.6.0

func (t *Tree) Get64(key []byte) (index int64, value []byte)

func (*Tree) GetByIndex

func (t *Tree) GetByIndex(index int) (key []byte, value []byte)

GetByIndex gets the key and value at the specified index.

func (*Tree) GetByIndex64 added in v0.6.0

func (t *Tree) GetByIndex64(index int64) (key []byte, value []byte)

func (*Tree) GetRangeWithProof

func (t *Tree) GetRangeWithProof(startKey []byte, endKey []byte, limit int) (keys, values [][]byte, proof *RangeProof, err error)

GetRangeWithProof gets key/value pairs within the specified range and limit. If the tree is empty, proof/error are nil.

func (*Tree) GetWithProof

func (t *Tree) GetWithProof(key []byte) (value []byte, proof *RangeProof, err error)

GetWithProof gets the value under the key if it exists, or returns nil. A proof of existence or absence is returned alongside the value. If the tree is empty, proof/error are nil.

func (*Tree) Has

func (t *Tree) Has(key []byte) bool

Has returns whether or not a key exists.

func (*Tree) Hash

func (t *Tree) Hash() []byte

Hash returns the root hash.

func (*Tree) Height

func (t *Tree) Height() int

Height returns the height of the tree.

func (*Tree) Height8 added in v0.6.0

func (t *Tree) Height8() int8

func (*Tree) Iterate

func (t *Tree) Iterate(fn func(key []byte, value []byte) bool) (stopped bool)

Iterate iterates over all keys of the tree, in order.

func (*Tree) IterateRange

func (t *Tree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool)

IterateRange makes a callback for all nodes with key between start and end non-inclusive. If either are nil, then it is open on that side (nil, nil is the same as Iterate)

func (*Tree) IterateRangeInclusive

func (t *Tree) IterateRangeInclusive(start, end []byte, ascending bool, fn func(key, value []byte, version int64) bool) (stopped bool)

IterateRangeInclusive makes a callback for all nodes with key between start and end inclusive. If either are nil, then it is open on that side (nil, nil is the same as Iterate)

func (*Tree) Remove

func (t *Tree) Remove(key []byte) ([]byte, bool)

Remove tries to remove a key from the tree and if removed, returns its value, and 'true'.

func (*Tree) Set

func (t *Tree) Set(key []byte, value []byte) (updated bool)

Set a key. Nil values are not supported.

func (*Tree) Size

func (t *Tree) Size() int

Size returns the number of leaf nodes in the tree.

func (*Tree) Size64 added in v0.6.0

func (t *Tree) Size64() int64

func (*Tree) String

func (t *Tree) String() string

String returns a string representation of Tree.

func (*Tree) Version added in v0.6.0

func (t *Tree) Version() int

Version returns the version of the tree.

func (*Tree) Version64 added in v0.6.0

func (t *Tree) Version64() int64

type VersionedTree

type VersionedTree struct {
	// contains filtered or unexported fields
}

VersionedTree is a persistent tree which keeps track of versions.

func NewVersionedTree

func NewVersionedTree(db dbm.DB, cacheSize int) *VersionedTree

NewVersionedTree returns a new tree with the specified cache size and datastore.

func (*VersionedTree) DeleteVersion

func (tree *VersionedTree) DeleteVersion(version int64) error

DeleteVersion deletes a tree version from disk. The version can then no longer be accessed.

func (*VersionedTree) GetVersioned

func (tree *VersionedTree) GetVersioned(key []byte, version int64) (
	index int, value []byte,
)

GetVersioned gets the value at the specified key and version.

func (*VersionedTree) GetVersionedRangeWithProof

func (tree *VersionedTree) GetVersionedRangeWithProof(startKey, endKey []byte, limit int, version int64) (
	keys, values [][]byte, proof *RangeProof, err error)

GetVersionedRangeWithProof gets key/value pairs within the specified range and limit. If the tree is empty, proof/error are nil.

func (*VersionedTree) GetVersionedWithProof

func (tree *VersionedTree) GetVersionedWithProof(key []byte, version int64) ([]byte, *RangeProof, error)

GetVersionedWithProof gets the value under the key at the specified version if it exists, or returns nil. If the tree is empty, proof/error are nil.

func (*VersionedTree) Hash

func (tree *VersionedTree) Hash() []byte

Hash returns the hash of the latest saved version of the tree, as returned by SaveVersion. If no versions have been saved, Hash returns nil.

func (*VersionedTree) IsEmpty

func (tree *VersionedTree) IsEmpty() bool

IsEmpty returns whether or not the tree has any keys. Only trees that are not empty can be saved.

func (*VersionedTree) Load

func (tree *VersionedTree) Load() (int64, error)

Load the latest versioned tree from disk.

Returns the version number of the latest version found

func (*VersionedTree) LoadVersion added in v0.6.0

func (tree *VersionedTree) LoadVersion(targetVersion int64) (int64, error)

Load a versioned tree from disk.

If version is 0, the latest version is loaded.

Returns the version number of the latest version found

func (*VersionedTree) Remove

func (tree *VersionedTree) Remove(key []byte) ([]byte, bool)

Remove removes a key from the working tree.

func (*VersionedTree) Rollback added in v0.6.0

func (tree *VersionedTree) Rollback()

Rollback resets the working tree to the latest saved version, discarding any unsaved modifications.

func (VersionedTree) SaveAs added in v0.6.0

func (tree VersionedTree) SaveAs(version int64)

SaveAs saves the underlying Tree and assigns it a new version. Saves orphans too.

func (*VersionedTree) SaveVersion

func (tree *VersionedTree) SaveVersion() ([]byte, int64, error)

SaveVersion saves a new tree version to disk, based on the current state of the tree. Returns the hash and new version number.

func (*VersionedTree) Set

func (tree *VersionedTree) Set(key, val []byte) bool

Set sets a key in the working tree. Nil values are not supported.

func (*VersionedTree) String

func (tree *VersionedTree) String() string

String returns a string representation of the tree.

func (*VersionedTree) Tree

func (tree *VersionedTree) Tree() *Tree

Tree returns the current working tree.

func (*VersionedTree) VersionExists

func (tree *VersionedTree) VersionExists(version int64) bool

VersionExists returns whether or not a version exists.

Directories

Path Synopsis
Package sha256truncated provides a sha256 hash.Hash whose output is truncated to 20 bytes (160 bits).
Package sha256truncated provides a sha256 hash.Hash whose output is truncated to 20 bytes (160 bits).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL