Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

proof.gno

2.02 Kb · 96 lines
 1package mpt
 2
 3import (
 4	"bytes"
 5	"encoding/hex"
 6
 7	"gno.land/p/nt/ufmt/v0"
 8)
 9
10// missingNodeError reports which proof node index/hash verifyProof needed
11// but didn't find, mirroring VerifyProof's "proof node %d (hash %064x)
12// missing" message. It satisfies errors.Is(err, ErrMissingNode) via Is, since
13// ufmt.Errorf has no %w wrapping to attach the sentinel directly.
14type missingNodeError struct {
15	index int
16	hash  [32]byte
17}
18
19func (e *missingNodeError) Error() string {
20	return ufmt.Sprintf("mpt: proof node %d (hash %s) missing", e.index, hex.EncodeToString(e.hash[:]))
21}
22
23func (e *missingNodeError) Is(target error) bool {
24	return target == ErrMissingNode
25}
26
27// verifyProof mirrors VerifyProof (proofDb pre-indexed by hash, matching how
28// go-ethereum's caller populates it via Prove).
29// Reference:
30// https://github.com/ethereum/go-ethereum/blob/v1.10.26/trie/proof.go#L111-L135
31func verifyProof(rootHash [32]byte, key []byte, proofDb map[[32]byte][]byte) ([]byte, error) {
32	key = keybytesToHex(key)
33	wantHash := rootHash
34
35	for i := 0; ; i++ {
36		buf, ok := proofDb[wantHash]
37		if !ok {
38			return nil, &missingNodeError{index: i, hash: wantHash}
39		}
40
41		n, err := decodeNode(buf)
42		if err != nil {
43			return nil, err
44		}
45
46		keyrest, cld := get(n, key, true)
47
48		switch c := cld.(type) {
49		case nil:
50			return nil, nil
51		case hashNode:
52			key = keyrest
53			copy(wantHash[:], c)
54		case valueNode:
55			return c, nil
56		}
57	}
58}
59
60// get mirrors get.
61// Reference:
62// https://github.com/ethereum/go-ethereum/blob/v1.10.26/trie/proof.go#L580-L608
63func get(tn node, key []byte, skipResolved bool) ([]byte, node) {
64	for {
65		switch n := tn.(type) {
66		case *shortNode:
67			if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
68				return nil, nil
69			}
70
71			tn = n.Val
72			key = key[len(n.Key):]
73
74			if !skipResolved {
75				return key, tn
76			}
77
78		case *fullNode:
79			tn = n.Children[key[0]]
80			key = key[1:]
81
82			if !skipResolved {
83				return key, tn
84			}
85
86		case hashNode:
87			return key, n
88
89		case nil:
90			return key, nil
91
92		case valueNode:
93			return nil, n
94		}
95	}
96}