github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/proof_iavl_value.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 ProofOpIAVLValue = "iavl:v"
    11  
    12  // IAVLValueOp takes a key and a single value as argument and
    13  // produces the root hash.
    14  //
    15  // If the produced root hash matches the expected hash, the proof
    16  // is good.
    17  type IAVLValueOp 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 = IAVLValueOp{}
    28  
    29  func NewIAVLValueOp(key []byte, proof *RangeProof) IAVLValueOp {
    30  	return IAVLValueOp{
    31  		key:   key,
    32  		Proof: proof,
    33  	}
    34  }
    35  
    36  func IAVLValueOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) {
    37  	if pop.Type != ProofOpIAVLValue {
    38  		return nil, errors.New("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpIAVLValue)
    39  	}
    40  	var op IAVLValueOp // a bit strange as we'll discard this, but it works.
    41  	err := cdc.UnmarshalSized(pop.Data, &op)
    42  	if err != nil {
    43  		return nil, errors.Wrap(err, "decoding ProofOp.Data into IAVLValueOp")
    44  	}
    45  	return NewIAVLValueOp(pop.Key, op.Proof), nil
    46  }
    47  
    48  func (op IAVLValueOp) ProofOp() merkle.ProofOp {
    49  	bz := cdc.MustMarshalSized(op)
    50  	return merkle.ProofOp{
    51  		Type: ProofOpIAVLValue,
    52  		Key:  op.key,
    53  		Data: bz,
    54  	}
    55  }
    56  
    57  func (op IAVLValueOp) String() string {
    58  	return fmt.Sprintf("IAVLValueOp{%v}", op.GetKey())
    59  }
    60  
    61  func (op IAVLValueOp) Run(args [][]byte) ([][]byte, error) {
    62  	if len(args) != 1 {
    63  		return nil, errors.New("Value size is not 1")
    64  	}
    65  	value := args[0]
    66  
    67  	// Compute the root hash and assume it is valid.
    68  	// The caller checks the ultimate root later.
    69  	root := op.Proof.ComputeRootHash()
    70  	err := op.Proof.Verify(root)
    71  	if err != nil {
    72  		return nil, errors.Wrap(err, "computing root hash")
    73  	}
    74  	// XXX What is the encoding for keys?
    75  	// We should decode the key depending on whether it's a string or hex,
    76  	// maybe based on quotes and 0x prefix?
    77  	err = op.Proof.VerifyItem(op.key, value)
    78  	if err != nil {
    79  		return nil, errors.Wrap(err, "verifying value")
    80  	}
    81  	return [][]byte{root}, nil
    82  }
    83  
    84  func (op IAVLValueOp) GetKey() []byte {
    85  	return op.key
    86  }