func (t *MerkleTree) getChildPointer(n *node, isRight bool) (**node, error) { ix := coname.BitToIndex(isRight) if n.childIds[ix] != 0 && n.children[ix] == nil { // lazy-load the child. *don't* append to n.prefixBits! childIndex := append(append([]bool{}, n.prefixBits...), isRight) child, err := t.loadNode(n.childIds[ix], childIndex) if err != nil { return nil, err } n.children[ix] = child } return &n.children[ix], nil }
// Set updates the leaf value at the index (or inserts it if it did not exist). // In-memory: doesn't actually touch the disk yet. func (snapshot *NewSnapshot) Set(indexBytes []byte, value []byte) (err error) { if len(indexBytes) != coname.IndexBytes { return fmt.Errorf("Wrong index length") } if len(value) != coname.HashBytes { return fmt.Errorf("Wrong value length") } value = append([]byte(nil), value...) // Make a copy of value indexBits := coname.ToBits(coname.IndexBits, indexBytes) nodePointer := &snapshot.root position := 0 // Traverse down the tree, following either the left or right child depending on the next bit. for *nodePointer != nil && !(*nodePointer).isLeaf { nodePointer, err = snapshot.tree.getChildPointer(*nodePointer, indexBits[position]) if err != nil { return } position++ } if *nodePointer == nil { // We've hit an empty branch where this leaf belongs -- put it there. *nodePointer = &node{ diskNode: diskNode{ isLeaf: true, indexBytes: append([]byte{}, indexBytes...), // Make a copy of indexBytes value: value, }, prefixBits: indexBits[:position], } } else if bytes.Equal((*nodePointer).indexBytes, indexBytes) { // We have an existing leaf at this index; just replace the value (*nodePointer).value = value } else { // We have a different leaf with a matching prefix. We'll have to create new intermediate nodes. oldLeaf := *nodePointer oldLeafIndexBits := coname.ToBits(coname.IndexBits, oldLeaf.indexBytes) // Create a new intermediate node for each bit that has now become shared. for oldLeafIndexBits[position] == indexBits[position] { newNode := &node{ diskNode: diskNode{ isLeaf: false, }, prefixBits: indexBits[:position], } *nodePointer, nodePointer = newNode, &newNode.children[coname.BitToIndex(indexBits[position])] position++ } // Create a new node at which the tree now branches. splitNode := &node{ diskNode: diskNode{ isLeaf: false, }, prefixBits: indexBits[:position], } // Create the new leaf under the splitNode newLeaf := &node{ diskNode: diskNode{ isLeaf: true, indexBytes: append([]byte{}, indexBytes...), // Make a copy of the index value: value, }, prefixBits: indexBits[:position+1], } // Move the old leaf's index down oldLeaf.prefixBits = oldLeafIndexBits[:position+1] splitNode.children[coname.BitToIndex(indexBits[position])] = newLeaf splitNode.children[coname.BitToIndex(oldLeafIndexBits[position])] = oldLeaf *nodePointer = splitNode } return nil }
func (n *LookupTracingNode) ChildHash(rightChild bool) []byte { return n.node.childHashes[coname.BitToIndex(rightChild)][:] }