github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/crypto/merkle/proof_simple_value.go (about)

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