multistoreproof.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package lightclient
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/tendermint/iavl"
  6. "github.com/tendermint/tendermint/crypto/merkle"
  7. cmn "github.com/tendermint/tendermint/libs/common"
  8. )
  9. // MultiStoreProof defines a collection of store proofs in a multi-store
  10. type MultiStoreProof struct {
  11. StoreInfos []StoreInfo
  12. }
  13. func NewMultiStoreProof(storeInfos []StoreInfo) *MultiStoreProof {
  14. return &MultiStoreProof{StoreInfos: storeInfos}
  15. }
  16. // ComputeRootHash returns the root hash for a given multi-store proof.
  17. func (proof *MultiStoreProof) ComputeRootHash() []byte {
  18. ci := CommitInfo{
  19. Version: -1, // TODO: Not needed; improve code.
  20. StoreInfos: proof.StoreInfos,
  21. }
  22. return ci.Hash()
  23. }
  24. // RequireProof return whether proof is require for the subpath
  25. func RequireProof(subpath string) bool {
  26. // XXX: create a better convention.
  27. // Currently, only when query subpath is "/store" or "/key", will proof be included in response.
  28. // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212
  29. if subpath == "/store" || subpath == "/key" {
  30. return true
  31. }
  32. return false
  33. }
  34. //-----------------------------------------------------------------------------
  35. var _ merkle.ProofOperator = MultiStoreProofOp{}
  36. // the multi-store proof operation constant value
  37. const ProofOpMultiStore = "multistore"
  38. // TODO: document
  39. type MultiStoreProofOp struct {
  40. // Encoded in ProofOp.Key
  41. key []byte
  42. // To encode in ProofOp.Data.
  43. Proof *MultiStoreProof `json:"proof"`
  44. }
  45. func NewMultiStoreProofOp(key []byte, proof *MultiStoreProof) MultiStoreProofOp {
  46. return MultiStoreProofOp{
  47. key: key,
  48. Proof: proof,
  49. }
  50. }
  51. // MultiStoreProofOpDecoder returns a multi-store merkle proof operator from a
  52. // given proof operation.
  53. func MultiStoreProofOpDecoder(pop merkle.ProofOp) (merkle.ProofOperator, error) {
  54. if pop.Type != ProofOpMultiStore {
  55. return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpMultiStore)
  56. }
  57. // XXX: a bit strange as we'll discard this, but it works
  58. var op MultiStoreProofOp
  59. err := Cdc.UnmarshalBinaryLengthPrefixed(pop.Data, &op)
  60. if err != nil {
  61. return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into MultiStoreProofOp")
  62. }
  63. return NewMultiStoreProofOp(pop.Key, op.Proof), nil
  64. }
  65. // ProofOp return a merkle proof operation from a given multi-store proof
  66. // operation.
  67. func (op MultiStoreProofOp) ProofOp() merkle.ProofOp {
  68. bz := Cdc.MustMarshalBinaryLengthPrefixed(op)
  69. return merkle.ProofOp{
  70. Type: ProofOpMultiStore,
  71. Key: op.key,
  72. Data: bz,
  73. }
  74. }
  75. // String implements the Stringer interface for a mult-store proof operation.
  76. func (op MultiStoreProofOp) String() string {
  77. return fmt.Sprintf("MultiStoreProofOp{%v}", op.GetKey())
  78. }
  79. // GetKey returns the key for a multi-store proof operation.
  80. func (op MultiStoreProofOp) GetKey() []byte {
  81. return op.key
  82. }
  83. // Run executes a multi-store proof operation for a given value. It returns
  84. // the root hash if the value matches all the store's commitID's hash or an
  85. // error otherwise.
  86. func (op MultiStoreProofOp) Run(args [][]byte) ([][]byte, error) {
  87. if len(args) != 1 {
  88. return nil, cmn.NewError("Value size is not 1")
  89. }
  90. value := args[0]
  91. root := op.Proof.ComputeRootHash()
  92. for _, si := range op.Proof.StoreInfos {
  93. if si.Name == string(op.key) {
  94. if bytes.Equal(value, si.Core.CommitID.Hash) {
  95. return [][]byte{root}, nil
  96. }
  97. return nil, cmn.NewError("hash mismatch for substore %v: %X vs %X", si.Name, si.Core.CommitID.Hash, value)
  98. }
  99. }
  100. return nil, cmn.NewError("key %v not found in multistore proof", op.key)
  101. }
  102. //-----------------------------------------------------------------------------
  103. // XXX: This should be managed by the rootMultiStore which may want to register
  104. // more proof ops?
  105. func DefaultProofRuntime() (prt *merkle.ProofRuntime) {
  106. prt = merkle.NewProofRuntime()
  107. prt.RegisterOpDecoder(merkle.ProofOpSimpleValue, merkle.SimpleValueOpDecoder)
  108. prt.RegisterOpDecoder(iavl.ProofOpIAVLValue, iavl.IAVLValueOpDecoder)
  109. prt.RegisterOpDecoder(iavl.ProofOpIAVLAbsence, iavl.IAVLAbsenceOpDecoder)
  110. prt.RegisterOpDecoder(ProofOpMultiStore, MultiStoreProofOpDecoder)
  111. return
  112. }