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