github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/core/mpt/proof.go (about) 1 package mpt 2 3 import ( 4 "bytes" 5 "errors" 6 7 "github.com/nspcc-dev/neo-go/pkg/core/storage" 8 "github.com/nspcc-dev/neo-go/pkg/crypto/hash" 9 "github.com/nspcc-dev/neo-go/pkg/util" 10 ) 11 12 // GetProof returns a proof that the key belongs to t. 13 // The proof consists of serialized nodes occurring on the path from the root to the leaf of key. 14 func (t *Trie) GetProof(key []byte) ([][]byte, error) { 15 var proof [][]byte 16 if len(key) > MaxKeyLength { 17 return nil, errors.New("key is too big") 18 } 19 path := toNibbles(key) 20 r, err := t.getProof(t.root, path, &proof) 21 if err != nil { 22 return proof, err 23 } 24 t.root = r 25 return proof, nil 26 } 27 28 func (t *Trie) getProof(curr Node, path []byte, proofs *[][]byte) (Node, error) { 29 switch n := curr.(type) { 30 case *LeafNode: 31 if len(path) == 0 { 32 *proofs = append(*proofs, bytes.Clone(n.Bytes())) 33 return n, nil 34 } 35 case *BranchNode: 36 *proofs = append(*proofs, bytes.Clone(n.Bytes())) 37 i, path := splitPath(path) 38 r, err := t.getProof(n.Children[i], path, proofs) 39 if err != nil { 40 return nil, err 41 } 42 n.Children[i] = r 43 return n, nil 44 case *ExtensionNode: 45 if bytes.HasPrefix(path, n.key) { 46 *proofs = append(*proofs, bytes.Clone(n.Bytes())) 47 r, err := t.getProof(n.next, path[len(n.key):], proofs) 48 if err != nil { 49 return nil, err 50 } 51 n.next = r 52 return n, nil 53 } 54 case *HashNode: 55 r, err := t.getFromStore(n.Hash()) 56 if err != nil { 57 return nil, err 58 } 59 return t.getProof(r, path, proofs) 60 } 61 return nil, ErrNotFound 62 } 63 64 // VerifyProof verifies that path indeed belongs to a MPT with the specified root hash. 65 // It also returns the value for the key. 66 func VerifyProof(rh util.Uint256, key []byte, proofs [][]byte) ([]byte, bool) { 67 path := toNibbles(key) 68 tr := NewTrie(NewHashNode(rh), ModeAll, storage.NewMemCachedStore(storage.NewMemoryStore())) 69 for i := range proofs { 70 h := hash.DoubleSha256(proofs[i]) 71 tr.Store.Put(makeStorageKey(h), proofs[i]) 72 } 73 _, leaf, _, err := tr.getWithPath(tr.root, path, true) 74 if err != nil { 75 return nil, false 76 } 77 return bytes.Clone(leaf.(*LeafNode).value), true 78 }