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 }