Example #1
0
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
}
Example #2
0
// 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
}
Example #3
0
func (n *LookupTracingNode) ChildHash(rightChild bool) []byte {
	return n.node.childHashes[coname.BitToIndex(rightChild)][:]
}