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.

91 lines
2.4 KiB

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