lbcd/claimtrie/merkletrie/merkletrie.go
Roy Lee 6828cf5e36 [lbry] claimtrie: import current snapshot
Sync to tip

Co-authored-by: Brannon King <countprimes@gmail.com>
2022-05-23 23:53:30 -07:00

256 lines
5.9 KiB
Go

package merkletrie
import (
"bytes"
"fmt"
"runtime"
"sort"
"sync"
"github.com/pkg/errors"
"github.com/lbryio/lbcd/chaincfg/chainhash"
"github.com/lbryio/lbcd/claimtrie/node"
)
var (
// EmptyTrieHash represents the Merkle Hash of an empty PersistentTrie.
// "0000000000000000000000000000000000000000000000000000000000000001"
EmptyTrieHash = &chainhash.Hash{1}
NoChildrenHash = &chainhash.Hash{2}
NoClaimsHash = &chainhash.Hash{3}
)
// PersistentTrie implements a 256-way prefix tree.
type PersistentTrie struct {
repo Repo
root *vertex
bufs *sync.Pool
}
// NewPersistentTrie returns a PersistentTrie.
func NewPersistentTrie(repo Repo) *PersistentTrie {
tr := &PersistentTrie{
repo: repo,
bufs: &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
},
root: newVertex(EmptyTrieHash),
}
return tr
}
// SetRoot drops all resolved nodes in the PersistentTrie, and set the Root with specified hash.
func (t *PersistentTrie) SetRoot(h *chainhash.Hash) error {
t.root = newVertex(h)
runtime.GC()
return nil
}
// Update updates the nodes along the path to the key.
// Each node is resolved or created with their Hash cleared.
func (t *PersistentTrie) Update(name []byte, hash *chainhash.Hash, restoreChildren bool) {
n := t.root
for i, ch := range name {
if restoreChildren && len(n.childLinks) == 0 {
t.resolveChildLinks(n, name[:i])
}
if n.childLinks[ch] == nil {
n.childLinks[ch] = newVertex(nil)
}
n.merkleHash = nil
n = n.childLinks[ch]
}
if restoreChildren && len(n.childLinks) == 0 {
t.resolveChildLinks(n, name)
}
n.merkleHash = nil
n.claimsHash = hash
}
// resolveChildLinks updates the links on n
func (t *PersistentTrie) resolveChildLinks(n *vertex, key []byte) {
if n.merkleHash == nil {
return
}
b := t.bufs.Get().(*bytes.Buffer)
defer t.bufs.Put(b)
b.Reset()
b.Write(key)
b.Write(n.merkleHash[:])
result, closer, err := t.repo.Get(b.Bytes())
if result == nil {
return
} else if err != nil {
panic(err)
}
defer closer.Close()
nb := nbuf(result)
_, n.claimsHash = nb.hasValue()
for i := 0; i < nb.entries(); i++ {
p, h := nb.entry(i)
n.childLinks[p] = newVertex(h)
}
}
// MerkleHash returns the Merkle Hash of the PersistentTrie.
// All nodes must have been resolved before calling this function.
func (t *PersistentTrie) MerkleHash() *chainhash.Hash {
buf := make([]byte, 0, 256)
if h := t.merkle(buf, t.root); h == nil {
return EmptyTrieHash
}
return t.root.merkleHash
}
// merkle recursively resolves the hashes of the node.
// All nodes must have been resolved before calling this function.
func (t *PersistentTrie) merkle(prefix []byte, v *vertex) *chainhash.Hash {
if v.merkleHash != nil {
return v.merkleHash
}
b := t.bufs.Get().(*bytes.Buffer)
defer t.bufs.Put(b)
b.Reset()
keys := keysInOrder(v)
for _, ch := range keys {
child := v.childLinks[ch]
if child == nil {
continue
}
p := append(prefix, ch)
h := t.merkle(p, child)
if h != nil {
b.WriteByte(ch) // nolint : errchk
b.Write(h[:]) // nolint : errchk
}
if h == nil || len(prefix) > 4 { // TODO: determine the right number here
delete(v.childLinks, ch) // keep the RAM down (they get recreated on Update)
}
}
if v.claimsHash != nil {
b.Write(v.claimsHash[:])
}
if b.Len() > 0 {
h := chainhash.DoubleHashH(b.Bytes())
v.merkleHash = &h
t.repo.Set(append(prefix, h[:]...), b.Bytes())
}
return v.merkleHash
}
func keysInOrder(v *vertex) []byte {
keys := make([]byte, 0, len(v.childLinks))
for key := range v.childLinks {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
return keys
}
func (t *PersistentTrie) MerkleHashAllClaims() *chainhash.Hash {
buf := make([]byte, 0, 256)
if h := t.merkleAllClaims(buf, t.root); h == nil {
return EmptyTrieHash
}
return t.root.merkleHash
}
func (t *PersistentTrie) merkleAllClaims(prefix []byte, v *vertex) *chainhash.Hash {
if v.merkleHash != nil {
return v.merkleHash
}
b := t.bufs.Get().(*bytes.Buffer)
defer t.bufs.Put(b)
b.Reset()
keys := keysInOrder(v)
childHashes := make([]*chainhash.Hash, 0, len(keys))
for _, ch := range keys {
n := v.childLinks[ch]
if n == nil {
continue
}
p := append(prefix, ch)
h := t.merkleAllClaims(p, n)
if h != nil {
childHashes = append(childHashes, h)
b.WriteByte(ch) // nolint : errchk
b.Write(h[:]) // nolint : errchk
}
if h == nil || len(prefix) > 4 { // TODO: determine the right number here
delete(v.childLinks, ch) // keep the RAM down (they get recreated on Update)
}
}
if len(childHashes) > 1 || v.claimsHash != nil { // yeah, about that 1 there -- old code used the condensed trie
left := NoChildrenHash
if len(childHashes) > 0 {
left = node.ComputeMerkleRoot(childHashes)
}
right := NoClaimsHash
if v.claimsHash != nil {
b.Write(v.claimsHash[:]) // for Has Value, nolint : errchk
right = v.claimsHash
}
h := node.HashMerkleBranches(left, right)
v.merkleHash = h
t.repo.Set(append(prefix, h[:]...), b.Bytes())
} else if len(childHashes) == 1 {
v.merkleHash = childHashes[0] // pass it up the tree
t.repo.Set(append(prefix, v.merkleHash[:]...), b.Bytes())
}
return v.merkleHash
}
func (t *PersistentTrie) Close() error {
return errors.WithStack(t.repo.Close())
}
func (t *PersistentTrie) Dump(s string) {
// TODO: this function is in the wrong spot; either it goes with its caller or it needs to be a generic iterator
// we don't want fmt used in here either way
v := t.root
for i := 0; i < len(s); i++ {
t.resolveChildLinks(v, []byte(s[:i]))
ch := s[i]
v = v.childLinks[ch]
if v == nil {
fmt.Printf("Missing child at %s\n", s[:i+1])
return
}
}
t.resolveChildLinks(v, []byte(s))
fmt.Printf("Node hash: %s, has value: %t\n", v.merkleHash.String(), v.claimsHash != nil)
for key, value := range v.childLinks {
fmt.Printf(" Child %s hash: %s\n", string(key), value.merkleHash.String())
}
}
func (t *PersistentTrie) Flush() error {
return t.repo.Flush()
}