Enforce ProofSpecs in 23-Commitment (#6374)
* enforce spec ordering * modify clients to pass in specs to verify functions * start fixing tests * Apply suggestions from code review * enforce spec length and proof length match * fix all tests * add argument to constructor: * fixed msg client and tests * appease linter * Apply suggestions from code review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * finish fixes from review * add back proof-specific checks * Apply suggestions from code review * more robust proof spec checks * add CHANGELOG entries * do not hardcode proofspecs in 23-commitment * fix client modules * fix tests * appease linter Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
parent
9048ffa8d3
commit
d82c2e6a94
|
@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||
balances or a single balance by denom when the `denom` query parameter is present.
|
||||
* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/pull/5640) The rest server endpoint `/swagger-ui/` is replaced by ´/´.
|
||||
* (x/auth) [\#5702](https://github.com/cosmos/cosmos-sdk/pull/5702) The `x/auth` querier route has changed from `"acc"` to `"auth"`.
|
||||
* (store/rootmulti) [\#6390](https://github.com/cosmos/cosmos-sdk/pull/6390) Proofs of empty stores are no longer supported.
|
||||
* (store/types) [\#5730](https://github.com/cosmos/cosmos-sdk/pull/5730) store.types.Cp() is removed in favour of types.CopyBytes().
|
||||
* (client) [\#5640](https://github.com/cosmos/cosmos-sdk/issues/5783) Unify all coins representations on JSON client requests for governance proposals.
|
||||
* [\#5785](https://github.com/cosmos/cosmos-sdk/issues/5785) JSON strings coerced to valid UTF-8 bytes at JSON marshalling time
|
||||
|
@ -135,6 +136,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa
|
|||
* (client/lcd) [\#6290](https://github.com/cosmos/cosmos-sdk/pull/6290) `CliCtx` of struct `RestServer` in package client/lcd has been renamed to `ClientCtx`.
|
||||
* (types) [\#6327](https://github.com/cosmos/cosmos-sdk/pull/6327) `sdk.Msg` now inherits `proto.Message`, as a result all `sdk.Msg` types now use pointer semantics.
|
||||
* (codec) [\#6330](https://github.com/cosmos/cosmos-sdk/pull/6330) `codec.RegisterCrypto` has been moved to the `crypto/codec` package and the global `codec.Cdc` Amino instance has been deprecated and moved to the `codec/legacy_global` package.
|
||||
* (x/ibc) [\#6374](https://github.com/cosmos/cosmos-sdk/pull/6374) `VerifyMembership` and `VerifyNonMembership` now take a `specs []string` argument to specify the proof format used for verification. Most SDK chains can simply use `commitmenttypes.GetSDKSpecs()` for this argument.
|
||||
|
||||
### Features
|
||||
|
||||
|
@ -153,6 +155,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa
|
|||
* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md).
|
||||
* (x/params) [\#6005](https://github.com/cosmos/cosmos-sdk/pull/6005) Add new CLI command for querying raw x/params parameters by subspace and key.
|
||||
* (x/ibc) [\#5769](https://github.com/cosmos/cosmos-sdk/pull/5769) [ICS 009 - Loopback Client](https://github.com/cosmos/ics/tree/master/spec/ics-009-loopback-client) subpackage
|
||||
* (x/ibc) [\#6374](https://github.com/cosmos/cosmos-sdk/pull/6374) ICS-23 Verify functions will now accept and verify ics23 CommitmentProofs exclusively
|
||||
* (store) [\#6324](https://github.com/cosmos/cosmos-sdk/pull/6324) IAVL store query proofs now return CommitmentOp which wraps an ics23 CommitmentProof
|
||||
* (store) [\#6390](https://github.com/cosmos/cosmos-sdk/pull/6390) `RootMulti` store query proofs now return `CommitmentOp` which wraps `CommitmentProofs`
|
||||
* `store.Query` now only returns chained `ics23.CommitmentProof` wrapped in `merkle.Proof`
|
||||
|
|
|
@ -190,7 +190,7 @@ func (chain *TestChain) CreateClient(client *TestChain) error {
|
|||
ctxTarget := chain.GetContext()
|
||||
|
||||
// create client
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header)
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ func (chain *TestChain) updateClient(client *TestChain) {
|
|||
ctxTarget, client.ClientID, uint64(client.Header.SignedHeader.Header.Height), consensusState,
|
||||
)
|
||||
chain.App.IBCKeeper.ClientKeeper.SetClientState(
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header),
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
|
||||
)
|
||||
|
||||
// _, _, err := simapp.SignCheckDeliver(
|
||||
|
|
|
@ -165,7 +165,7 @@ func (chain *TestChain) CreateClient(client *TestChain) error {
|
|||
ctxTarget := chain.GetContext()
|
||||
|
||||
// create client
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header)
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ func (chain *TestChain) updateClient(client *TestChain) {
|
|||
ctxTarget, client.ClientID, client.Header.GetHeight(), consensusState,
|
||||
)
|
||||
chain.App.IBCKeeper.ClientKeeper.SetClientState(
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header),
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
|
||||
)
|
||||
|
||||
// _, _, err := simapp.SignCheckDeliver(
|
||||
|
|
|
@ -3,6 +3,7 @@ package exported
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
|
@ -21,6 +22,7 @@ type ClientState interface {
|
|||
GetLatestHeight() uint64
|
||||
IsFrozen() bool
|
||||
Validate() error
|
||||
GetProofSpecs() []*ics23.ProofSpec
|
||||
|
||||
// State verification functions
|
||||
|
||||
|
|
|
@ -38,12 +38,12 @@ func (suite *KeeperTestSuite) TestCreateClient() {
|
|||
i := i
|
||||
if tc.expPanic {
|
||||
suite.Require().Panics(func() {
|
||||
clientState, err := ibctmtypes.Initialize(tc.clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(tc.clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
suite.Require().NoError(err, "err on client state initialization")
|
||||
suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
|
||||
}, "Msg %d didn't panic: %s", i, tc.msg)
|
||||
} else {
|
||||
clientState, err := ibctmtypes.Initialize(tc.clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(tc.clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err, "errored on initialization")
|
||||
suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg)
|
||||
|
@ -80,7 +80,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
|||
expPass bool
|
||||
}{
|
||||
{"valid update", func() error {
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
|||
return nil
|
||||
}, false},
|
||||
{"invalid header", func() error {
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
},
|
||||
func() error {
|
||||
suite.consensusState.ValidatorSet = bothValSet
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
},
|
||||
func() error {
|
||||
suite.consensusState.ValidatorSet = bothValSet
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
ClientID: testClientID,
|
||||
},
|
||||
func() error {
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
testClientID = "gaia"
|
||||
testClientID = "gaiachain"
|
||||
testClientID2 = "ethbridge"
|
||||
testClientID3 = "ethermint"
|
||||
|
||||
|
@ -90,7 +90,7 @@ func TestKeeperTestSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func (suite *KeeperTestSuite) TestSetClientState() {
|
||||
clientState := ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{})
|
||||
clientState := ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs())
|
||||
suite.keeper.SetClientState(suite.ctx, clientState)
|
||||
|
||||
retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID)
|
||||
|
@ -121,9 +121,9 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() {
|
|||
|
||||
func (suite KeeperTestSuite) TestGetAllClients() {
|
||||
expClients := []exported.ClientState{
|
||||
ibctmtypes.NewClientState(testClientID2, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientID3, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientID2, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.NewClientState(testClientID3, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
}
|
||||
|
||||
for i := range expClients {
|
||||
|
@ -168,7 +168,7 @@ func (suite KeeperTestSuite) TestGetConsensusState() {
|
|||
|
||||
func (suite KeeperTestSuite) TestConsensusStateHelpers() {
|
||||
// initial setup
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState, err := ibctmtypes.Initialize(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.keeper.SetClientState(suite.ctx, clientState)
|
||||
|
|
|
@ -50,7 +50,7 @@ func TestValidateGenesis(t *testing.T) {
|
|||
name: "valid genesis",
|
||||
genState: types.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("chaindID", 10),
|
||||
},
|
||||
[]types.ClientConsensusStates{
|
||||
|
@ -71,7 +71,7 @@ func TestValidateGenesis(t *testing.T) {
|
|||
name: "invalid client",
|
||||
genState: types.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("chaindID", 0),
|
||||
},
|
||||
nil,
|
||||
|
@ -83,7 +83,7 @@ func TestValidateGenesis(t *testing.T) {
|
|||
name: "invalid consensus state",
|
||||
genState: types.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("chaindID", 10),
|
||||
},
|
||||
[]types.ClientConsensusStates{
|
||||
|
@ -104,7 +104,7 @@ func TestValidateGenesis(t *testing.T) {
|
|||
name: "invalid consensus state",
|
||||
genState: types.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("chaindID", 10),
|
||||
},
|
||||
[]types.ClientConsensusStates{
|
||||
|
|
|
@ -132,9 +132,9 @@ func (suite KeeperTestSuite) TestGetAllConnections() {
|
|||
|
||||
func (suite KeeperTestSuite) TestGetAllClientConnectionPaths() {
|
||||
clients := []clientexported.ClientState{
|
||||
ibctmtypes.NewClientState(testClientIDA, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientIDB, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientID3, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
ibctmtypes.NewClientState(testClientIDA, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.NewClientState(testClientIDB, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.NewClientState(testClientID3, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
}
|
||||
|
||||
for i := range clients {
|
||||
|
@ -264,7 +264,7 @@ func (chain *TestChain) CreateClient(client *TestChain) error {
|
|||
ctxTarget := chain.GetContext()
|
||||
|
||||
// create client
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header)
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ func (chain *TestChain) updateClient(client *TestChain) {
|
|||
ctxTarget, client.ClientID, client.Header.GetHeight(), consensusState,
|
||||
)
|
||||
chain.App.IBCKeeper.ClientKeeper.SetClientState(
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header),
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
|
||||
)
|
||||
|
||||
// _, _, err := simapp.SignCheckDeliver(
|
||||
|
|
|
@ -381,7 +381,7 @@ func (chain *TestChain) CreateClient(client *TestChain) error {
|
|||
ctxTarget := chain.GetContext()
|
||||
|
||||
// create client
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header)
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -449,7 +449,7 @@ func (chain *TestChain) updateClient(client *TestChain) {
|
|||
ctxTarget, client.ClientID, client.Header.GetHeight(), consensusState,
|
||||
)
|
||||
chain.App.IBCKeeper.ClientKeeper.SetClientState(
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header),
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
|
||||
)
|
||||
|
||||
// _, _, err := simapp.SignCheckDeliver(
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -25,9 +26,13 @@ import (
|
|||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
)
|
||||
|
||||
const flagTrustLevel = "trust-level"
|
||||
const (
|
||||
flagTrustLevel = "trust-level"
|
||||
flagProofSpecs = "proof-specs"
|
||||
)
|
||||
|
||||
// GetCmdCreateClient defines the command to create a new IBC Client as defined
|
||||
// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
|
||||
|
@ -35,7 +40,9 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
|
|||
cmd := &cobra.Command{
|
||||
Use: "create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift]",
|
||||
Short: "create new tendermint client",
|
||||
Long: "create new tendermint client. Trust level can be a fraction (eg: '1/3') or 'default'",
|
||||
Long: `Create a new tendermint IBC client.
|
||||
- 'trust-level' flag can be a fraction (eg: '1/3') or 'default'
|
||||
- 'proof-specs' flag can be a comma-separated list of strings (eg: 'ics23:simple,ics23:iavl') or 'default'`,
|
||||
Example: fmt.Sprintf("%s tx ibc %s create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --from node0 --home ../node0/<app>cli --chain-id $CID", version.ClientName, ibctmtypes.SubModuleName),
|
||||
Args: cobra.ExactArgs(5),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
@ -59,6 +66,7 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
|
|||
|
||||
var (
|
||||
trustLevel tmmath.Fraction
|
||||
specs []*ics23.ProofSpec
|
||||
err error
|
||||
)
|
||||
|
||||
|
@ -88,8 +96,20 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
spc := viper.GetString(flagProofSpecs)
|
||||
|
||||
// Currently supports SDK chain or simple kvstore tendermint chain
|
||||
switch spc {
|
||||
case "default":
|
||||
specs = commitmenttypes.GetSDKSpecs()
|
||||
case "simple":
|
||||
specs = []*ics23.ProofSpec{ics23.TendermintSpec}
|
||||
default:
|
||||
return fmt.Errorf("proof Spec: %s not supported", spc)
|
||||
}
|
||||
|
||||
msg := ibctmtypes.NewMsgCreateClient(
|
||||
clientID, header, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clientCtx.GetFromAddress(),
|
||||
clientID, header, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, specs, clientCtx.GetFromAddress(),
|
||||
)
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
|
@ -100,6 +120,7 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
cmd.Flags().String(flagTrustLevel, "default", "light client trust level fraction for header updates")
|
||||
cmd.Flags().String(flagProofSpecs, "default", "proof specs format to be used for verification")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package rest
|
|||
import (
|
||||
"time"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
tmmath "github.com/tendermint/tendermint/libs/math"
|
||||
|
@ -34,6 +35,7 @@ type CreateClientReq struct {
|
|||
TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"`
|
||||
UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"`
|
||||
MaxClockDrift time.Duration `json:"max_clock_drift" yaml:"max_clock_drift"`
|
||||
ProofSpecs []*ics23.ProofSpec `json:"proof_specs" yaml:"proof_specs"`
|
||||
}
|
||||
|
||||
// UpdateClientReq defines the properties of a update client request's body.
|
||||
|
|
|
@ -52,7 +52,7 @@ func createClientHandlerFn(clientCtx client.Context) http.HandlerFunc {
|
|||
msg := ibctmtypes.NewMsgCreateClient(
|
||||
req.ClientID, req.Header, req.TrustLevel,
|
||||
req.TrustingPeriod, req.UnbondingPeriod, req.MaxClockDrift,
|
||||
fromAddr,
|
||||
req.ProofSpecs, fromAddr,
|
||||
)
|
||||
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
|
|
|
@ -49,7 +49,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
}{
|
||||
{
|
||||
"valid misbehavior evidence",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
||||
|
@ -62,7 +62,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"valid misbehavior at height greater than last consensusState",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
||||
|
@ -75,7 +75,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"consensus state's valset hash different from evidence should still pass",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
||||
|
@ -88,7 +88,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"first valset has too much change",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
||||
|
@ -101,7 +101,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"second valset has too much change",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothSigners),
|
||||
|
@ -114,7 +114,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"both valsets have too much change",
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet},
|
||||
ibctmtypes.Evidence{
|
||||
Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altSigners),
|
||||
|
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
"time"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
tmmath "github.com/tendermint/tendermint/libs/math"
|
||||
lite "github.com/tendermint/tendermint/lite2"
|
||||
|
||||
|
@ -46,6 +47,8 @@ type ClientState struct {
|
|||
|
||||
// Last Header that was stored by client
|
||||
LastHeader Header `json:"last_header" yaml:"last_header"`
|
||||
|
||||
ProofSpecs []*ics23.ProofSpec `json:"proof_specs" yaml:"proof_specs"`
|
||||
}
|
||||
|
||||
// InitializeFromMsg creates a tendermint client state from a CreateClientMsg
|
||||
|
@ -53,7 +56,7 @@ func InitializeFromMsg(msg MsgCreateClient) (ClientState, error) {
|
|||
return Initialize(
|
||||
msg.GetClientID(), msg.TrustLevel,
|
||||
msg.TrustingPeriod, msg.UnbondingPeriod, msg.MaxClockDrift,
|
||||
msg.Header,
|
||||
msg.Header, msg.ProofSpecs,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -62,17 +65,10 @@ func InitializeFromMsg(msg MsgCreateClient) (ClientState, error) {
|
|||
func Initialize(
|
||||
id string, trustLevel tmmath.Fraction,
|
||||
trustingPeriod, ubdPeriod, maxClockDrift time.Duration,
|
||||
header Header,
|
||||
header Header, specs []*ics23.ProofSpec,
|
||||
) (ClientState, error) {
|
||||
clientState := NewClientState(id, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header, specs)
|
||||
|
||||
if trustingPeriod >= ubdPeriod {
|
||||
return ClientState{}, sdkerrors.Wrapf(
|
||||
ErrInvalidTrustingPeriod,
|
||||
"trusting period (%s) should be < unbonding period (%s)", trustingPeriod, ubdPeriod,
|
||||
)
|
||||
}
|
||||
|
||||
clientState := NewClientState(id, trustLevel, trustingPeriod, ubdPeriod, maxClockDrift, header)
|
||||
return clientState, nil
|
||||
}
|
||||
|
||||
|
@ -80,7 +76,7 @@ func Initialize(
|
|||
func NewClientState(
|
||||
id string, trustLevel tmmath.Fraction,
|
||||
trustingPeriod, ubdPeriod, maxClockDrift time.Duration,
|
||||
header Header,
|
||||
header Header, specs []*ics23.ProofSpec,
|
||||
) ClientState {
|
||||
return ClientState{
|
||||
ID: id,
|
||||
|
@ -90,6 +86,7 @@ func NewClientState(
|
|||
MaxClockDrift: maxClockDrift,
|
||||
LastHeader: header,
|
||||
FrozenHeight: 0,
|
||||
ProofSpecs: specs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,9 +140,31 @@ func (cs ClientState) Validate() error {
|
|||
if cs.MaxClockDrift == 0 {
|
||||
return sdkerrors.Wrap(ErrInvalidMaxClockDrift, "max clock drift cannot be zero")
|
||||
}
|
||||
if cs.TrustingPeriod >= cs.UnbondingPeriod {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrInvalidTrustingPeriod,
|
||||
"trusting period (%s) should be < unbonding period (%s)", cs.TrustingPeriod, cs.UnbondingPeriod,
|
||||
)
|
||||
}
|
||||
// Validate ProofSpecs
|
||||
if cs.ProofSpecs == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil for tm client")
|
||||
}
|
||||
for _, spec := range cs.ProofSpecs {
|
||||
if spec == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof spec cannot be nil")
|
||||
}
|
||||
}
|
||||
|
||||
return cs.LastHeader.ValidateBasic(cs.GetChainID())
|
||||
}
|
||||
|
||||
// GetProofSpecs returns the format the client expects for proof verification
|
||||
// as a string array specifying the proof type for each position in chained proof
|
||||
func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec {
|
||||
return cs.ProofSpecs
|
||||
}
|
||||
|
||||
// VerifyClientConsensusState verifies a proof of the consensus state of the
|
||||
// Tendermint client stored on the target machine.
|
||||
func (cs ClientState) VerifyClientConsensusState(
|
||||
|
@ -176,7 +195,7 @@ func (cs ClientState) VerifyClientConsensusState(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyMembership(provingRoot, path, bz); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, provingRoot, path, bz); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedClientConsensusStateVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -215,7 +234,7 @@ func (cs ClientState) VerifyConnectionState(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedConnectionStateVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -255,7 +274,7 @@ func (cs ClientState) VerifyChannelState(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedChannelStateVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -286,7 +305,7 @@ func (cs ClientState) VerifyPacketCommitment(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyMembership(consensusState.GetRoot(), path, commitmentBytes); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, commitmentBytes); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedPacketCommitmentVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -317,7 +336,7 @@ func (cs ClientState) VerifyPacketAcknowledgement(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyMembership(consensusState.GetRoot(), path, channeltypes.CommitAcknowledgement(acknowledgement)); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, channeltypes.CommitAcknowledgement(acknowledgement)); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -348,7 +367,7 @@ func (cs ClientState) VerifyPacketAcknowledgementAbsence(
|
|||
return err
|
||||
}
|
||||
|
||||
if err := merkleProof.VerifyNonMembership(consensusState.GetRoot(), path); err != nil {
|
||||
if err := merkleProof.VerifyNonMembership(cs.ProofSpecs, consensusState.GetRoot(), path); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckAbsenceVerification, err.Error())
|
||||
}
|
||||
|
||||
|
@ -380,7 +399,7 @@ func (cs ClientState) VerifyNextSequenceRecv(
|
|||
|
||||
bz := sdk.Uint64ToBigEndian(nextSequenceRecv)
|
||||
|
||||
if err := merkleProof.VerifyMembership(consensusState.GetRoot(), path, bz); err != nil {
|
||||
if err := merkleProof.VerifyMembership(cs.ProofSpecs, consensusState.GetRoot(), path, bz); err != nil {
|
||||
return sdkerrors.Wrap(clienttypes.ErrFailedNextSeqRecvVerification, err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -27,37 +27,37 @@ func (suite *TendermintTestSuite) TestValidate() {
|
|||
}{
|
||||
{
|
||||
name: "valid client",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
name: "invalid client id",
|
||||
clientState: ibctmtypes.NewClientState("(testClientID)", lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState("(testClientID)", lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid trust level",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, tmmath.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, tmmath.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid trusting period",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid unbonding period",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid max clock drift",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, 0, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "invalid header",
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}),
|
||||
clientState: ibctmtypes.NewClientState(testClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, ibctmtypes.Header{}, commitmenttypes.GetSDKSpecs()),
|
||||
expPass: false,
|
||||
},
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
// },
|
||||
|
@ -93,7 +93,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -102,7 +102,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -120,7 +120,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
ValidatorSet: suite.valSet,
|
||||
|
@ -162,7 +162,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -172,7 +172,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
connection: conn,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -182,7 +182,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
connection: conn,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -202,7 +202,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
connection: conn,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -245,7 +245,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -255,7 +255,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
channel: ch,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -265,7 +265,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
channel: ch,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -285,7 +285,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
channel: ch,
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -325,7 +325,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -335,7 +335,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
commitment: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -345,7 +345,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
commitment: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -365,7 +365,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
commitment: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -405,7 +405,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -415,7 +415,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ack: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -425,7 +425,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ack: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -445,7 +445,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
ack: []byte{},
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -484,7 +484,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -494,7 +494,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -503,7 +503,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -521,7 +521,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
ValidatorSet: suite.valSet,
|
||||
|
@ -559,7 +559,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
|
|||
// FIXME: uncomment
|
||||
// {
|
||||
// name: "successful verification",
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height),
|
||||
// clientState: ibctmtypes.NewClientState(chainID, chainID, height, commitmenttypes.GetSDKSpecs()),
|
||||
// connection: conn,
|
||||
// consensusState: ibctmtypes.ConsensusState{
|
||||
// Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
|
@ -569,7 +569,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
|
|||
// },
|
||||
{
|
||||
name: "ApplyPrefix failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -578,7 +578,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
|
|||
},
|
||||
{
|
||||
name: "latest client height < height",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
},
|
||||
|
@ -596,7 +596,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() {
|
|||
},
|
||||
{
|
||||
name: "proof verification failed",
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
clientState: ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
consensusState: ibctmtypes.ConsensusState{
|
||||
Root: commitmenttypes.NewMerkleRoot(suite.header.AppHash),
|
||||
ValidatorSet: suite.valSet,
|
||||
|
|
|
@ -16,4 +16,5 @@ var (
|
|||
ErrInvalidMaxClockDrift = sdkerrors.Register(SubModuleName, 5, "invalid max clock drift")
|
||||
ErrTrustingPeriodExpired = sdkerrors.Register(SubModuleName, 6, "time since latest trusted state has passed the trusting period")
|
||||
ErrUnbondingPeriodExpired = sdkerrors.Register(SubModuleName, 7, "time since latest trusted state has passed the unbonding period")
|
||||
ErrInvalidProofSpecs = sdkerrors.Register(SubModuleName, 8, "invalid proof specs")
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ package types
|
|||
import (
|
||||
"time"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
tmmath "github.com/tendermint/tendermint/libs/math"
|
||||
lite "github.com/tendermint/tendermint/lite2"
|
||||
|
||||
|
@ -36,6 +37,7 @@ type MsgCreateClient struct {
|
|||
TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"`
|
||||
UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"`
|
||||
MaxClockDrift time.Duration `json:"max_clock_drift" yaml:"max_clock_drift"`
|
||||
ProofSpecs []*ics23.ProofSpec `json:"proof_specs" yaml:"proof_specs"`
|
||||
Signer sdk.AccAddress `json:"address" yaml:"address"`
|
||||
}
|
||||
|
||||
|
@ -50,7 +52,8 @@ func (msg MsgCreateClient) ProtoMessage() {}
|
|||
// NewMsgCreateClient creates a new MsgCreateClient instance
|
||||
func NewMsgCreateClient(
|
||||
id string, header Header, trustLevel tmmath.Fraction,
|
||||
trustingPeriod, unbondingPeriod, maxClockDrift time.Duration, signer sdk.AccAddress,
|
||||
trustingPeriod, unbondingPeriod, maxClockDrift time.Duration,
|
||||
specs []*ics23.ProofSpec, signer sdk.AccAddress,
|
||||
) MsgCreateClient {
|
||||
|
||||
return MsgCreateClient{
|
||||
|
@ -60,6 +63,7 @@ func NewMsgCreateClient(
|
|||
TrustingPeriod: trustingPeriod,
|
||||
UnbondingPeriod: unbondingPeriod,
|
||||
MaxClockDrift: maxClockDrift,
|
||||
ProofSpecs: specs,
|
||||
Signer: signer,
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +99,21 @@ func (msg MsgCreateClient) ValidateBasic() error {
|
|||
if err := msg.Header.ValidateBasic(msg.Header.ChainID); err != nil {
|
||||
return sdkerrors.Wrapf(ErrInvalidHeader, "header failed validatebasic with its own chain-id: %v", err)
|
||||
}
|
||||
if msg.TrustingPeriod >= msg.UnbondingPeriod {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrInvalidTrustingPeriod,
|
||||
"trusting period (%s) should be < unbonding period (%s)", msg.TrustingPeriod, msg.UnbondingPeriod,
|
||||
)
|
||||
}
|
||||
// Validate ProofSpecs
|
||||
if msg.ProofSpecs == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof specs cannot be nil")
|
||||
}
|
||||
for _, spec := range msg.ProofSpecs {
|
||||
if spec == nil {
|
||||
return sdkerrors.Wrap(ErrInvalidProofSpecs, "proof spec cannot be nil")
|
||||
}
|
||||
}
|
||||
return host.ClientIdentifierValidator(msg.ClientID)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package types_test
|
||||
|
||||
import (
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"github.com/tendermint/tendermint/libs/math"
|
||||
lite "github.com/tendermint/tendermint/lite2"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
|
||||
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
)
|
||||
|
||||
func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() {
|
||||
|
@ -22,14 +24,15 @@ func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() {
|
|||
expPass bool
|
||||
errMsg string
|
||||
}{
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, signer), true, "success msg should pass"},
|
||||
{ibctmtypes.NewMsgCreateClient("(BADCHAIN)", suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, signer), false, "invalid client id passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, math.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, signer), false, "invalid trust level"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, signer), false, "zero trusting period passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, signer), false, "zero unbonding period passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, nil), false, "Empty address passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, signer), false, "nil header"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, invalidHeader, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, signer), false, "invalid header"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), true, "success msg should pass"},
|
||||
{ibctmtypes.NewMsgCreateClient("(BADCHAIN)", suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid client id passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, math.Fraction{Numerator: 0, Denominator: 1}, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid trust level"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, 0, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero trusting period passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, 0, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "zero unbonding period passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), nil), false, "Empty address passed"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, ibctmtypes.Header{}, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "nil header"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, invalidHeader, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, commitmenttypes.GetSDKSpecs(), signer), false, "invalid header"},
|
||||
{ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, []*ics23.ProofSpec{nil}, signer), false, "invalid proof specs"},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
|
|
|
@ -54,7 +54,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "successful update with next height and same validator set",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -63,7 +63,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "successful update with future height and different validator set",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, bothValSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -72,7 +72,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "unsuccessful update with next height: update header mismatches nextValSetHash",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -81,7 +81,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "unsuccessful update with future height: too much change in validator set",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, altValSet, altSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -90,7 +90,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "unsuccessful update: trusting period has passed since last client timestamp",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
||||
// make current time pass trusting period from last timestamp on clientstate
|
||||
currentTime = suite.now.Add(ubdPeriod)
|
||||
|
@ -100,7 +100,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "unsuccessful update: header timestamp is past current timestamp",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.now.Add(time.Minute), suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -109,7 +109,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "unsuccessful update: header timestamp is not past last client timestamp",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.clientTime, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
|
@ -118,7 +118,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "header basic validation failed",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, signers)
|
||||
// cause new header to fail validatebasic by changing commit height to mismatch header height
|
||||
newHeader.SignedHeader.Commit.Height = height - 1
|
||||
|
@ -129,7 +129,7 @@ func (suite *TendermintTestSuite) TestCheckValidity() {
|
|||
{
|
||||
name: "header height < latest client height",
|
||||
setup: func() {
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header)
|
||||
clientState = ibctmtypes.NewClientState(chainID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs())
|
||||
// Make new header at height less than latest client state
|
||||
newHeader = ibctmtypes.CreateTestHeader(chainID, height-1, suite.headerTime, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
@ -74,6 +75,11 @@ func (cs ClientState) Validate() error {
|
|||
return host.ClientIdentifierValidator(cs.ID)
|
||||
}
|
||||
|
||||
// GetProofSpecs returns nil since localhost does not have to verify proofs
|
||||
func (cs ClientState) GetProofSpecs() []*ics23.ProofSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyClientConsensusState verifies a proof of the consensus
|
||||
// state of the loop-back client.
|
||||
// VerifyClientConsensusState verifies a proof of the consensus state of the
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package exported
|
||||
|
||||
import ics23 "github.com/confio/ics23/go"
|
||||
|
||||
// ICS 023 Types Implementation
|
||||
//
|
||||
// This file includes types defined under
|
||||
|
@ -39,8 +41,8 @@ type Path interface {
|
|||
// Proofs includes key but value is provided dynamically at the verification time.
|
||||
type Proof interface {
|
||||
GetCommitmentType() Type
|
||||
VerifyMembership(Root, Path, []byte) error
|
||||
VerifyNonMembership(Root, Path) error
|
||||
VerifyMembership([]*ics23.ProofSpec, Root, Path, []byte) error
|
||||
VerifyNonMembership([]*ics23.ProofSpec, Root, Path) error
|
||||
Empty() bool
|
||||
|
||||
ValidateBasic() error
|
||||
|
|
|
@ -26,3 +26,15 @@ func (pth *KeyPath) String() string {
|
|||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// GetKey returns the bytes representation of key at given index
|
||||
// Passing in a positive index return the key at index in forward order
|
||||
// from the highest key to the lowest key
|
||||
// Passing in a negative index will return the key at index in reverse order
|
||||
// from the lowest key to the highest key. This is the order for proof verification,
|
||||
// since we prove lowest key first before moving to key of higher subtrees
|
||||
func (pth *KeyPath) GetKey(i int) []byte {
|
||||
total := len(pth.Keys)
|
||||
index := (total + i) % total
|
||||
return pth.Keys[index].name
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/url"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/rootmulti"
|
||||
ics23 "github.com/confio/ics23/go"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
|
||||
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
||||
|
@ -11,6 +12,9 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
)
|
||||
|
||||
// var representing the proofspecs for a SDK chain
|
||||
var sdkSpecs = []*ics23.ProofSpec{ics23.IavlSpec, ics23.TendermintSpec}
|
||||
|
||||
// ICS 023 Merkle Types Implementation
|
||||
//
|
||||
// This file defines Merkle commitment types that implements ICS 023.
|
||||
|
@ -19,6 +23,11 @@ import (
|
|||
// Applied on SDK-based IBC implementation
|
||||
var _ exported.Root = (*MerkleRoot)(nil)
|
||||
|
||||
// GetSDKSpecs is a getter function for the proofspecs of an sdk chain
|
||||
func GetSDKSpecs() []*ics23.ProofSpec {
|
||||
return sdkSpecs
|
||||
}
|
||||
|
||||
// NewMerkleRoot constructs a new MerkleRoot
|
||||
func NewMerkleRoot(hash []byte) MerkleRoot {
|
||||
return MerkleRoot{
|
||||
|
@ -128,23 +137,230 @@ func (MerkleProof) GetCommitmentType() exported.Type {
|
|||
}
|
||||
|
||||
// VerifyMembership verifies the membership pf a merkle proof against the given root, path, and value.
|
||||
func (proof MerkleProof) VerifyMembership(root exported.Root, path exported.Path, value []byte) error {
|
||||
if proof.Empty() || root == nil || root.Empty() || path == nil || path.Empty() || len(value) == 0 {
|
||||
return sdkerrors.Wrap(ErrInvalidMerkleProof, "empty params or proof")
|
||||
func (proof MerkleProof) VerifyMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, value []byte) error {
|
||||
if err := proof.validateVerificationArgs(specs, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime := rootmulti.DefaultProofRuntime()
|
||||
return runtime.VerifyValue(proof.Proof, root.GetHash(), path.String(), value)
|
||||
// VerifyMembership specific argument validation
|
||||
mpath, ok := path.(MerklePath)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
|
||||
}
|
||||
if len(mpath.KeyPath.Keys) != len(specs) {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
|
||||
len(mpath.KeyPath.Keys), len(specs))
|
||||
}
|
||||
if len(value) == 0 {
|
||||
return sdkerrors.Wrap(ErrInvalidProof, "empty value in membership proof")
|
||||
}
|
||||
|
||||
// Convert Proof to []CommitmentProof
|
||||
proofs, err := convertProofs(proof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since every proof in chain is a membership proof we can chain from index 0
|
||||
if err := verifyChainedMembershipProof(root.GetHash(), specs, proofs, mpath.KeyPath, value, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyNonMembership verifies the absence of a merkle proof against the given root and path.
|
||||
func (proof MerkleProof) VerifyNonMembership(root exported.Root, path exported.Path) error {
|
||||
if proof.Empty() || root == nil || root.Empty() || path == nil || path.Empty() {
|
||||
return sdkerrors.Wrap(ErrInvalidMerkleProof, "empty params or proof")
|
||||
// VerifyNonMembership verifies a chained proof where the absence of a given path is proven
|
||||
// at the lowest subtree and then each subtree's inclusion is proved up to the final root.
|
||||
func (proof MerkleProof) VerifyNonMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path) error {
|
||||
if err := proof.validateVerificationArgs(specs, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime := rootmulti.DefaultProofRuntime()
|
||||
return runtime.VerifyAbsence(proof.Proof, root.GetHash(), path.String())
|
||||
// VerifyNonMembership specific argument validation
|
||||
mpath, ok := path.(MerklePath)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
|
||||
}
|
||||
if len(mpath.KeyPath.Keys) != len(specs) {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
|
||||
len(mpath.KeyPath.Keys), len(specs))
|
||||
}
|
||||
|
||||
// Convert Proof to []CommitmentProof
|
||||
proofs, err := convertProofs(proof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs
|
||||
// of all subroots up to final root
|
||||
subroot, err := proofs[0].Calculate()
|
||||
if err != nil {
|
||||
sdkerrors.Wrapf(ErrInvalidProof, "could not calculate root for proof index 0. %v", err)
|
||||
}
|
||||
key := mpath.KeyPath.GetKey(-1)
|
||||
if ok := ics23.VerifyNonMembership(specs[0], subroot, proofs[0], key); !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "could not verify absence of key %s", string(key))
|
||||
}
|
||||
|
||||
// Verify chained membership proof starting from index 1 with value = subroot
|
||||
if err := verifyChainedMembershipProof(root.GetHash(), specs, proofs, mpath.KeyPath, subroot, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchVerifyMembership verifies a group of key value pairs against the given root
|
||||
// NOTE: All items must be part of a batch proof in the first chained proof, i.e. items must all be part of smallest subtree in the chained proof
|
||||
// NOTE: The path passed in must be the path from the root to the smallest subtree in the chained proof
|
||||
// NOTE: Untested
|
||||
func (proof MerkleProof) BatchVerifyMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, items map[string][]byte) error {
|
||||
if err := proof.validateVerificationArgs(specs, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert Proof to []CommitmentProof
|
||||
proofs, err := convertProofs(proof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs
|
||||
// of all subroots up to final root
|
||||
subroot, err := proofs[0].Calculate()
|
||||
if err != nil {
|
||||
sdkerrors.Wrapf(ErrInvalidProof, "could not calculate root for proof index 0. %v", err)
|
||||
}
|
||||
if ok := ics23.BatchVerifyMembership(specs[0], subroot, proofs[0], items); !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "could not verify batch items")
|
||||
}
|
||||
|
||||
// BatchVerifyMembership specific argument validation
|
||||
// Path must only be defined if this is a chained proof
|
||||
if len(specs) > 1 {
|
||||
mpath, ok := path.(MerklePath)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
|
||||
}
|
||||
// path length should be one less than specs, since lowest proof keys are in items
|
||||
if len(mpath.KeyPath.Keys) != len(specs)-1 {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
|
||||
len(mpath.KeyPath.Keys), len(specs))
|
||||
}
|
||||
|
||||
// Since BatchedProof path does not include lowest subtree, exclude first proof from specs and proofs and start
|
||||
// chaining at index 0
|
||||
if err := verifyChainedMembershipProof(root.GetHash(), specs[1:], proofs[1:], mpath.KeyPath, subroot, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !bytes.Equal(root.GetHash(), subroot) {
|
||||
// Since we are not chaining proofs, we must check first subroot equals given root
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "batched proof did not commit to expected root: %X, got: %X", root.GetHash(), subroot)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchVerifyNonMembership verifies absence of a group of keys against the given root
|
||||
// NOTE: All items must be part of a batch proof in the first chained proof, i.e. items must all be part of smallest subtree in the chained proof
|
||||
// NOTE: The path passed in must be the path from the root to the smallest subtree in the chained proof
|
||||
// NOTE: Untested
|
||||
func (proof MerkleProof) BatchVerifyNonMembership(specs []*ics23.ProofSpec, root exported.Root, path exported.Path, items [][]byte) error {
|
||||
if err := proof.validateVerificationArgs(specs, root); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Convert Proof to []CommitmentProof
|
||||
proofs, err := convertProofs(proof)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs
|
||||
// of all subroots up to final root
|
||||
subroot, err := proofs[0].Calculate()
|
||||
if err != nil {
|
||||
sdkerrors.Wrapf(ErrInvalidProof, "could not calculate root for proof index 0. %v", err)
|
||||
}
|
||||
if ok := ics23.BatchVerifyNonMembership(specs[0], subroot, proofs[0], items); !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "could not verify batch items")
|
||||
}
|
||||
|
||||
// BatchVerifyNonMembership specific argument validation
|
||||
// Path must only be defined if this is a chained proof
|
||||
if len(specs) > 1 {
|
||||
mpath, ok := path.(MerklePath)
|
||||
if !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path %v is not of type MerkleProof", path)
|
||||
}
|
||||
// path length should be one less than specs, since lowest proof keys are in items
|
||||
if len(mpath.KeyPath.Keys) != len(specs)-1 {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "path length %d not same as proof %d",
|
||||
len(mpath.KeyPath.Keys), len(specs))
|
||||
}
|
||||
|
||||
// Since BatchedProof path does not include lowest subtree, exclude first proof from specs and proofs and start
|
||||
// chaining at index 0
|
||||
if err := verifyChainedMembershipProof(root.GetHash(), specs[1:], proofs[1:], mpath.KeyPath, subroot, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if !bytes.Equal(root.GetHash(), subroot) {
|
||||
// Since we are not chaining proofs, we must check first subroot equals given root
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "batched proof did not commit to expected root: %X, got: %X", root.GetHash(), subroot)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyChainedMembershipProof takes a list of proofs and specs and verifies each proof sequentially ensuring that the value is committed to
|
||||
// by first proof and each subsequent subroot is committed to by the next subroot and checking that the final calculated root is equal to the given roothash.
|
||||
// The proofs and specs are passed in from lowest subtree to the highest subtree, but the keys are passed in from highest subtree to lowest.
|
||||
// The index specifies what index to start chaining the membership proofs, this is useful since the lowest proof may not be a membership proof, thus we
|
||||
// will want to start the membership proof chaining from index 1 with value being the lowest subroot
|
||||
func verifyChainedMembershipProof(root []byte, specs []*ics23.ProofSpec, proofs []*ics23.CommitmentProof, keys KeyPath, value []byte, index int) error {
|
||||
var (
|
||||
subroot []byte
|
||||
err error
|
||||
)
|
||||
// Initialize subroot to value since the proofs list may be empty.
|
||||
// This may happen if this call is verifying intermediate proofs after the lowest proof has been executed.
|
||||
// In this case, there may be no intermediate proofs to verify and we just check that lowest proof root equals final root
|
||||
subroot = value
|
||||
for i := index; i < len(proofs); i++ {
|
||||
subroot, err = proofs[i].Calculate()
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "could not calculate proof root at index %d. %v", i, err)
|
||||
}
|
||||
// Since keys are passed in from highest to lowest, we must grab their indices in reverse order
|
||||
// from the proofs and specs which are lowest to highest
|
||||
key := keys.GetKey(-1 * (i + 1))
|
||||
if ok := ics23.VerifyMembership(specs[i], subroot, proofs[i], key, value); !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "chained membership proof failed to verify membership of value: %X in subroot %X at index %d",
|
||||
value, subroot, i)
|
||||
}
|
||||
// Set value to subroot so that we verify next proof in chain commits to this subroot
|
||||
value = subroot
|
||||
}
|
||||
// Check that chained proof root equals passed-in root
|
||||
if !bytes.Equal(root, subroot) {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "proof did not commit to expected root: %X, got: %X", root, subroot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertProofs converts a MerkleProof into []*ics23.CommitmentProof
|
||||
func convertProofs(mproof MerkleProof) ([]*ics23.CommitmentProof, error) {
|
||||
// Unmarshal all proof ops to CommitmentProof
|
||||
proofs := make([]*ics23.CommitmentProof, len(mproof.Proof.Ops))
|
||||
for i, op := range mproof.Proof.Ops {
|
||||
var p ics23.CommitmentProof
|
||||
err := p.Unmarshal(op.Data)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(ErrInvalidMerkleProof, "could not unmarshal proof op into CommitmentProof at index: %d", i)
|
||||
}
|
||||
proofs[i] = &p
|
||||
}
|
||||
return proofs, nil
|
||||
}
|
||||
|
||||
// Empty returns true if the root is empty
|
||||
|
@ -159,3 +375,23 @@ func (proof MerkleProof) ValidateBasic() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateVerificationArgs verifies the proof arguments are valid
|
||||
func (proof MerkleProof) validateVerificationArgs(specs []*ics23.ProofSpec, root exported.Root) error {
|
||||
if proof.Empty() || root == nil || root.Empty() {
|
||||
return sdkerrors.Wrap(ErrInvalidMerkleProof, "empty params or proof")
|
||||
}
|
||||
|
||||
if len(specs) != len(proof.Proof.Ops) {
|
||||
return sdkerrors.Wrapf(ErrInvalidMerkleProof,
|
||||
"length of specs: %d not equal to length of proof: %d",
|
||||
len(specs), len(proof.Proof.Ops))
|
||||
}
|
||||
|
||||
for i, spec := range specs {
|
||||
if spec == nil {
|
||||
return sdkerrors.Wrapf(ErrInvalidProof, "spec at position %d is nil", i)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto/merkle"
|
||||
)
|
||||
|
||||
func (suite *MerkleTestSuite) TestVerifyMembership() {
|
||||
|
@ -33,27 +34,38 @@ func (suite *MerkleTestSuite) TestVerifyMembership() {
|
|||
root []byte
|
||||
pathArr []string
|
||||
value []byte
|
||||
malleate func()
|
||||
shouldPass bool
|
||||
}{
|
||||
{"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), true}, // valid proof
|
||||
{"wrong value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("WRONGVALUE"), false}, // invalid proof with wrong value
|
||||
{"nil value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte(nil), false}, // invalid proof with nil value
|
||||
{"wrong key", cid.Hash, []string{suite.storeKey.Name(), "NOTMYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong key
|
||||
{"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path
|
||||
{"wrong path 2", cid.Hash, []string{suite.storeKey.Name()}, []byte("MYVALUE"), false}, // invalid proof with wrong path
|
||||
{"wrong path 3", cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong path
|
||||
{"wrong storekey", cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong store prefix
|
||||
{"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with wrong root
|
||||
{"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), false}, // invalid proof with nil root
|
||||
{"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), func() {}, true}, // valid proof
|
||||
{"wrong value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("WRONGVALUE"), func() {}, false}, // invalid proof with wrong value
|
||||
{"nil value", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte(nil), func() {}, false}, // invalid proof with nil value
|
||||
{"wrong key", cid.Hash, []string{suite.storeKey.Name(), "NOTMYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong key
|
||||
{"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong path 2", cid.Hash, []string{suite.storeKey.Name()}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong path 3", cid.Hash, []string{"MYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong storekey", cid.Hash, []string{"otherStoreKey", "MYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong store prefix
|
||||
{"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with wrong root
|
||||
{"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), func() {}, false}, // invalid proof with nil root
|
||||
{"proof is wrong length", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, []byte("MYVALUE"), func() {
|
||||
proof = types.MerkleProof{
|
||||
Proof: &merkle.Proof{
|
||||
Ops: res.Proof.Ops[1:],
|
||||
},
|
||||
}
|
||||
}, false}, // invalid proof with wrong length
|
||||
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
tc := tc
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
root := types.NewMerkleRoot(tc.root)
|
||||
path := types.NewMerklePath(tc.pathArr)
|
||||
|
||||
err := proof.VerifyMembership(&root, path, tc.value)
|
||||
err := proof.VerifyMembership(types.GetSDKSpecs(), &root, path, tc.value)
|
||||
|
||||
if tc.shouldPass {
|
||||
// nolint: scopelint
|
||||
|
@ -88,27 +100,38 @@ func (suite *MerkleTestSuite) TestVerifyNonMembership() {
|
|||
name string
|
||||
root []byte
|
||||
pathArr []string
|
||||
malleate func()
|
||||
shouldPass bool
|
||||
}{
|
||||
{"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY"}, true}, // valid proof
|
||||
{"wrong key", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, false}, // invalid proof with existent key
|
||||
{"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYABSENTKEY"}, false}, // invalid proof with wrong path
|
||||
{"wrong path 2", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY", "MYKEY"}, false}, // invalid proof with wrong path
|
||||
{"wrong path 3", cid.Hash, []string{suite.storeKey.Name()}, false}, // invalid proof with wrong path
|
||||
{"wrong path 4", cid.Hash, []string{"MYABSENTKEY"}, false}, // invalid proof with wrong path
|
||||
{"wrong storeKey", cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, false}, // invalid proof with wrong store prefix
|
||||
{"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with wrong root
|
||||
{"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYABSENTKEY"}, false}, // invalid proof with nil root
|
||||
{"valid proof", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY"}, func() {}, true}, // valid proof
|
||||
{"wrong key", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, func() {}, false}, // invalid proof with existent key
|
||||
{"wrong path 1", cid.Hash, []string{suite.storeKey.Name(), "MYKEY", "MYABSENTKEY"}, func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong path 2", cid.Hash, []string{suite.storeKey.Name(), "MYABSENTKEY", "MYKEY"}, func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong path 3", cid.Hash, []string{suite.storeKey.Name()}, func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong path 4", cid.Hash, []string{"MYABSENTKEY"}, func() {}, false}, // invalid proof with wrong path
|
||||
{"wrong storeKey", cid.Hash, []string{"otherStoreKey", "MYABSENTKEY"}, func() {}, false}, // invalid proof with wrong store prefix
|
||||
{"wrong root", []byte("WRONGROOT"), []string{suite.storeKey.Name(), "MYABSENTKEY"}, func() {}, false}, // invalid proof with wrong root
|
||||
{"nil root", []byte(nil), []string{suite.storeKey.Name(), "MYABSENTKEY"}, func() {}, false}, // invalid proof with nil root
|
||||
{"proof is wrong length", cid.Hash, []string{suite.storeKey.Name(), "MYKEY"}, func() {
|
||||
proof = types.MerkleProof{
|
||||
Proof: &merkle.Proof{
|
||||
Ops: res.Proof.Ops[1:],
|
||||
},
|
||||
}
|
||||
}, false}, // invalid proof with wrong length
|
||||
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
tc := tc
|
||||
|
||||
suite.Run(tc.name, func() {
|
||||
tc.malleate()
|
||||
|
||||
root := types.NewMerkleRoot(tc.root)
|
||||
path := types.NewMerklePath(tc.pathArr)
|
||||
|
||||
err := proof.VerifyNonMembership(&root, path)
|
||||
err := proof.VerifyNonMembership(types.GetSDKSpecs(), &root, path)
|
||||
|
||||
if tc.shouldPass {
|
||||
// nolint: scopelint
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package commitment
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
|
||||
)
|
||||
|
||||
// CalculateRoot returns the application Hash at the curretn block height as a commitment
|
||||
// root for proof verification.
|
||||
func CalculateRoot(ctx sdk.Context) exported.Root {
|
||||
root := types.NewMerkleRoot(ctx.BlockHeader().AppHash)
|
||||
return &root
|
||||
}
|
||||
|
||||
// BatchVerifyMembership verifies a proof that many paths have been set to
|
||||
// specific values in a commitment. It calls the proof's VerifyMembership method
|
||||
// with the calculated root and the provided paths.
|
||||
// Returns false on the first failed membership verification.
|
||||
func BatchVerifyMembership(
|
||||
ctx sdk.Context,
|
||||
proof exported.Proof,
|
||||
prefix exported.Prefix,
|
||||
items map[string][]byte,
|
||||
) error {
|
||||
root := CalculateRoot(ctx)
|
||||
|
||||
for pathStr, value := range items {
|
||||
path, err := types.ApplyPrefix(prefix, pathStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := proof.VerifyMembership(root, path, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BatchVerifyNonMembership verifies a proof that many paths have not been set
|
||||
// to any value in a commitment. It calls the proof's VerifyNonMembership method
|
||||
// with the calculated root and the provided paths.
|
||||
// Returns false on the first failed non-membership verification.
|
||||
func BatchVerifyNonMembership(
|
||||
ctx sdk.Context,
|
||||
proof exported.Proof,
|
||||
prefix exported.Prefix,
|
||||
paths []string,
|
||||
) error {
|
||||
root := CalculateRoot(ctx)
|
||||
for _, pathStr := range paths {
|
||||
path, err := types.ApplyPrefix(prefix, pathStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := proof.VerifyNonMembership(root, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -243,7 +243,7 @@ func (chain *TestChain) CreateClient(client *TestChain) error {
|
|||
ctxTarget := chain.GetContext()
|
||||
|
||||
// create client
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header)
|
||||
clientState, err := ibctmtypes.Initialize(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ func (chain *TestChain) updateClient(client *TestChain) {
|
|||
ctxTarget, client.ClientID, uint64(client.Header.Height-1), consensusState,
|
||||
)
|
||||
chain.App.IBCKeeper.ClientKeeper.SetClientState(
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header),
|
||||
ctxTarget, ibctmtypes.NewClientState(client.ClientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, client.Header, commitmenttypes.GetSDKSpecs()),
|
||||
)
|
||||
|
||||
// _, _, err := simapp.SignCheckDeliver(
|
||||
|
|
|
@ -30,7 +30,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
|||
genState: ibc.GenesisState{
|
||||
ClientGenesis: client.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("chaindID", 10),
|
||||
},
|
||||
[]client.ConsensusStates{
|
||||
|
@ -86,7 +86,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
|
|||
genState: ibc.GenesisState{
|
||||
ClientGenesis: client.NewGenesisState(
|
||||
[]exported.ClientState{
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header),
|
||||
ibctmtypes.NewClientState(clientID, lite.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, suite.header, commitmenttypes.GetSDKSpecs()),
|
||||
localhosttypes.NewClientState("(chaindID)", 0),
|
||||
},
|
||||
nil,
|
||||
|
|
|
@ -246,7 +246,7 @@ func (chain *TestChain) CreateTMClient(counterparty *TestChain, clientID string)
|
|||
msg := ibctmtypes.NewMsgCreateClient(
|
||||
clientID, counterparty.LastHeader,
|
||||
DefaultTrustLevel, TrustingPeriod, UnbondingPeriod, MaxClockDrift,
|
||||
chain.SenderAccount.GetAddress(),
|
||||
commitmenttypes.GetSDKSpecs(), chain.SenderAccount.GetAddress(),
|
||||
)
|
||||
|
||||
return chain.SendMsg(msg)
|
||||
|
|
Loading…
Reference in New Issue