mirror of
https://github.com/tendermint/tendermint.git
synced 2026-07-20 15:02:33 +00:00
fixed all tests
This commit is contained in:
Generated
+3
-3
@@ -308,8 +308,8 @@
|
||||
".",
|
||||
"sha256truncated"
|
||||
]
|
||||
revision = "8ca620e7e401976d0324938c9a361cf78bca9770"
|
||||
version = "v0.9.3-rc0"
|
||||
revision = "866a229a90d86b07af23ffa156c3fa1396416574"
|
||||
version = "v0.10.0-rc1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
@@ -432,6 +432,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "e473d5da80b2f997f7b1e42ff6eb0fff055fa0ff9ab1a9f0bd01ed239b479fe3"
|
||||
inputs-digest = "ece6ed2d29c510b27b489c93a94e68e4aa5db840c16c6b8b7563d81fed4072fe"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/iavl"
|
||||
version = "0.9.3-rc0"
|
||||
version = "0.10.0-rc1"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/tendermint/iavl"
|
||||
"github.com/tendermint/tendermint/abci/example/code"
|
||||
"github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
)
|
||||
@@ -107,27 +108,42 @@ func (app *KVStoreApplication) Commit() types.ResponseCommit {
|
||||
|
||||
func (app *KVStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) {
|
||||
key := reqQuery.Data
|
||||
height := app.state.Height
|
||||
if reqQuery.Height != 0 {
|
||||
height = reqQuery.Height
|
||||
}
|
||||
if reqQuery.Prove {
|
||||
value, proof, err := app.state.tree.GetWithProof(key)
|
||||
value, proof, err := app.state.tree.GetVersionedWithProof(key, height)
|
||||
if err != nil {
|
||||
resQuery.Code = code.CodeTypeUnknownError
|
||||
resQuery.Log = err.Error()
|
||||
return
|
||||
}
|
||||
resQuery.Height = height
|
||||
resQuery.Index = proof.LeftIndex() // TODO make Proof return index
|
||||
resQuery.Key = reqQuery.Data
|
||||
resQuery.Key = key
|
||||
resQuery.Value = value
|
||||
if value != nil {
|
||||
resQuery.Proof = &merkle.Proof{
|
||||
// XXX key encoding
|
||||
Ops: []merkle.ProofOp{iavl.NewIAVLValueOp(string(key), proof).ProofOp()},
|
||||
}
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
resQuery.Proof = &merkle.Proof{
|
||||
// XXX key encoding
|
||||
Ops: []merkle.ProofOp{iavl.NewIAVLAbsenceOp(string(key), proof).ProofOp()},
|
||||
}
|
||||
resQuery.Log = "does not exist"
|
||||
}
|
||||
return
|
||||
} else {
|
||||
index, value := app.state.tree.Get64(key)
|
||||
resQuery.Index = index
|
||||
resQuery.Key = reqQuery.Data
|
||||
index, value := app.state.tree.GetVersioned(key, height)
|
||||
resQuery.Height = height
|
||||
resQuery.Index = int64(index) // TODO GetVersioned64?
|
||||
resQuery.Key = key
|
||||
resQuery.Value = value
|
||||
resQuery.Proof = nil
|
||||
if value != nil {
|
||||
resQuery.Log = "exists"
|
||||
} else {
|
||||
|
||||
@@ -18,11 +18,13 @@ import (
|
||||
)
|
||||
|
||||
func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) {
|
||||
ar := app.DeliverTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
rdtx := app.DeliverTx(tx)
|
||||
require.False(t, rdtx.IsErr(), rdtx)
|
||||
// repeating tx doesn't raise error
|
||||
ar = app.DeliverTx(tx)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
rdtx = app.DeliverTx(tx)
|
||||
require.False(t, rdtx.IsErr(), rdtx)
|
||||
rc := app.Commit()
|
||||
require.NotNil(t, rc.Data)
|
||||
|
||||
// make sure query is fine
|
||||
resQuery := app.Query(types.RequestQuery{
|
||||
@@ -281,13 +283,16 @@ func runClientTests(t *testing.T, client abcicli.Client) {
|
||||
}
|
||||
|
||||
func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
|
||||
ar, err := app.DeliverTxSync(tx)
|
||||
rdtx, err := app.DeliverTxSync(tx)
|
||||
require.NoError(t, err)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
require.False(t, rdtx.IsErr(), rdtx)
|
||||
// repeating tx doesn't raise error
|
||||
ar, err = app.DeliverTxSync(tx)
|
||||
rdtx, err = app.DeliverTxSync(tx)
|
||||
require.NoError(t, err)
|
||||
require.False(t, ar.IsErr(), ar)
|
||||
require.False(t, rdtx.IsErr(), rdtx)
|
||||
rc, err := app.CommitSync()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rc.Data)
|
||||
|
||||
// make sure query is fine
|
||||
resQuery, err := app.QuerySync(types.RequestQuery{
|
||||
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
|
||||
// genesis, chain_id, priv_val
|
||||
var config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||
var ensureTimeout = time.Second * 1 // must be in seconds because CreateEmptyBlocksInterval is
|
||||
var ensureTimeout = time.Second * 5 // must be in seconds because CreateEmptyBlocksInterval is
|
||||
|
||||
func ensureDir(dir string, mode os.FileMode) {
|
||||
if err := cmn.EnsureDir(dir, mode); err != nil {
|
||||
|
||||
+9
-19
@@ -2,7 +2,6 @@ package merkle
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
@@ -72,20 +71,6 @@ func NewProofRuntime() *ProofRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
func (prt *ProofRuntime) RegisterAminoOpDecoder(typ string, opType reflect.Type) {
|
||||
prt.RegisterOpDecoder(
|
||||
typ,
|
||||
func(pop ProofOp) (ProofOperator, error) {
|
||||
newOp := reflect.New(opType).Elem().Interface()
|
||||
err := cdc.UnmarshalBinary(pop.Data, &newOp)
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data")
|
||||
}
|
||||
return newOp.(ProofOperator), nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (prt *ProofRuntime) RegisterOpDecoder(typ string, dec OpDecoder) {
|
||||
_, ok := prt.decoders[typ]
|
||||
if ok {
|
||||
@@ -120,6 +105,14 @@ func (prt *ProofRuntime) VerifyValue(proof *Proof, root []byte, value []byte, ke
|
||||
return prt.Verify(proof, root, [][]byte{value}, keys...)
|
||||
}
|
||||
|
||||
// XXX Reorder value/keys, and figure out how to merge keys into a single string
|
||||
// after figuring out encoding between bytes/string.
|
||||
// TODO In the long run we'll need a method of classifcation of ops,
|
||||
// whether existence or absence or perhaps a third?
|
||||
func (prt *ProofRuntime) VerifyAbsence(proof *Proof, root []byte, keys ...string) (err error) {
|
||||
return prt.Verify(proof, root, nil, keys...)
|
||||
}
|
||||
|
||||
// XXX Reorder value/keys, and figure out how to merge keys into a single string
|
||||
// after figuring out encoding between bytes/string.
|
||||
func (prt *ProofRuntime) Verify(proof *Proof, root []byte, args [][]byte, keys ...string) (err error) {
|
||||
@@ -136,9 +129,6 @@ func (prt *ProofRuntime) Verify(proof *Proof, root []byte, args [][]byte, keys .
|
||||
// defined in the IAVL package.
|
||||
func DefaultProofRuntime() (prt *ProofRuntime) {
|
||||
prt = NewProofRuntime()
|
||||
prt.RegisterAminoOpDecoder(
|
||||
ProofOpSimpleValue,
|
||||
reflect.TypeOf(SimpleValueOp{}),
|
||||
)
|
||||
prt.RegisterOpDecoder(ProofOpSimpleValue, SimpleValueOpDecoder)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const ProofOpSimpleValue = "simple:v"
|
||||
// If the produced root hash matches the expected hash, the
|
||||
// proof is good.
|
||||
type SimpleValueOp struct {
|
||||
// encoded in ProofOp.Key, not .Data
|
||||
// Encoded in ProofOp.Key.
|
||||
key string
|
||||
|
||||
// To encode in ProofOp.Data
|
||||
@@ -37,6 +37,27 @@ func NewSimpleValueOp(key string, proof *SimpleProof) SimpleValueOp {
|
||||
}
|
||||
}
|
||||
|
||||
func SimpleValueOpDecoder(pop ProofOp) (ProofOperator, error) {
|
||||
if pop.Type != ProofOpSimpleValue {
|
||||
return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpSimpleValue)
|
||||
}
|
||||
var op SimpleValueOp // a bit strange as we'll discard this, but it works.
|
||||
err := cdc.UnmarshalBinary(pop.Data, &op)
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into SimpleValueOp")
|
||||
}
|
||||
return NewSimpleValueOp(pop.Key, op.Proof), nil
|
||||
}
|
||||
|
||||
func (op SimpleValueOp) ProofOp() ProofOp {
|
||||
bz := cdc.MustMarshalBinary(op)
|
||||
return ProofOp{
|
||||
Type: ProofOpSimpleValue,
|
||||
Key: op.key,
|
||||
Data: bz,
|
||||
}
|
||||
}
|
||||
|
||||
func (op SimpleValueOp) String() string {
|
||||
return fmt.Sprintf("SimpleValueOp{%v}", op.GetKey())
|
||||
}
|
||||
@@ -50,7 +71,7 @@ func (op SimpleValueOp) Run(args [][]byte) ([][]byte, error) {
|
||||
hasher.Write(value) // does not error
|
||||
vhash := hasher.Sum(nil)
|
||||
|
||||
// Wrap <op.key, vhash> to hash the KVPair.
|
||||
// Wrap <op.Key, vhash> to hash the KVPair.
|
||||
hasher = tmhash.New()
|
||||
encodeByteSlice(hasher, []byte(op.key)) // does not error
|
||||
encodeByteSlice(hasher, []byte(vhash)) // does not error
|
||||
@@ -68,12 +89,3 @@ func (op SimpleValueOp) Run(args [][]byte) ([][]byte, error) {
|
||||
func (op SimpleValueOp) GetKey() string {
|
||||
return op.key
|
||||
}
|
||||
|
||||
func (op SimpleValueOp) ProofOp() ProofOp {
|
||||
bz := cdc.MustMarshalBinary(op)
|
||||
return ProofOp{
|
||||
Type: ProofOpSimpleValue,
|
||||
Key: op.key,
|
||||
Data: bz,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ func (e errMissingValidators) Error() string {
|
||||
e.chainID, e.height)
|
||||
}
|
||||
|
||||
type errEmptyTree struct{}
|
||||
|
||||
func (e errEmptyTree) Error() string {
|
||||
return "Tree is empty"
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Methods for above error types
|
||||
|
||||
@@ -110,3 +116,18 @@ func IsErrMissingValidators(err error) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//-----------------
|
||||
// ErrEmptyTree
|
||||
|
||||
func ErrEmptyTree() error {
|
||||
return cmn.ErrorWrap(errEmptyTree{}, "")
|
||||
}
|
||||
|
||||
func IsErrEmptyTree(err error) bool {
|
||||
if err_, ok := err.(cmn.Error); ok {
|
||||
_, ok := err_.Data().(errEmptyTree)
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
type errNoData struct{}
|
||||
|
||||
func (e errNoData) Error() string {
|
||||
return "No data returned for query"
|
||||
}
|
||||
|
||||
// IsErrNoData checks whether an error is due to a query returning empty data
|
||||
func IsErrNoData(err error) bool {
|
||||
if err_, ok := err.(cmn.Error); ok {
|
||||
_, ok := err_.Data().(errNoData)
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ErrNoData() error {
|
||||
return cmn.ErrorWrap(errNoData{}, "")
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/tendermint/iavl"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
)
|
||||
|
||||
func defaultProofRuntime() *merkle.ProofRuntime {
|
||||
prt := merkle.NewProofRuntime()
|
||||
prt.RegisterOpDecoder(
|
||||
merkle.ProofOpSimpleValue,
|
||||
merkle.SimpleValueOpDecoder,
|
||||
)
|
||||
prt.RegisterOpDecoder(
|
||||
iavl.ProofOpIAVLValue,
|
||||
iavl.IAVLValueOpDecoder,
|
||||
)
|
||||
prt.RegisterOpDecoder(
|
||||
iavl.ProofOpIAVLAbsence,
|
||||
iavl.IAVLAbsenceOpDecoder,
|
||||
)
|
||||
return prt
|
||||
}
|
||||
+19
-12
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
"github.com/tendermint/tendermint/lite"
|
||||
lerr "github.com/tendermint/tendermint/lite/errors"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -16,7 +17,7 @@ import (
|
||||
// a valid proof, as defined by the certifier.
|
||||
//
|
||||
// If there is any error in checking, returns an error.
|
||||
func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
||||
func GetWithProof(prt *merkle.ProofRuntime, key []byte, reqHeight int64, node rpcclient.Client,
|
||||
cert lite.Certifier) (
|
||||
val cmn.HexBytes, height int64, proof *merkle.Proof, err error) {
|
||||
|
||||
@@ -25,7 +26,7 @@ func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
||||
return
|
||||
}
|
||||
|
||||
res, err := GetWithProofOptions("/key", key,
|
||||
res, err := GetWithProofOptions(prt, "/key", key,
|
||||
rpcclient.ABCIQueryOptions{Height: int64(reqHeight), Prove: true},
|
||||
node, cert)
|
||||
if err != nil {
|
||||
@@ -38,7 +39,8 @@ func GetWithProof(key []byte, reqHeight int64, node rpcclient.Client,
|
||||
}
|
||||
|
||||
// GetWithProofOptions is useful if you want full access to the ABCIQueryOptions.
|
||||
func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOptions,
|
||||
// XXX Usage of path? It's not used, and sometimes it's /, sometimes /key, sometimes /store.
|
||||
func GetWithProofOptions(prt *merkle.ProofRuntime, path string, key []byte, opts rpcclient.ABCIQueryOptions,
|
||||
node rpcclient.Client, cert lite.Certifier) (
|
||||
*ctypes.ResultABCIQuery, error) {
|
||||
|
||||
@@ -57,8 +59,9 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
|
||||
err = cmn.NewError("Query error for key %d: %d", key, resp.Code)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Key) == 0 || resp.Proof == nil {
|
||||
return nil, ErrNoData()
|
||||
return nil, lerr.ErrEmptyTree()
|
||||
}
|
||||
if resp.Height == 0 {
|
||||
return nil, cmn.NewError("Height returned is zero")
|
||||
@@ -70,21 +73,25 @@ func GetWithProofOptions(path string, key []byte, opts rpcclient.ABCIQueryOption
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Value) > 0 {
|
||||
// Validate the proof against the certified header to ensure data integrity.
|
||||
// XXX Pass this in somehow so iavl can be registered.
|
||||
// Validate the proof against the certified header to ensure data integrity.
|
||||
if resp.Value != nil {
|
||||
// Value exists
|
||||
// XXX How do we encode the key into a string...
|
||||
prt := merkle.NewProofRuntime()
|
||||
err = prt.VerifyValue(resp.Proof, signedHeader.AppHash, resp.Value, string(resp.Key))
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "Couldn't verify proof")
|
||||
return nil, cmn.ErrorWrap(err, "Couldn't verify value proof")
|
||||
}
|
||||
return &ctypes.ResultABCIQuery{Response: resp}, nil
|
||||
} else {
|
||||
return nil, cmn.NewError("proof of absence not yet supported")
|
||||
// Value absent
|
||||
// Validate the proof against the certified header to ensure data integrity.
|
||||
// XXX How do we encode the key into a string...
|
||||
err = prt.VerifyAbsence(resp.Proof, signedHeader.AppHash, string(resp.Key))
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "Couldn't verify absence proof")
|
||||
}
|
||||
return &ctypes.ResultABCIQuery{Response: resp}, nil
|
||||
}
|
||||
|
||||
return &ctypes.ResultABCIQuery{Response: resp}, ErrNoData()
|
||||
}
|
||||
|
||||
// GetCertifiedCommit gets the signed header for a given height and certifies
|
||||
|
||||
+55
-37
@@ -4,13 +4,12 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
"github.com/tendermint/tendermint/lite"
|
||||
certclient "github.com/tendermint/tendermint/lite/client"
|
||||
nm "github.com/tendermint/tendermint/node"
|
||||
@@ -21,6 +20,7 @@ import (
|
||||
|
||||
var node *nm.Node
|
||||
var chainID = "tendermint_test" // TODO use from config.
|
||||
var waitForEventTimeout = 5 * time.Second
|
||||
|
||||
// TODO fix tests!!
|
||||
|
||||
@@ -42,64 +42,82 @@ func kvstoreTx(k, v []byte) []byte {
|
||||
func TestAppProofs(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
prt := defaultProofRuntime()
|
||||
cl := client.NewLocal(node)
|
||||
client.WaitForHeight(cl, 1, nil)
|
||||
|
||||
// This sets up our trust on the node based on some past point.
|
||||
source := certclient.NewProvider(chainID, cl)
|
||||
seed, err := source.LatestFullCommit(chainID, 1, 1)
|
||||
require.NoError(err, "%#v", err)
|
||||
cert := lite.NewBaseCertifier(chainID, seed.Height(), seed.Validators)
|
||||
|
||||
// Wait for tx confirmation.
|
||||
done := make(chan int64)
|
||||
go func() {
|
||||
evtTyp := types.EventTx
|
||||
_, err = client.WaitForOneEvent(cl, evtTyp, waitForEventTimeout)
|
||||
require.Nil(err, "%#v", err)
|
||||
close(done)
|
||||
}()
|
||||
|
||||
// Submit a transaction.
|
||||
k := []byte("my-key")
|
||||
v := []byte("my-value")
|
||||
|
||||
tx := kvstoreTx(k, v)
|
||||
br, err := cl.BroadcastTxCommit(tx)
|
||||
require.NoError(err, "%+v", err)
|
||||
require.NoError(err, "%#v", err)
|
||||
require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx)
|
||||
require.EqualValues(0, br.DeliverTx.Code)
|
||||
brh := br.Height
|
||||
|
||||
// This sets up our trust on the node based on some past point.
|
||||
source := certclient.NewProvider(chainID, cl)
|
||||
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
||||
require.NoError(err, "%+v", err)
|
||||
cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators)
|
||||
|
||||
client.WaitForHeight(cl, 3, nil)
|
||||
// Fetch latest after tx commit.
|
||||
<-done
|
||||
latest, err := source.LatestFullCommit(chainID, 1, 1<<63-1)
|
||||
require.NoError(err, "%+v", err)
|
||||
require.NoError(err, "%#v", err)
|
||||
rootHash := latest.SignedHeader.AppHash
|
||||
if rootHash == nil {
|
||||
// Fetch one block later, AppHash hasn't been committed yet.
|
||||
// TODO find a way to avoid doing this.
|
||||
client.WaitForHeight(cl, latest.SignedHeader.Height+1, nil)
|
||||
latest, err = source.LatestFullCommit(chainID, latest.SignedHeader.Height+1, 1<<63-1)
|
||||
require.NoError(err, "%#v", err)
|
||||
rootHash = latest.SignedHeader.AppHash
|
||||
}
|
||||
require.NotNil(rootHash)
|
||||
|
||||
// verify a query before the tx block has no data (and valid non-exist proof)
|
||||
bs, height, proof, err := GetWithProof(k, brh-1, cl, cert)
|
||||
require.NotNil(err)
|
||||
require.NotNil(proof)
|
||||
// XXX test proof
|
||||
require.True(IsErrNoData(err), err.Error())
|
||||
bs, height, proof, err := GetWithProof(prt, k, brh-1, cl, cert)
|
||||
require.NoError(err, "%#v", err)
|
||||
// require.NotNil(proof)
|
||||
// TODO: Ensure that *some* keys will be there, ensuring that proof is nil,
|
||||
// (currently there's a race condition)
|
||||
// and ensure that proof proves absence of k.
|
||||
require.Nil(bs)
|
||||
|
||||
// but given that block it is good
|
||||
bs, height, proof, err = GetWithProof(k, brh, cl, cert)
|
||||
require.NoError(err, "%+v", err)
|
||||
bs, height, proof, err = GetWithProof(prt, k, brh, cl, cert)
|
||||
require.NoError(err, "%#v", err)
|
||||
require.NotNil(proof)
|
||||
require.True(height >= int64(latest.Height()))
|
||||
|
||||
prt := merkle.NewProofRuntime()
|
||||
require.Equal(height, brh)
|
||||
|
||||
assert.EqualValues(v, bs)
|
||||
err = prt.VerifyValue(proof, rootHash, k, string(bs))
|
||||
assert.NoError(err, "%+v", err)
|
||||
err = prt.VerifyValue(proof, rootHash, bs, string(k)) // XXX key encoding
|
||||
assert.NoError(err, "%#v", err)
|
||||
|
||||
// Test non-existing key.
|
||||
missing := []byte("my-missing-key")
|
||||
bs, _, proof, err = GetWithProof(missing, 0, cl, cert)
|
||||
require.True(IsErrNoData(err))
|
||||
bs, _, proof, err = GetWithProof(prt, missing, 0, cl, cert)
|
||||
require.NoError(err)
|
||||
require.Nil(bs)
|
||||
require.NotNil(proof)
|
||||
err = prt.VerifyValue(proof, rootHash, missing, "") // XXX VerifyAbsence()
|
||||
assert.NoError(err, "%+v", err)
|
||||
err = prt.VerifyValue(proof, rootHash, k, "") // XXX VerifyAbsence()
|
||||
assert.Error(err)
|
||||
err = prt.Verify(proof, rootHash, nil, string(missing)) // XXX VerifyAbsence(), keyencoding
|
||||
assert.NoError(err, "%#v", err)
|
||||
err = prt.Verify(proof, rootHash, nil, string(k)) // XXX VerifyAbsence(), keyencoding
|
||||
assert.Error(err, "%#v", err)
|
||||
}
|
||||
|
||||
func _TestTxProofs(t *testing.T) {
|
||||
func TestTxProofs(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
cl := client.NewLocal(node)
|
||||
@@ -107,15 +125,15 @@ func _TestTxProofs(t *testing.T) {
|
||||
|
||||
tx := kvstoreTx([]byte("key-a"), []byte("value-a"))
|
||||
br, err := cl.BroadcastTxCommit(tx)
|
||||
require.NoError(err, "%+v", err)
|
||||
require.NoError(err, "%#v", err)
|
||||
require.EqualValues(0, br.CheckTx.Code, "%#v", br.CheckTx)
|
||||
require.EqualValues(0, br.DeliverTx.Code)
|
||||
brh := br.Height
|
||||
|
||||
source := certclient.NewProvider(chainID, cl)
|
||||
seed, err := source.LatestFullCommit(chainID, brh-2, brh-2)
|
||||
require.NoError(err, "%+v", err)
|
||||
cert := lite.NewBaseCertifier("my-chain", seed.Height(), seed.Validators)
|
||||
require.NoError(err, "%#v", err)
|
||||
cert := lite.NewBaseCertifier(chainID, seed.Height(), seed.Validators)
|
||||
|
||||
// First let's make sure a bogus transaction hash returns a valid non-existence proof.
|
||||
key := types.Tx([]byte("bogus")).Hash()
|
||||
@@ -126,12 +144,12 @@ func _TestTxProofs(t *testing.T) {
|
||||
// Now let's check with the real tx hash.
|
||||
key = types.Tx(tx).Hash()
|
||||
res, err = cl.Tx(key, true)
|
||||
require.NoError(err, "%+v", err)
|
||||
require.NoError(err, "%#v", err)
|
||||
require.NotNil(res)
|
||||
err = res.Proof.Validate(key)
|
||||
assert.NoError(err, "%+v", err)
|
||||
assert.NoError(err, "%#v", err)
|
||||
|
||||
commit, err := GetCertifiedCommit(br.Height, cl, cert)
|
||||
require.Nil(err, "%+v", err)
|
||||
require.Nil(err, "%#v", err)
|
||||
require.Equal(res.Proof.RootHash, commit.Header.DataHash)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package proxy
|
||||
import (
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
"github.com/tendermint/tendermint/lite"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
@@ -15,6 +16,7 @@ var _ rpcclient.Client = Wrapper{}
|
||||
type Wrapper struct {
|
||||
rpcclient.Client
|
||||
cert *lite.InquiringCertifier
|
||||
prt *merkle.ProofRuntime
|
||||
}
|
||||
|
||||
// SecureClient uses a given certifier to wrap an connection to an untrusted
|
||||
@@ -22,7 +24,8 @@ type Wrapper struct {
|
||||
//
|
||||
// If it is wrapping an HTTP rpcclient, it will also wrap the websocket interface
|
||||
func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper {
|
||||
wrap := Wrapper{c, cert}
|
||||
prt := defaultProofRuntime()
|
||||
wrap := Wrapper{c, cert, prt}
|
||||
// TODO: no longer possible as no more such interface exposed....
|
||||
// if we wrap http client, then we can swap out the event switch to filter
|
||||
// if hc, ok := c.(*rpcclient.HTTP); ok {
|
||||
@@ -36,7 +39,7 @@ func SecureClient(c rpcclient.Client, cert *lite.InquiringCertifier) Wrapper {
|
||||
func (w Wrapper) ABCIQueryWithOptions(path string, data cmn.HexBytes,
|
||||
opts rpcclient.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
|
||||
|
||||
res, err := GetWithProofOptions(path, data, opts, w.Client, w.cert)
|
||||
res, err := GetWithProofOptions(w.prt, path, data, opts, w.Client, w.cert)
|
||||
return res, err
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ func (a ABCIApp) ABCIQueryWithOptions(path string, data cmn.HexBytes, opts clien
|
||||
return &ctypes.ResultABCIQuery{q}, nil
|
||||
}
|
||||
|
||||
// NOTE: Caller should call a.App.Commit() separately,
|
||||
// this function does not actually wait for a commit.
|
||||
// TODO: Make it wait for a commit and set res.Height appropriately.
|
||||
func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
res := ctypes.ResultBroadcastTxCommit{}
|
||||
res.CheckTx = a.App.CheckTx(tx)
|
||||
@@ -42,6 +45,7 @@ func (a ABCIApp) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit
|
||||
return &res, nil
|
||||
}
|
||||
res.DeliverTx = a.App.DeliverTx(tx)
|
||||
res.Height = -1 // TODO
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -173,6 +173,12 @@ func TestABCIApp(t *testing.T) {
|
||||
require.NotNil(res.DeliverTx)
|
||||
assert.True(res.DeliverTx.IsOK())
|
||||
|
||||
// commit
|
||||
// TODO: This may not be necessary in the future
|
||||
if res.Height == -1 {
|
||||
m.App.Commit()
|
||||
}
|
||||
|
||||
// check the key
|
||||
_qres, err := m.ABCIQueryWithOptions("/key", cmn.HexBytes(key), client.ABCIQueryOptions{Prove: true})
|
||||
qres := _qres.Response
|
||||
|
||||
@@ -359,7 +359,7 @@ func TestTxSearch(t *testing.T) {
|
||||
require.Len(t, result.Txs, 0)
|
||||
|
||||
// we query using a tag (see kvstore application)
|
||||
result, err = c.TxSearch("app.creator='jae'", false, 1, 30)
|
||||
result, err = c.TxSearch("app.creator='Cosmoshi Netowoko'", false, 1, 30)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
if len(result.Txs) == 0 {
|
||||
t.Fatal("expected a lot of transactions")
|
||||
|
||||
+5
-6
@@ -10,7 +10,7 @@ import (
|
||||
// Query the application for some information.
|
||||
//
|
||||
// ```shell
|
||||
// curl 'localhost:26657/abci_query?path=""&data="abcd"&trusted=false'
|
||||
// curl 'localhost:26657/abci_query?path=""&data="abcd"&prove=false'
|
||||
// ```
|
||||
//
|
||||
// ```go
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
// "response": {
|
||||
// "log": "exists",
|
||||
// "height": 0,
|
||||
// "proof": "010114FED0DAD959F36091AD761C922ABA3CBF1D8349990101020103011406AA2262E2F448242DF2C2607C3CDC705313EE3B0001149D16177BC71E445476174622EA559715C293740C",
|
||||
// "value": "61626364",
|
||||
// "key": "61626364",
|
||||
// "index": -1,
|
||||
@@ -45,14 +44,14 @@ import (
|
||||
// |-----------+--------+---------+----------+------------------------------------------------|
|
||||
// | path | string | false | false | Path to the data ("/a/b/c") |
|
||||
// | data | []byte | false | true | Data |
|
||||
// | height | int64 | 0 | false | Height (0 means latest) |
|
||||
// | trusted | bool | false | false | Does not include a proof of the data inclusion |
|
||||
func ABCIQuery(path string, data cmn.HexBytes, height int64, trusted bool) (*ctypes.ResultABCIQuery, error) {
|
||||
// | height | int64 | 0 | false | Height (0 means latest) |
|
||||
// | prove | bool | false | false | Includes proof if true |
|
||||
func ABCIQuery(path string, data cmn.HexBytes, height int64, prove bool) (*ctypes.ResultABCIQuery, error) {
|
||||
resQuery, err := proxyAppQuery.QuerySync(abci.RequestQuery{
|
||||
Path: path,
|
||||
Data: data,
|
||||
Height: height,
|
||||
Prove: !trusted,
|
||||
Prove: prove,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user