mirror of
https://github.com/tendermint/tendermint.git
synced 2026-08-28 20:06:24 +00:00
Merge branch 'abci_proof' into develop
This commit is contained in:
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/tendermint/abci/server"
|
||||
@@ -59,8 +58,10 @@ func (app *ChainAwareApplication) Commit() types.Result {
|
||||
return types.NewResultOK([]byte("nil"), "")
|
||||
}
|
||||
|
||||
func (app *ChainAwareApplication) Query(query []byte) types.Result {
|
||||
return types.NewResultOK([]byte(fmt.Sprintf("%d,%d", app.beginCount, app.endCount)), "")
|
||||
func (app *ChainAwareApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
return types.ResponseQuery{
|
||||
Value: []byte(cmn.Fmt("%d,%d", app.beginCount, app.endCount)),
|
||||
}
|
||||
}
|
||||
|
||||
func (app *ChainAwareApplication) BeginBlock(hash []byte, header *types.Header) {
|
||||
|
||||
@@ -40,10 +40,10 @@ func TestChainAware(t *testing.T) {
|
||||
client.CommitSync()
|
||||
}
|
||||
|
||||
r := app.Query(nil)
|
||||
spl := strings.Split(string(r.Data), ",")
|
||||
r := app.Query(types.RequestQuery{})
|
||||
spl := strings.Split(string(r.Value), ",")
|
||||
if len(spl) != 2 {
|
||||
t.Fatal("expected %d,%d ; got %s", n, n, string(r.Data))
|
||||
t.Fatal("expected %d,%d ; got %s", n, n, string(r.Value))
|
||||
}
|
||||
beginCount, _ := strconv.Atoi(spl[0])
|
||||
endCount, _ := strconv.Atoi(spl[1])
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/abci/types"
|
||||
. "github.com/tendermint/go-common"
|
||||
)
|
||||
|
||||
type CounterApplication struct {
|
||||
@@ -69,15 +70,13 @@ func (app *CounterApplication) Commit() types.Result {
|
||||
return types.NewResultOK(hash, "")
|
||||
}
|
||||
|
||||
func (app *CounterApplication) Query(query []byte) types.Result {
|
||||
queryStr := string(query)
|
||||
|
||||
switch queryStr {
|
||||
func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {
|
||||
switch reqQuery.Path {
|
||||
case "hash":
|
||||
return types.NewResultOK(nil, fmt.Sprintf("%v", app.hashCount))
|
||||
return types.ResponseQuery{Value: []byte(Fmt("%v", app.hashCount))}
|
||||
case "tx":
|
||||
return types.NewResultOK(nil, fmt.Sprintf("%v", app.txCount))
|
||||
return types.ResponseQuery{Value: []byte(Fmt("%v", app.txCount))}
|
||||
default:
|
||||
return types.ResponseQuery{Log: Fmt("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)}
|
||||
}
|
||||
|
||||
return types.ErrUnknownRequest.SetLog(fmt.Sprintf("Invalid nonce. Expected hash or tx, got %v", queryStr))
|
||||
}
|
||||
|
||||
+24
-13
@@ -1,13 +1,11 @@
|
||||
package dummy
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/go-merkle"
|
||||
"github.com/tendermint/go-wire"
|
||||
)
|
||||
|
||||
type DummyApplication struct {
|
||||
@@ -47,15 +45,28 @@ func (app *DummyApplication) Commit() types.Result {
|
||||
return types.NewResultOK(hash, "")
|
||||
}
|
||||
|
||||
func (app *DummyApplication) Query(query []byte) types.Result {
|
||||
index, value, exists := app.state.Get(query)
|
||||
queryResult := QueryResult{index, string(value), hex.EncodeToString(value), exists}
|
||||
return types.NewResultOK(wire.JSONBytes(queryResult), "")
|
||||
}
|
||||
|
||||
type QueryResult struct {
|
||||
Index int `json:"index"`
|
||||
Value string `json:"value"`
|
||||
ValueHex string `json:"valueHex"`
|
||||
Exists bool `json:"exists"`
|
||||
func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
if reqQuery.Prove {
|
||||
value, proof, exists := app.state.Proof(reqQuery.Data)
|
||||
resQuery.Index = -1 // TODO make Proof return index
|
||||
resQuery.Key = reqQuery.Data
|
||||
resQuery.Value = value
|
||||
resQuery.Proof = proof
|
||||
if exists {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
} else {
|
||||
index, value, exists := app.state.Get(reqQuery.Data)
|
||||
resQuery.Index = int64(index)
|
||||
resQuery.Value = value
|
||||
if exists {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+127
-21
@@ -7,34 +7,41 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abcicli "github.com/tendermint/abci/client"
|
||||
"github.com/tendermint/abci/server"
|
||||
"github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire"
|
||||
merkle "github.com/tendermint/go-merkle"
|
||||
)
|
||||
|
||||
func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value string) {
|
||||
if r := dummy.DeliverTx(tx); r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
if r := dummy.DeliverTx(tx); r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
func testDummy(t *testing.T, app types.Application, tx []byte, key, value string) {
|
||||
ar := app.DeliverTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
// repeating tx doesn't raise error
|
||||
ar = app.DeliverTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
|
||||
r := dummy.Query([]byte(key))
|
||||
if r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
|
||||
q := new(QueryResult)
|
||||
if err := wire.ReadJSONBytes(r.Data, q); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if q.Value != value {
|
||||
t.Fatalf("Got %s, expected %s", q.Value, value)
|
||||
}
|
||||
// make sure query is fine
|
||||
resQuery := app.Query(types.RequestQuery{
|
||||
Path: "/store",
|
||||
Data: []byte(key),
|
||||
})
|
||||
require.Equal(t, types.CodeType_OK, resQuery.Code)
|
||||
require.Equal(t, value, string(resQuery.Value))
|
||||
|
||||
// make sure proof is fine
|
||||
resQuery = app.Query(types.RequestQuery{
|
||||
Path: "/store",
|
||||
Data: []byte(key),
|
||||
Prove: true,
|
||||
})
|
||||
require.Equal(t, types.CodeType_OK, resQuery.Code)
|
||||
require.Equal(t, value, string(resQuery.Value))
|
||||
proof, err := merkle.ReadProof(resQuery.Proof)
|
||||
require.Nil(t, err)
|
||||
require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash
|
||||
}
|
||||
|
||||
func TestDummyKV(t *testing.T) {
|
||||
@@ -202,3 +209,102 @@ func valsEqual(t *testing.T, vals1, vals2 []*types.Validator) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeSocketClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) {
|
||||
// Start the listener
|
||||
socket := cmn.Fmt("unix://%s.sock", name)
|
||||
server, err := server.NewSocketServer(socket, app)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Connect to the socket
|
||||
client, err := abcicli.NewSocketClient(socket, false)
|
||||
if err != nil {
|
||||
server.Stop()
|
||||
return nil, nil, err
|
||||
}
|
||||
client.Start()
|
||||
|
||||
return client, server, err
|
||||
}
|
||||
|
||||
func makeGRPCClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) {
|
||||
// Start the listener
|
||||
socket := cmn.Fmt("unix://%s.sock", name)
|
||||
|
||||
gapp := types.NewGRPCApplication(app)
|
||||
server, err := server.NewGRPCServer(socket, gapp)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
client, err := abcicli.NewGRPCClient(socket, true)
|
||||
if err != nil {
|
||||
server.Stop()
|
||||
return nil, nil, err
|
||||
}
|
||||
return client, server, err
|
||||
}
|
||||
|
||||
func TestClientServer(t *testing.T) {
|
||||
// set up socket app
|
||||
dummy := NewDummyApplication()
|
||||
client, server, err := makeSocketClientServer(dummy, "dummy-socket")
|
||||
require.Nil(t, err)
|
||||
defer server.Stop()
|
||||
defer client.Stop()
|
||||
|
||||
runClientTests(t, client)
|
||||
|
||||
// set up grpc app
|
||||
dummy = NewDummyApplication()
|
||||
gclient, gserver, err := makeGRPCClientServer(dummy, "dummy-grpc")
|
||||
require.Nil(t, err)
|
||||
defer gserver.Stop()
|
||||
defer gclient.Stop()
|
||||
|
||||
runClientTests(t, gclient)
|
||||
}
|
||||
|
||||
func runClientTests(t *testing.T, client abcicli.Client) {
|
||||
// run some tests....
|
||||
key := "abc"
|
||||
value := key
|
||||
tx := []byte(key)
|
||||
testClient(t, client, tx, key, value)
|
||||
|
||||
value = "def"
|
||||
tx = []byte(key + "=" + value)
|
||||
testClient(t, client, tx, key, value)
|
||||
}
|
||||
|
||||
func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
|
||||
ar := app.DeliverTxSync(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
// repeating tx doesn't raise error
|
||||
ar = app.DeliverTxSync(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
|
||||
// make sure query is fine
|
||||
resQuery, err := app.QuerySync(types.RequestQuery{
|
||||
Path: "/store",
|
||||
Data: []byte(key),
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, types.CodeType_OK, resQuery.Code)
|
||||
require.Equal(t, value, string(resQuery.Value))
|
||||
|
||||
// make sure proof is fine
|
||||
resQuery, err = app.QuerySync(types.RequestQuery{
|
||||
Path: "/store",
|
||||
Data: []byte(key),
|
||||
Prove: true,
|
||||
})
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, types.CodeType_OK, resQuery.Code)
|
||||
require.Equal(t, value, string(resQuery.Value))
|
||||
proof, err := merkle.ReadProof(resQuery.Proof)
|
||||
require.Nil(t, err)
|
||||
require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash
|
||||
}
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
package dummy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
. "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-crypto"
|
||||
merkle "github.com/tendermint/go-merkle"
|
||||
"github.com/tendermint/go-wire"
|
||||
<<<<<<< HEAD
|
||||
"github.com/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value string) {
|
||||
if r := dummy.DeliverTx(tx); r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
if r := dummy.DeliverTx(tx); r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
|
||||
r := dummy.Query([]byte(key))
|
||||
if r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
=======
|
||||
tmspcli "github.com/tendermint/tmsp/client"
|
||||
"github.com/tendermint/tmsp/server"
|
||||
"github.com/tendermint/tmsp/types"
|
||||
)
|
||||
|
||||
func testDummy(t *testing.T, app types.Application, tx []byte, key, value string) {
|
||||
ar := app.AppendTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
// repeating tx doesn't raise error
|
||||
ar = app.AppendTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
>>>>>>> Add tests for client-server proofs over socket and grpc
|
||||
|
||||
// make sure query is fine
|
||||
r := app.Query([]byte(key))
|
||||
require.False(t, r.IsErr(), r)
|
||||
q := new(QueryResult)
|
||||
err := wire.ReadJSONBytes(r.Data, q)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, value, q.Value)
|
||||
|
||||
// make sure proof is fine
|
||||
rp := app.Proof([]byte(key), 0)
|
||||
require.False(t, rp.IsErr(), rp)
|
||||
p, err := merkle.LoadProof(rp.Data)
|
||||
require.Nil(t, err)
|
||||
require.True(t, p.Valid())
|
||||
assert.Equal(t, []byte(key), p.Key())
|
||||
assert.Equal(t, []byte(value), p.Value())
|
||||
}
|
||||
|
||||
func TestDummyKV(t *testing.T) {
|
||||
dummy := NewDummyApplication()
|
||||
key := "abc"
|
||||
value := key
|
||||
tx := []byte(key)
|
||||
testDummy(t, dummy, tx, key, value)
|
||||
|
||||
value = "def"
|
||||
tx = []byte(key + "=" + value)
|
||||
testDummy(t, dummy, tx, key, value)
|
||||
}
|
||||
|
||||
func TestPersistentDummyKV(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dummy := NewPersistentDummyApplication(dir)
|
||||
key := "abc"
|
||||
value := key
|
||||
tx := []byte(key)
|
||||
testDummy(t, dummy, tx, key, value)
|
||||
|
||||
value = "def"
|
||||
tx = []byte(key + "=" + value)
|
||||
testDummy(t, dummy, tx, key, value)
|
||||
}
|
||||
|
||||
func TestPersistentDummyInfo(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dummy := NewPersistentDummyApplication(dir)
|
||||
height := uint64(0)
|
||||
|
||||
resInfo := dummy.Info()
|
||||
if resInfo.LastBlockHeight != height {
|
||||
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
|
||||
}
|
||||
|
||||
// make and apply block
|
||||
height = uint64(1)
|
||||
hash := []byte("foo")
|
||||
header := &types.Header{
|
||||
Height: uint64(height),
|
||||
}
|
||||
dummy.BeginBlock(hash, header)
|
||||
dummy.EndBlock(height)
|
||||
dummy.Commit()
|
||||
|
||||
resInfo = dummy.Info()
|
||||
if resInfo.LastBlockHeight != height {
|
||||
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// add a validator, remove a validator, update a validator
|
||||
func TestValSetChanges(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dummy := NewPersistentDummyApplication(dir)
|
||||
|
||||
// init with some validators
|
||||
total := 10
|
||||
nInit := 5
|
||||
vals := make([]*types.Validator, total)
|
||||
for i := 0; i < total; i++ {
|
||||
pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(Fmt("test%d", i))).PubKey().Bytes()
|
||||
power := RandInt()
|
||||
vals[i] = &types.Validator{pubkey, uint64(power)}
|
||||
}
|
||||
// iniitalize with the first nInit
|
||||
dummy.InitChain(vals[:nInit])
|
||||
|
||||
vals1, vals2 := vals[:nInit], dummy.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
var v1, v2, v3 *types.Validator
|
||||
|
||||
// add some validators
|
||||
v1, v2 = vals[nInit], vals[nInit+1]
|
||||
diff := []*types.Validator{v1, v2}
|
||||
tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
|
||||
|
||||
makeApplyBlock(t, dummy, 1, diff, tx1, tx2)
|
||||
|
||||
vals1, vals2 = vals[:nInit+2], dummy.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
// remove some validators
|
||||
v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
|
||||
v1.Power = 0
|
||||
v2.Power = 0
|
||||
v3.Power = 0
|
||||
diff = []*types.Validator{v1, v2, v3}
|
||||
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
|
||||
tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
|
||||
|
||||
makeApplyBlock(t, dummy, 2, diff, tx1, tx2, tx3)
|
||||
|
||||
vals1 = append(vals[:nInit-2], vals[nInit+1])
|
||||
vals2 = dummy.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
// update some validators
|
||||
v1 = vals[0]
|
||||
if v1.Power == 5 {
|
||||
v1.Power = 6
|
||||
} else {
|
||||
v1.Power = 5
|
||||
}
|
||||
diff = []*types.Validator{v1}
|
||||
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
|
||||
|
||||
makeApplyBlock(t, dummy, 3, diff, tx1)
|
||||
|
||||
vals1 = append([]*types.Validator{v1}, vals1[1:len(vals1)]...)
|
||||
vals2 = dummy.Validators()
|
||||
valsEqual(t, vals1, vals2)
|
||||
|
||||
}
|
||||
|
||||
func makeApplyBlock(t *testing.T, dummy types.Application, heightInt int, diff []*types.Validator, txs ...[]byte) {
|
||||
// make and apply block
|
||||
height := uint64(heightInt)
|
||||
hash := []byte("foo")
|
||||
header := &types.Header{
|
||||
Height: height,
|
||||
}
|
||||
|
||||
dummyChain := dummy.(types.BlockchainAware) // hmm...
|
||||
dummyChain.BeginBlock(hash, header)
|
||||
for _, tx := range txs {
|
||||
if r := dummy.DeliverTx(tx); r.IsErr() {
|
||||
t.Fatal(r)
|
||||
}
|
||||
}
|
||||
resEndBlock := dummyChain.EndBlock(height)
|
||||
dummy.Commit()
|
||||
|
||||
valsEqual(t, diff, resEndBlock.Diffs)
|
||||
|
||||
}
|
||||
|
||||
// order doesn't matter
|
||||
func valsEqual(t *testing.T, vals1, vals2 []*types.Validator) {
|
||||
if len(vals1) != len(vals2) {
|
||||
t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
|
||||
}
|
||||
sort.Sort(types.Validators(vals1))
|
||||
sort.Sort(types.Validators(vals2))
|
||||
for i, v1 := range vals1 {
|
||||
v2 := vals2[i]
|
||||
if !bytes.Equal(v1.PubKey, v2.PubKey) ||
|
||||
v1.Power != v2.Power {
|
||||
t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeSocketClientServer(app types.Application, name string) (tmspcli.Client, Service, error) {
|
||||
// Start the listener
|
||||
socket := Fmt("unix://%s.sock", name)
|
||||
server, err := server.NewSocketServer(socket, app)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Connect to the socket
|
||||
client, err := tmspcli.NewSocketClient(socket, false)
|
||||
if err != nil {
|
||||
server.Stop()
|
||||
return nil, nil, err
|
||||
}
|
||||
client.Start()
|
||||
|
||||
return client, server, err
|
||||
}
|
||||
|
||||
func makeGRPCClientServer(app types.Application, name string) (tmspcli.Client, Service, error) {
|
||||
// Start the listener
|
||||
socket := Fmt("unix://%s.sock", name)
|
||||
|
||||
gapp := types.NewGRPCApplication(app)
|
||||
server, err := server.NewGRPCServer(socket, gapp)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
client, err := tmspcli.NewGRPCClient(socket, true)
|
||||
if err != nil {
|
||||
server.Stop()
|
||||
return nil, nil, err
|
||||
}
|
||||
return client, server, err
|
||||
}
|
||||
|
||||
func TestClientServer(t *testing.T) {
|
||||
// set up socket app
|
||||
dummy := NewDummyApplication()
|
||||
client, server, err := makeSocketClientServer(dummy, "dummy-socket")
|
||||
require.Nil(t, err)
|
||||
defer server.Stop()
|
||||
defer client.Stop()
|
||||
|
||||
runClientTests(t, client)
|
||||
|
||||
// set up grpc app
|
||||
dummy = NewDummyApplication()
|
||||
gclient, gserver, err := makeGRPCClientServer(dummy, "dummy-grpc")
|
||||
require.Nil(t, err)
|
||||
defer gserver.Stop()
|
||||
defer gclient.Stop()
|
||||
|
||||
runClientTests(t, gclient)
|
||||
}
|
||||
|
||||
func runClientTests(t *testing.T, client tmspcli.Client) {
|
||||
// run some tests....
|
||||
key := "abc"
|
||||
value := key
|
||||
tx := []byte(key)
|
||||
testClient(t, client, tx, key, value)
|
||||
|
||||
value = "def"
|
||||
tx = []byte(key + "=" + value)
|
||||
testClient(t, client, tx, key, value)
|
||||
}
|
||||
|
||||
func testClient(t *testing.T, app tmspcli.Client, tx []byte, key, value string) {
|
||||
ar := app.AppendTxSync(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
// repeating tx doesn't raise error
|
||||
ar = app.AppendTxSync(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
|
||||
// make sure query is fine
|
||||
r := app.QuerySync([]byte(key))
|
||||
require.False(t, r.IsErr(), r)
|
||||
q := new(QueryResult)
|
||||
err := wire.ReadJSONBytes(r.Data, q)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, value, q.Value)
|
||||
|
||||
// make sure proof is fine
|
||||
rp := app.ProofSync([]byte(key), 0)
|
||||
require.False(t, rp.IsErr(), rp)
|
||||
p, err := merkle.LoadProof(rp.Data)
|
||||
require.Nil(t, err)
|
||||
require.True(t, p.Valid())
|
||||
assert.Equal(t, []byte(key), p.Key())
|
||||
assert.Equal(t, []byte(value), p.Value())
|
||||
}
|
||||
@@ -90,8 +90,8 @@ func (app *PersistentDummyApplication) Commit() types.Result {
|
||||
return types.NewResultOK(appHash, "")
|
||||
}
|
||||
|
||||
func (app *PersistentDummyApplication) Query(query []byte) types.Result {
|
||||
return app.app.Query(query)
|
||||
func (app *PersistentDummyApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery {
|
||||
return app.app.Query(reqQuery)
|
||||
}
|
||||
|
||||
// Save the validators in the merkle tree
|
||||
|
||||
@@ -31,6 +31,6 @@ func (app *NilApplication) Commit() types.Result {
|
||||
return types.NewResultOK([]byte("nil"), "")
|
||||
}
|
||||
|
||||
func (app *NilApplication) Query(query []byte) types.Result {
|
||||
return types.NewResultOK(nil, "")
|
||||
func (app *NilApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
return resQuery
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user