Merge PR #2192: Split LCD implementation PR, part one
This commit is contained in:
commit
03f79ef744
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79"
|
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
|
||||||
name = "github.com/btcsuite/btcd"
|
name = "github.com/btcsuite/btcd"
|
||||||
packages = ["btcec"]
|
packages = ["btcec"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
version = "v1.4.7"
|
version = "v1.4.7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe"
|
digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11"
|
||||||
name = "github.com/go-kit/kit"
|
name = "github.com/go-kit/kit"
|
||||||
packages = [
|
packages = [
|
||||||
"log",
|
"log",
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
version = "v1.7.0"
|
version = "v1.7.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45"
|
digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
|
||||||
name = "github.com/gogo/protobuf"
|
name = "github.com/gogo/protobuf"
|
||||||
packages = [
|
packages = [
|
||||||
"gogoproto",
|
"gogoproto",
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
version = "v1.1.1"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888"
|
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
|
||||||
name = "github.com/golang/protobuf"
|
name = "github.com/golang/protobuf"
|
||||||
packages = [
|
packages = [
|
||||||
"proto",
|
"proto",
|
||||||
|
@ -165,13 +165,12 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:ac64f01acc5eeea9dde40e326de6b6471e501392ec06524c3b51033aa50789bc"
|
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
|
||||||
name = "github.com/hashicorp/hcl"
|
name = "github.com/hashicorp/hcl"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"hcl/ast",
|
"hcl/ast",
|
||||||
"hcl/parser",
|
"hcl/parser",
|
||||||
"hcl/printer",
|
|
||||||
"hcl/scanner",
|
"hcl/scanner",
|
||||||
"hcl/strconv",
|
"hcl/strconv",
|
||||||
"hcl/token",
|
"hcl/token",
|
||||||
|
@ -263,7 +262,7 @@
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e"
|
digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0"
|
||||||
name = "github.com/prometheus/client_golang"
|
name = "github.com/prometheus/client_golang"
|
||||||
packages = [
|
packages = [
|
||||||
"prometheus",
|
"prometheus",
|
||||||
|
@ -274,7 +273,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a"
|
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
||||||
name = "github.com/prometheus/client_model"
|
name = "github.com/prometheus/client_model"
|
||||||
packages = ["go"]
|
packages = ["go"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
|
@ -282,7 +281,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:dad2e5a2153ee7a6c9ab8fc13673a16ee4fb64434a7da980965a3741b0c981a3"
|
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
|
||||||
name = "github.com/prometheus/common"
|
name = "github.com/prometheus/common"
|
||||||
packages = [
|
packages = [
|
||||||
"expfmt",
|
"expfmt",
|
||||||
|
@ -294,7 +293,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:a37c98f4b7a66bb5c539c0539f0915a74ef1c8e0b3b6f45735289d94cae92bfd"
|
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
|
||||||
name = "github.com/prometheus/procfs"
|
name = "github.com/prometheus/procfs"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -313,7 +312,7 @@
|
||||||
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c"
|
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
|
||||||
name = "github.com/spf13/afero"
|
name = "github.com/spf13/afero"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -332,7 +331,7 @@
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26"
|
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
|
||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
|
@ -364,7 +363,7 @@
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d"
|
digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6"
|
||||||
name = "github.com/stretchr/testify"
|
name = "github.com/stretchr/testify"
|
||||||
packages = [
|
packages = [
|
||||||
"assert",
|
"assert",
|
||||||
|
@ -376,7 +375,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65"
|
digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
|
||||||
name = "github.com/syndtr/goleveldb"
|
name = "github.com/syndtr/goleveldb"
|
||||||
packages = [
|
packages = [
|
||||||
"leveldb",
|
"leveldb",
|
||||||
|
@ -397,7 +396,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232"
|
digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722"
|
||||||
name = "github.com/tendermint/ed25519"
|
name = "github.com/tendermint/ed25519"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -424,7 +423,7 @@
|
||||||
version = "v0.9.2"
|
version = "v0.9.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:963f6c04345ce36f900c1d6367200eebc3cc2db6ee632ff865ea8dcf64b748a0"
|
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
packages = [
|
packages = [
|
||||||
"abci/client",
|
"abci/client",
|
||||||
|
@ -491,7 +490,7 @@
|
||||||
version = "v0.23.1-rc0"
|
version = "v0.23.1-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ad879bb8c71020a3f92f0c61f414d93eae1d5dc2f37023b6abaa3cc84b00165e"
|
digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e"
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
packages = ["cli"]
|
packages = ["cli"]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
|
@ -507,7 +506,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:2a3ce1f08dcae8bac666deb6e4c88b5d7170c510da38fd746231144cac351704"
|
digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a"
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = [
|
packages = [
|
||||||
"blowfish",
|
"blowfish",
|
||||||
|
@ -529,7 +528,7 @@
|
||||||
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
|
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9"
|
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"context",
|
"context",
|
||||||
|
@ -546,7 +545,7 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:c8baf78f0ac6eb27c645e264fe5e8a74d5a50db188ab41a7ff3b275c112e0735"
|
digest = "1:86171d21d59449dcf7cee0b7d2da83dff989dab9b9b69bfe0a3d59c3c1ca6081"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = [
|
packages = [
|
||||||
"cpu",
|
"cpu",
|
||||||
|
@ -556,7 +555,7 @@
|
||||||
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
|
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca"
|
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
packages = [
|
packages = [
|
||||||
"collate",
|
"collate",
|
||||||
|
@ -587,7 +586,7 @@
|
||||||
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
|
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4515e3030c440845b046354fd5d57671238428b820deebce2e9dabb5cd3c51ac"
|
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
|
||||||
name = "google.golang.org/grpc"
|
name = "google.golang.org/grpc"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
|
@ -664,6 +663,8 @@
|
||||||
"github.com/tendermint/tendermint/libs/common",
|
"github.com/tendermint/tendermint/libs/common",
|
||||||
"github.com/tendermint/tendermint/libs/db",
|
"github.com/tendermint/tendermint/libs/db",
|
||||||
"github.com/tendermint/tendermint/libs/log",
|
"github.com/tendermint/tendermint/libs/log",
|
||||||
|
"github.com/tendermint/tendermint/lite",
|
||||||
|
"github.com/tendermint/tendermint/lite/proxy",
|
||||||
"github.com/tendermint/tendermint/node",
|
"github.com/tendermint/tendermint/node",
|
||||||
"github.com/tendermint/tendermint/p2p",
|
"github.com/tendermint/tendermint/p2p",
|
||||||
"github.com/tendermint/tendermint/privval",
|
"github.com/tendermint/tendermint/privval",
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
tmlite "github.com/tendermint/tendermint/lite"
|
||||||
|
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +36,7 @@ type CLIContext struct {
|
||||||
Async bool
|
Async bool
|
||||||
JSON bool
|
JSON bool
|
||||||
PrintResponse bool
|
PrintResponse bool
|
||||||
|
Certifier tmlite.Certifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
||||||
|
@ -57,9 +62,40 @@ func NewCLIContext() CLIContext {
|
||||||
Async: viper.GetBool(client.FlagAsync),
|
Async: viper.GetBool(client.FlagAsync),
|
||||||
JSON: viper.GetBool(client.FlagJson),
|
JSON: viper.GetBool(client.FlagJson),
|
||||||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||||
|
Certifier: createCertifier(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createCertifier() tmlite.Certifier {
|
||||||
|
trustNode := viper.GetBool(client.FlagTrustNode)
|
||||||
|
if trustNode {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
chainID := viper.GetString(client.FlagChainID)
|
||||||
|
home := viper.GetString(cli.HomeFlag)
|
||||||
|
nodeURI := viper.GetString(client.FlagNode)
|
||||||
|
|
||||||
|
var errMsg bytes.Buffer
|
||||||
|
if chainID == "" {
|
||||||
|
errMsg.WriteString("chain-id ")
|
||||||
|
}
|
||||||
|
if home == "" {
|
||||||
|
errMsg.WriteString("home ")
|
||||||
|
}
|
||||||
|
if nodeURI == "" {
|
||||||
|
errMsg.WriteString("node ")
|
||||||
|
}
|
||||||
|
// errMsg is not empty
|
||||||
|
if errMsg.Len() != 0 {
|
||||||
|
panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String()))
|
||||||
|
}
|
||||||
|
certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return certifier
|
||||||
|
}
|
||||||
|
|
||||||
// WithCodec returns a copy of the context with an updated codec.
|
// WithCodec returns a copy of the context with an updated codec.
|
||||||
func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext {
|
func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext {
|
||||||
ctx.Codec = cdc
|
ctx.Codec = cdc
|
||||||
|
@ -117,3 +153,9 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext {
|
||||||
ctx.UseLedger = useLedger
|
ctx.UseLedger = useLedger
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithCertifier - return a copy of the context with an updated Certifier
|
||||||
|
func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext {
|
||||||
|
ctx.Certifier = certifier
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,14 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetNode returns an RPC client. If the context's client is not defined, an
|
// GetNode returns an RPC client. If the context's client is not defined, an
|
||||||
|
@ -304,12 +309,77 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
|
||||||
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
|
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Data from trusted node or subspace query doesn't need verification
|
||||||
|
if ctx.TrustNode || !isQueryStoreWithProof(path) {
|
||||||
|
return resp.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctx.verifyProof(path, resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return resp.Value, nil
|
return resp.Value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verifyProof perform response proof verification
|
||||||
|
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
|
||||||
|
|
||||||
|
if ctx.Certifier == nil {
|
||||||
|
return fmt.Errorf("missing valid certifier to verify data from untrusted node")
|
||||||
|
}
|
||||||
|
|
||||||
|
node, err := ctx.GetNode()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppHash for height H is in header H+1
|
||||||
|
commit, err := tmliteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var multiStoreProof store.MultiStoreProof
|
||||||
|
cdc := wire.NewCodec()
|
||||||
|
err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to unmarshalBinary rangeProof")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the substore commit hash against trusted appHash
|
||||||
|
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName,
|
||||||
|
multiStoreProof.StoreInfos, commit.Header.AppHash)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed in verifying the proof against appHash")
|
||||||
|
}
|
||||||
|
err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed in the range proof verification")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// queryStore performs a query from a Tendermint node with the provided a store
|
// queryStore performs a query from a Tendermint node with the provided a store
|
||||||
// name and path.
|
// name and path.
|
||||||
func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) {
|
func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) {
|
||||||
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
|
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
|
||||||
return ctx.query(path, key)
|
return ctx.query(path, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
|
||||||
|
// queryType can be app or store
|
||||||
|
func isQueryStoreWithProof(path string) bool {
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
paths := strings.SplitN(path[1:], "/", 3)
|
||||||
|
if len(paths) != 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if store.RequireProof("/" + paths[2]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||||
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
|
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
|
||||||
c.Flags().Bool(FlagJson, false, "return output in json format")
|
c.Flags().Bool(FlagJson, false, "return output in json format")
|
||||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
||||||
|
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
|
||||||
}
|
}
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
client "github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
|
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||||
tx "github.com/cosmos/cosmos-sdk/client/tx"
|
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||||
|
@ -66,6 +66,7 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
||||||
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
|
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
|
||||||
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
|
||||||
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
|
||||||
|
cmd.Flags().Bool(client.FlagTrustNode, false, "Whether trust connected full node")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,6 +190,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
||||||
node, err := startTM(config, logger, genDoc, privVal, app)
|
node, err := startTM(config, logger, genDoc, privVal, app)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
|
||||||
lcd, err := startLCD(logger, listenAddr, cdc)
|
lcd, err := startLCD(logger, listenAddr, cdc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
|
||||||
"os"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
"io"
|
"io"
|
||||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
"os"
|
||||||
)
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestEmptyState(t *testing.T) {
|
func TestEmptyState(t *testing.T) {
|
||||||
defer setupViper(t)()
|
defer setupViper(t)()
|
||||||
|
|
|
@ -129,7 +129,7 @@ func AppGenStateEmpty(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMess
|
||||||
|
|
||||||
// Return a validator, not much else
|
// Return a validator, not much else
|
||||||
func AppGenTx(_ *wire.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) (
|
func AppGenTx(_ *wire.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) (
|
||||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||||
|
|
||||||
validator = tmtypes.GenesisValidator{
|
validator = tmtypes.GenesisValidator{
|
||||||
PubKey: pk,
|
PubKey: pk,
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/tendermint/iavl"
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MultiStoreProof defines a collection of store proofs in a multi-store
|
||||||
|
type MultiStoreProof struct {
|
||||||
|
StoreInfos []storeInfo
|
||||||
|
StoreName string
|
||||||
|
RangeProof iavl.RangeProof
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos
|
||||||
|
func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) []byte {
|
||||||
|
var rangeProof iavl.RangeProof
|
||||||
|
cdc.MustUnmarshalBinary(iavlProof, &rangeProof)
|
||||||
|
|
||||||
|
msp := MultiStoreProof{
|
||||||
|
StoreInfos: storeInfos,
|
||||||
|
StoreName: storeName,
|
||||||
|
RangeProof: rangeProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
proof := cdc.MustMarshalBinary(msp)
|
||||||
|
return proof
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash
|
||||||
|
func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHash []byte) ([]byte, error) {
|
||||||
|
var substoreCommitHash []byte
|
||||||
|
var height int64
|
||||||
|
for _, storeInfo := range storeInfos {
|
||||||
|
if storeInfo.Name == storeName {
|
||||||
|
substoreCommitHash = storeInfo.Core.CommitID.Hash
|
||||||
|
height = storeInfo.Core.CommitID.Version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(substoreCommitHash) == 0 {
|
||||||
|
return nil, cmn.NewError("failed to get substore root commit hash by store name")
|
||||||
|
}
|
||||||
|
|
||||||
|
ci := commitInfo{
|
||||||
|
Version: height,
|
||||||
|
StoreInfos: storeInfos,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(appHash, ci.Hash()) {
|
||||||
|
return nil, cmn.NewError("the merkle root of multiStoreCommitInfo doesn't equal to appHash")
|
||||||
|
}
|
||||||
|
return substoreCommitHash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRangeProof verify iavl RangeProof
|
||||||
|
func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error {
|
||||||
|
|
||||||
|
// verify the proof to ensure data integrity.
|
||||||
|
err := rangeProof.Verify(substoreCommitHash)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(value) != 0 {
|
||||||
|
// verify existence proof
|
||||||
|
err = rangeProof.VerifyItem(key, value)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed in existence verification")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// verify absence proof
|
||||||
|
err = rangeProof.VerifyAbsence(key)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed in absence verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireProof return whether proof is require for the subpath
|
||||||
|
func RequireProof(subpath string) bool {
|
||||||
|
// Currently, only when query subpath is "/store" or "/key", will proof be included in response.
|
||||||
|
// If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212
|
||||||
|
if subpath == "/store" || subpath == "/key" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/tendermint/iavl"
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
|
||||||
|
appHash, _ := hex.DecodeString("ebf3c1fb724d3458023c8fefef7b33add2fc1e84")
|
||||||
|
|
||||||
|
substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
|
||||||
|
storeName := "acc"
|
||||||
|
|
||||||
|
var storeInfos []storeInfo
|
||||||
|
|
||||||
|
gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78")
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "gov",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: gocRootHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "main",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "acc",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: accRootHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "ibc",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4")
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "stake",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: stakeRootHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e")
|
||||||
|
storeInfos = append(storeInfos, storeInfo{
|
||||||
|
Name: "slashing",
|
||||||
|
Core: storeCore{
|
||||||
|
CommitID: CommitID{
|
||||||
|
Version: 689,
|
||||||
|
Hash: slashingRootHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, commitHash, substoreRootHash)
|
||||||
|
|
||||||
|
appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3")
|
||||||
|
|
||||||
|
_, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
|
||||||
|
assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyRangeProof(t *testing.T) {
|
||||||
|
tree := iavl.NewTree(nil, 0)
|
||||||
|
|
||||||
|
rand := cmn.NewRand()
|
||||||
|
rand.Seed(0) // for determinism
|
||||||
|
for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} {
|
||||||
|
key := []byte{ikey}
|
||||||
|
tree.Set(key, []byte(rand.Str(8)))
|
||||||
|
}
|
||||||
|
|
||||||
|
root := tree.Hash()
|
||||||
|
|
||||||
|
key := []byte{0x32}
|
||||||
|
val, proof, err := tree.GetWithProof(key)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotEmpty(t, val)
|
||||||
|
assert.NotEmpty(t, proof)
|
||||||
|
err = VerifyRangeProof(key, val, root, proof)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
key = []byte{0x40}
|
||||||
|
val, proof, err = tree.GetWithProof(key)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Empty(t, val)
|
||||||
|
assert.NotEmpty(t, proof)
|
||||||
|
err = VerifyRangeProof(key, val, root, proof)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
|
@ -291,6 +291,18 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery {
|
||||||
// trim the path and make the query
|
// trim the path and make the query
|
||||||
req.Path = subpath
|
req.Path = subpath
|
||||||
res := queryable.Query(req)
|
res := queryable.Query(req)
|
||||||
|
|
||||||
|
if !req.Prove || !RequireProof(subpath) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
commitInfo, errMsg := getCommitInfo(rs.db, res.Height)
|
||||||
|
if errMsg != nil {
|
||||||
|
return sdk.ErrInternal(errMsg.Error()).QueryResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
tmclient "github.com/tendermint/tendermint/rpc/client"
|
tmclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Wait for the next tendermint block from the Tendermint RPC
|
// Wait for the next tendermint block from the Tendermint RPC
|
||||||
|
@ -185,6 +186,17 @@ func WaitForRPC(laddr string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtractPortFromAddress extract port from listenAddress
|
||||||
|
// The listenAddress must be some strings like tcp://0.0.0.0:12345
|
||||||
|
func ExtractPortFromAddress(listenAddress string) string {
|
||||||
|
stringList := strings.Split(listenAddress, ":")
|
||||||
|
length := len(stringList)
|
||||||
|
if length != 3 {
|
||||||
|
panic(fmt.Errorf("expected listen address: tcp://0.0.0.0:12345, got %s", listenAddress))
|
||||||
|
}
|
||||||
|
return stringList[2]
|
||||||
|
}
|
||||||
|
|
||||||
var cdc = amino.NewCodec()
|
var cdc = amino.NewCodec()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
Loading…
Reference in New Issue