package merkletree import ( "fmt" "math/big" ) // NodeType defines the type of node in the MT. type NodeType byte const ( // NodeTypeMiddle indicates the type of middle Node that has children. NodeTypeMiddle NodeType = 0 // NodeTypeLeaf indicates the type of a leaf Node that contains a claim. NodeTypeLeaf NodeType = 1 // NodeTypeEmpty indicates the type of an empty Node. NodeTypeEmpty NodeType = 2 // DBEntryTypeRoot indicates the type of a DB entry that indicates the current Root of a MerkleTree DBEntryTypeRoot NodeType = 3 ) // Node is the struct that represents a node in the MT. The node should not be // modified after creation because the cached key won't be updated. type Node struct { // Type is the type of node in the tree. Type NodeType // ChildL is the left child of a middle node. ChildL *Hash // ChildR is the right child of a middle node. ChildR *Hash // Entry is the data stored in a leaf node. Entry [2]*Hash // key is a cache used to avoid recalculating key key *Hash } // NewNodeLeaf creates a new leaf node. func NewNodeLeaf(k, v *Hash) *Node { return &Node{Type: NodeTypeLeaf, Entry: [2]*Hash{k, v}} } // NewNodeMiddle creates a new middle node. func NewNodeMiddle(childL *Hash, childR *Hash) *Node { return &Node{Type: NodeTypeMiddle, ChildL: childL, ChildR: childR} } // NewNodeEmpty creates a new empty node. func NewNodeEmpty() *Node { return &Node{Type: NodeTypeEmpty} } // NewNodeFromBytes creates a new node by parsing the input []byte. func NewNodeFromBytes(b []byte) (*Node, error) { if len(b) < 1 { return nil, ErrNodeDataBadSize } n := Node{Type: NodeType(b[0])} b = b[1:] switch n.Type { case NodeTypeMiddle: if len(b) != 2*ElemBytesLen { return nil, ErrNodeDataBadSize } n.ChildL, n.ChildR = &Hash{}, &Hash{} copy(n.ChildL[:], b[:ElemBytesLen]) copy(n.ChildR[:], b[ElemBytesLen:ElemBytesLen*2]) case NodeTypeLeaf: if len(b) != 2*ElemBytesLen { return nil, ErrNodeDataBadSize } n.Entry = [2]*Hash{&Hash{}, &Hash{}} copy(n.Entry[0][:], b[0:32]) copy(n.Entry[1][:], b[32:64]) case NodeTypeEmpty: break default: return nil, ErrInvalidNodeFound } return &n, nil } // LeafKey computes the key of a leaf node given the hIndex and hValue of the // entry of the leaf. func LeafKey(k, v *Hash) (*Hash, error) { return HashElemsKey(big.NewInt(1), k.BigInt(), v.BigInt()) } // Key computes the key of the node by hashing the content in a specific way // for each type of node. This key is used as the hash of the merklee tree for // each node. func (n *Node) Key() (*Hash, error) { if n.key == nil { // Cache the key to avoid repeated hash computations. // NOTE: We are not using the type to calculate the hash! switch n.Type { case NodeTypeMiddle: // H(ChildL || ChildR) var err error n.key, err = HashElems(n.ChildL.BigInt(), n.ChildR.BigInt()) if err != nil { return nil, err } case NodeTypeLeaf: var err error n.key, err = LeafKey(n.Entry[0], n.Entry[1]) if err != nil { return nil, err } case NodeTypeEmpty: // Zero n.key = &HashZero default: n.key = &HashZero } } return n.key, nil } // Value returns the value of the node. This is the content that is stored in the backend database. func (n *Node) Value() []byte { switch n.Type { case NodeTypeMiddle: // {Type || ChildL || ChildR} return append([]byte{byte(n.Type)}, append(n.ChildL[:], n.ChildR[:]...)...) case NodeTypeLeaf: // {Type || Data...} return append([]byte{byte(n.Type)}, append(n.Entry[0][:], n.Entry[1][:]...)...) case NodeTypeEmpty: // {} return []byte{} default: return []byte{} } } // String outputs a string representation of a node (different for each type). func (n *Node) String() string { switch n.Type { case NodeTypeMiddle: // {Type || ChildL || ChildR} return fmt.Sprintf("Middle L:%s R:%s", n.ChildL, n.ChildR) case NodeTypeLeaf: // {Type || Data...} return fmt.Sprintf("Leaf I:%v D:%v", n.Entry[0], n.Entry[1]) case NodeTypeEmpty: // {} return "Empty" default: return "Invalid Node" } }