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 }