You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
2.3 KiB

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