github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/proof_iavl_absence.go (about) 1 package iavl 2 3 import ( 4 "fmt" 5 6 "github.com/gnolang/gno/tm2/pkg/crypto/merkle" 7 "github.com/gnolang/gno/tm2/pkg/errors" 8 ) 9 10 const ProofOpIAVLAbsence = "iavl:a" 11 12 // IAVLAbsenceOp takes a key as its only argument 13 // 14 // If the produced root hash matches the expected hash, the proof 15 // is good. 16 type IAVLAbsenceOp struct { 17 // Encoded in ProofOp.Key. 18 key []byte 19 20 // To encode in ProofOp.Data. 21 // Proof is nil for an empty tree. 22 // The hash of an empty tree is nil. 23 Proof *RangeProof `json:"proof"` 24 } 25 26 var _ merkle.ProofOperator = IAVLAbsenceOp{} 27 28 func NewIAVLAbsenceOp(key []byte, proof *RangeProof) IAVLAbsenceOp { 29 return IAVLAbsenceOp{ 30 key: key, 31 Proof: proof, 32 } 33 } 34 35 func IAVLAbsenceOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) { 36 if pop.Type != ProofOpIAVLAbsence { 37 return nil, errors.New("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLAbsence) 38 } 39 var op IAVLAbsenceOp // a bit strange as we'll discard this, but it works. 40 err := cdc.UnmarshalSized(pop.Data, &op) 41 if err != nil { 42 return nil, errors.Wrap(err, "decoding ProofOp.Data into IAVLAbsenceOp") 43 } 44 return NewIAVLAbsenceOp(pop.Key, op.Proof), nil 45 } 46 47 func (op IAVLAbsenceOp) ProofOp() merkle.ProofOp { 48 bz := cdc.MustMarshalSized(op) 49 return merkle.ProofOp{ 50 Type: ProofOpIAVLAbsence, 51 Key: op.key, 52 Data: bz, 53 } 54 } 55 56 func (op IAVLAbsenceOp) String() string { 57 return fmt.Sprintf("IAVLAbsenceOp{%v}", op.GetKey()) 58 } 59 60 func (op IAVLAbsenceOp) Run(args [][]byte) ([][]byte, error) { 61 if len(args) != 0 { 62 return nil, errors.New("expected 0 args, got %v", len(args)) 63 } 64 // If the tree is nil, the proof is nil, and all keys are absent. 65 if op.Proof == nil { 66 return [][]byte{[]byte(nil)}, nil 67 } 68 // Compute the root hash and assume it is valid. 69 // The caller checks the ultimate root later. 70 root := op.Proof.ComputeRootHash() 71 err := op.Proof.Verify(root) 72 if err != nil { 73 return nil, errors.Wrap(err, "computing root hash") 74 } 75 // XXX What is the encoding for keys? 76 // We should decode the key depending on whether it's a string or hex, 77 // maybe based on quotes and 0x prefix? 78 err = op.Proof.VerifyAbsence(op.key) 79 if err != nil { 80 return nil, errors.Wrap(err, "verifying absence") 81 } 82 return [][]byte{root}, nil 83 } 84 85 func (op IAVLAbsenceOp) GetKey() []byte { 86 return op.key 87 }