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  }