2021-07-06 18:39:56 -07:00
|
|
|
package merkletrie
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2021-07-14 14:42:00 -04:00
|
|
|
"runtime"
|
2021-07-06 18:39:56 -07:00
|
|
|
"sort"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
2021-07-09 13:28:05 -04:00
|
|
|
"github.com/btcsuite/btcd/claimtrie/node"
|
|
|
|
|
2021-07-06 18:39:56 -07:00
|
|
|
"github.com/cockroachdb/pebble"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2021-07-09 13:28:05 -04:00
|
|
|
// EmptyTrieHash represents the Merkle Hash of an empty PersistentTrie.
|
2021-07-06 18:39:56 -07:00
|
|
|
// "0000000000000000000000000000000000000000000000000000000000000001"
|
|
|
|
EmptyTrieHash = &chainhash.Hash{1}
|
|
|
|
NoChildrenHash = &chainhash.Hash{2}
|
|
|
|
NoClaimsHash = &chainhash.Hash{3}
|
|
|
|
)
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
// ValueStore enables PersistentTrie to query node values from different implementations.
|
2021-07-06 18:39:56 -07:00
|
|
|
type ValueStore interface {
|
|
|
|
Hash(name []byte) *chainhash.Hash
|
2021-07-09 13:28:05 -04:00
|
|
|
IterateNames(predicate func(name []byte) bool)
|
2021-07-06 18:39:56 -07:00
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
// PersistentTrie implements a 256-way prefix tree.
|
|
|
|
type PersistentTrie struct {
|
2021-07-06 18:39:56 -07:00
|
|
|
store ValueStore
|
|
|
|
repo Repo
|
|
|
|
|
|
|
|
root *vertex
|
|
|
|
bufs *sync.Pool
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
// NewPersistentTrie returns a PersistentTrie.
|
|
|
|
func NewPersistentTrie(store ValueStore, repo Repo) *PersistentTrie {
|
2021-07-06 18:39:56 -07:00
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
tr := &PersistentTrie{
|
2021-07-06 18:39:56 -07:00
|
|
|
store: store,
|
|
|
|
repo: repo,
|
|
|
|
bufs: &sync.Pool{
|
|
|
|
New: func() interface{} {
|
|
|
|
return new(bytes.Buffer)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
root: newVertex(EmptyTrieHash),
|
|
|
|
}
|
|
|
|
|
|
|
|
return tr
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
// SetRoot drops all resolved nodes in the PersistentTrie, and set the Root with specified hash.
|
|
|
|
func (t *PersistentTrie) SetRoot(h *chainhash.Hash, names [][]byte) {
|
2021-07-06 18:39:56 -07:00
|
|
|
t.root = newVertex(h)
|
2021-07-14 14:42:00 -04:00
|
|
|
runtime.GC()
|
2021-07-06 18:39:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update updates the nodes along the path to the key.
|
|
|
|
// Each node is resolved or created with their Hash cleared.
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) Update(name []byte, restoreChildren bool) {
|
2021-07-06 18:39:56 -07:00
|
|
|
|
|
|
|
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.hasValue = true
|
|
|
|
n.merkleHash = nil
|
|
|
|
n.claimsHash = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// resolveChildLinks updates the links on n
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) resolveChildLinks(n *vertex, key []byte) {
|
2021-07-06 18:39:56 -07:00
|
|
|
|
|
|
|
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 err == pebble.ErrNotFound { // TODO: leaky abstraction
|
|
|
|
return
|
|
|
|
} else if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
defer closer.Close()
|
|
|
|
|
|
|
|
nb := nbuf(result)
|
|
|
|
n.hasValue, n.claimsHash = nb.hasValue()
|
|
|
|
for i := 0; i < nb.entries(); i++ {
|
|
|
|
p, h := nb.entry(i)
|
|
|
|
n.childLinks[p] = newVertex(h)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
// MerkleHash returns the Merkle Hash of the PersistentTrie.
|
2021-07-06 18:39:56 -07:00
|
|
|
// All nodes must have been resolved before calling this function.
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) MerkleHash() *chainhash.Hash {
|
2021-07-06 18:39:56 -07:00
|
|
|
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.
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) merkle(prefix []byte, v *vertex) *chainhash.Hash {
|
2021-07-06 18:39:56 -07:00
|
|
|
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.hasValue {
|
|
|
|
claimHash := v.claimsHash
|
|
|
|
if claimHash == nil {
|
|
|
|
claimHash = t.store.Hash(prefix)
|
|
|
|
v.claimsHash = claimHash
|
|
|
|
}
|
|
|
|
if claimHash != nil {
|
|
|
|
b.Write(claimHash[:])
|
|
|
|
} else {
|
|
|
|
v.hasValue = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) MerkleHashAllClaims() *chainhash.Hash {
|
2021-07-06 18:39:56 -07:00
|
|
|
buf := make([]byte, 0, 256)
|
|
|
|
if h := t.merkleAllClaims(buf, t.root); h == nil {
|
|
|
|
return EmptyTrieHash
|
|
|
|
}
|
|
|
|
return t.root.merkleHash
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) merkleAllClaims(prefix []byte, v *vertex) *chainhash.Hash {
|
2021-07-06 18:39:56 -07:00
|
|
|
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 v.hasValue {
|
2021-07-09 13:28:05 -04:00
|
|
|
if v.claimsHash == nil {
|
|
|
|
v.claimsHash = t.store.Hash(prefix)
|
|
|
|
v.hasValue = v.claimsHash != nil
|
2021-07-06 18:39:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
if len(childHashes) > 1 || v.claimsHash != nil { // yeah, about that 1 there -- old code used the condensed trie
|
2021-07-06 18:39:56 -07:00
|
|
|
left := NoChildrenHash
|
|
|
|
if len(childHashes) > 0 {
|
2021-07-09 13:28:05 -04:00
|
|
|
left = node.ComputeMerkleRoot(childHashes)
|
2021-07-06 18:39:56 -07:00
|
|
|
}
|
|
|
|
right := NoClaimsHash
|
2021-07-09 13:28:05 -04:00
|
|
|
if v.claimsHash != nil {
|
|
|
|
b.Write(v.claimsHash[:]) // for Has Value, nolint : errchk
|
|
|
|
right = v.claimsHash
|
2021-07-06 18:39:56 -07:00
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
h := node.HashMerkleBranches(left, right)
|
2021-07-06 18:39:56 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) Close() error {
|
2021-07-06 18:39:56 -07:00
|
|
|
return t.repo.Close()
|
|
|
|
}
|
|
|
|
|
2021-07-09 13:28:05 -04:00
|
|
|
func (t *PersistentTrie) Dump(s string, allClaims bool) {
|
2021-07-06 18:39:56 -07:00
|
|
|
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.hasValue)
|
|
|
|
|
|
|
|
for key, value := range v.childLinks {
|
|
|
|
fmt.Printf(" Child %s hash: %s\n", string(key), value.merkleHash.String())
|
|
|
|
}
|
|
|
|
}
|