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