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  }