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.

152 lines
3.8 KiB

  1. package rpc
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "fmt"
  6. "testing"
  7. ics23 "github.com/confio/ics23/go"
  8. "github.com/cosmos/iavl"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/mock"
  11. "github.com/stretchr/testify/require"
  12. dbm "github.com/tendermint/tm-db"
  13. abci "github.com/tendermint/tendermint/abci/types"
  14. "github.com/tendermint/tendermint/crypto/merkle"
  15. "github.com/tendermint/tendermint/libs/bytes"
  16. lcmock "github.com/tendermint/tendermint/light/rpc/mocks"
  17. tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
  18. rpcmock "github.com/tendermint/tendermint/rpc/client/mocks"
  19. ctypes "github.com/tendermint/tendermint/rpc/core/types"
  20. "github.com/tendermint/tendermint/types"
  21. )
  22. // TestABCIQuery tests ABCIQuery requests and verifies proofs. HAPPY PATH 😀
  23. func TestABCIQuery(t *testing.T) {
  24. tree, err := iavl.NewMutableTree(dbm.NewMemDB(), 100)
  25. require.NoError(t, err)
  26. var (
  27. key = []byte("foo")
  28. value = []byte("bar")
  29. )
  30. tree.Set(key, value)
  31. commitmentProof, err := tree.GetMembershipProof(key)
  32. require.NoError(t, err)
  33. op := &testOp{
  34. Spec: ics23.IavlSpec,
  35. Key: key,
  36. Proof: commitmentProof,
  37. }
  38. next := &rpcmock.Client{}
  39. next.On(
  40. "ABCIQueryWithOptions",
  41. context.Background(),
  42. mock.AnythingOfType("string"),
  43. bytes.HexBytes(key),
  44. mock.AnythingOfType("client.ABCIQueryOptions"),
  45. ).Return(&ctypes.ResultABCIQuery{
  46. Response: abci.ResponseQuery{
  47. Code: 0,
  48. Key: key,
  49. Value: value,
  50. Height: 1,
  51. ProofOps: &tmcrypto.ProofOps{
  52. Ops: []tmcrypto.ProofOp{op.ProofOp()},
  53. },
  54. },
  55. }, nil)
  56. lc := &lcmock.LightClient{}
  57. appHash, _ := hex.DecodeString("5EFD44055350B5CC34DBD26085347A9DBBE44EA192B9286A9FC107F40EA1FAC5")
  58. lc.On("VerifyLightBlockAtHeight", context.Background(), int64(2), mock.AnythingOfType("time.Time")).Return(
  59. &types.LightBlock{
  60. SignedHeader: &types.SignedHeader{
  61. Header: &types.Header{AppHash: appHash},
  62. },
  63. },
  64. nil,
  65. )
  66. c := NewClient(next, lc,
  67. KeyPathFn(func(_ string, key []byte) (merkle.KeyPath, error) {
  68. kp := merkle.KeyPath{}
  69. kp = kp.AppendKey(key, merkle.KeyEncodingURL)
  70. return kp, nil
  71. }))
  72. c.RegisterOpDecoder("ics23:iavl", testOpDecoder)
  73. res, err := c.ABCIQuery(context.Background(), "/store/accounts/key", key)
  74. require.NoError(t, err)
  75. assert.NotNil(t, res)
  76. }
  77. type testOp struct {
  78. Spec *ics23.ProofSpec
  79. Key []byte
  80. Proof *ics23.CommitmentProof
  81. }
  82. var _ merkle.ProofOperator = testOp{}
  83. func (op testOp) GetKey() []byte {
  84. return op.Key
  85. }
  86. func (op testOp) ProofOp() tmcrypto.ProofOp {
  87. bz, err := op.Proof.Marshal()
  88. if err != nil {
  89. panic(err.Error())
  90. }
  91. return tmcrypto.ProofOp{
  92. Type: "ics23:iavl",
  93. Key: op.Key,
  94. Data: bz,
  95. }
  96. }
  97. func (op testOp) Run(args [][]byte) ([][]byte, error) {
  98. // calculate root from proof
  99. root, err := op.Proof.Calculate()
  100. if err != nil {
  101. return nil, fmt.Errorf("could not calculate root for proof: %v", err)
  102. }
  103. // Only support an existence proof or nonexistence proof (batch proofs currently unsupported)
  104. switch len(args) {
  105. case 0:
  106. // Args are nil, so we verify the absence of the key.
  107. absent := ics23.VerifyNonMembership(op.Spec, root, op.Proof, op.Key)
  108. if !absent {
  109. return nil, fmt.Errorf("proof did not verify absence of key: %s", string(op.Key))
  110. }
  111. case 1:
  112. // Args is length 1, verify existence of key with value args[0]
  113. if !ics23.VerifyMembership(op.Spec, root, op.Proof, op.Key, args[0]) {
  114. return nil, fmt.Errorf("proof did not verify existence of key %s with given value %x", op.Key, args[0])
  115. }
  116. default:
  117. return nil, fmt.Errorf("args must be length 0 or 1, got: %d", len(args))
  118. }
  119. return [][]byte{root}, nil
  120. }
  121. func testOpDecoder(pop tmcrypto.ProofOp) (merkle.ProofOperator, error) {
  122. proof := &ics23.CommitmentProof{}
  123. err := proof.Unmarshal(pop.Data)
  124. if err != nil {
  125. return nil, err
  126. }
  127. op := testOp{
  128. Key: pop.Key,
  129. Spec: ics23.IavlSpec,
  130. Proof: proof,
  131. }
  132. return op, nil
  133. }