github.com/project-88388/tendermint-v0.34.14-terra.2@v1.0.0/crypto/merkle/proof_value.go (about)

     1  package merkle
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/tendermint/tendermint/crypto/tmhash"
     8  	tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
     9  )
    10  
    11  const ProofOpValue = "simple:v"
    12  
    13  // ValueOp takes a key and a single value as argument and
    14  // produces the root hash.  The corresponding tree structure is
    15  // the SimpleMap tree.  SimpleMap takes a Hasher, and currently
    16  // Tendermint uses tmhash.  SimpleValueOp should support
    17  // the hash function as used in tmhash.  TODO support
    18  // additional hash functions here as options/args to this
    19  // operator.
    20  //
    21  // If the produced root hash matches the expected hash, the
    22  // proof is good.
    23  type ValueOp struct {
    24  	// Encoded in ProofOp.Key.
    25  	key []byte
    26  
    27  	// To encode in ProofOp.Data
    28  	Proof *Proof `json:"proof"`
    29  }
    30  
    31  var _ ProofOperator = ValueOp{}
    32  
    33  func NewValueOp(key []byte, proof *Proof) ValueOp {
    34  	return ValueOp{
    35  		key:   key,
    36  		Proof: proof,
    37  	}
    38  }
    39  
    40  func ValueOpDecoder(pop tmcrypto.ProofOp) (ProofOperator, error) {
    41  	if pop.Type != ProofOpValue {
    42  		return nil, fmt.Errorf("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpValue)
    43  	}
    44  	var pbop tmcrypto.ValueOp // a bit strange as we'll discard this, but it works.
    45  	err := pbop.Unmarshal(pop.Data)
    46  	if err != nil {
    47  		return nil, fmt.Errorf("decoding ProofOp.Data into ValueOp: %w", err)
    48  	}
    49  
    50  	sp, err := ProofFromProto(pbop.Proof)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	return NewValueOp(pop.Key, sp), nil
    55  }
    56  
    57  func (op ValueOp) ProofOp() tmcrypto.ProofOp {
    58  	pbval := tmcrypto.ValueOp{
    59  		Key:   op.key,
    60  		Proof: op.Proof.ToProto(),
    61  	}
    62  	bz, err := pbval.Marshal()
    63  	if err != nil {
    64  		panic(err)
    65  	}
    66  	return tmcrypto.ProofOp{
    67  		Type: ProofOpValue,
    68  		Key:  op.key,
    69  		Data: bz,
    70  	}
    71  }
    72  
    73  func (op ValueOp) String() string {
    74  	return fmt.Sprintf("ValueOp{%v}", op.GetKey())
    75  }
    76  
    77  func (op ValueOp) Run(args [][]byte) ([][]byte, error) {
    78  	if len(args) != 1 {
    79  		return nil, fmt.Errorf("expected 1 arg, got %v", len(args))
    80  	}
    81  	value := args[0]
    82  	hasher := tmhash.New()
    83  	hasher.Write(value)
    84  	vhash := hasher.Sum(nil)
    85  
    86  	bz := new(bytes.Buffer)
    87  	// Wrap <op.Key, vhash> to hash the KVPair.
    88  	encodeByteSlice(bz, op.key) // nolint: errcheck // does not error
    89  	encodeByteSlice(bz, vhash)  // nolint: errcheck // does not error
    90  	kvhash := leafHash(bz.Bytes())
    91  
    92  	if !bytes.Equal(kvhash, op.Proof.LeafHash) {
    93  		return nil, fmt.Errorf("leaf hash mismatch: want %X got %X", op.Proof.LeafHash, kvhash)
    94  	}
    95  
    96  	return [][]byte{
    97  		op.Proof.ComputeRootHash(),
    98  	}, nil
    99  }
   100  
   101  func (op ValueOp) GetKey() []byte {
   102  	return op.key
   103  }