x/ibc: create localhost client on InitGenesis (#6170)

closes: #6159
This commit is contained in:
Federico Kunze 2020-05-11 11:46:00 -04:00 committed by GitHub
parent f37308778a
commit f88d9ab586
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 75 additions and 36 deletions

View File

@ -11,7 +11,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
) )
type ClientTestSuite struct { type ClientTestSuite struct {
@ -27,7 +26,7 @@ func (suite *ClientTestSuite) SetupTest() {
suite.app = simapp.Setup(isCheckTx) suite.app = simapp.Setup(isCheckTx)
suite.cdc = suite.app.Codec() suite.cdc = suite.app.Codec()
suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, abci.Header{Height: 1, ChainID: "localhost_chain"}) suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, abci.Header{Height: 0, ChainID: "localhost_chain"})
} }
@ -36,25 +35,23 @@ func TestClientTestSuite(t *testing.T) {
} }
func (suite *ClientTestSuite) TestBeginBlocker() { func (suite *ClientTestSuite) TestBeginBlocker() {
localHostClient := localhosttypes.NewClientState( prevHeight := suite.ctx.BlockHeight()
suite.app.IBCKeeper.ClientKeeper.ClientStore(suite.ctx, exported.ClientTypeLocalHost),
suite.ctx.ChainID(),
suite.ctx.BlockHeight(),
)
_, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, localHostClient, nil)
suite.Require().NoError(err)
// increase height localHostClient, found := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, exported.ClientTypeLocalHost)
suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) suite.Require().True(found)
suite.Require().Equal(prevHeight, int64(localHostClient.GetLatestHeight()))
var prevHeight uint64
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
prevHeight = localHostClient.GetLatestHeight() // increment height
suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1)
suite.Require().NotPanics(func() { suite.Require().NotPanics(func() {
client.BeginBlocker(suite.ctx, suite.app.IBCKeeper.ClientKeeper) client.BeginBlocker(suite.ctx, suite.app.IBCKeeper.ClientKeeper)
}, "BeginBlocker shouldn't panic") }, "BeginBlocker shouldn't panic")
localHostClient, found := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, localHostClient.GetID())
localHostClient, found = suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, exported.ClientTypeLocalHost)
suite.Require().True(found) suite.Require().True(found)
suite.Require().Equal(prevHeight+1, localHostClient.GetLatestHeight()) suite.Require().Equal(prevHeight+1, int64(localHostClient.GetLatestHeight()))
prevHeight = int64(localHostClient.GetLatestHeight())
} }
} }

View File

@ -2,6 +2,8 @@ package client
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
) )
// InitGenesis initializes the ibc client submodule's state from a provided genesis // InitGenesis initializes the ibc client submodule's state from a provided genesis
@ -16,6 +18,28 @@ func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) {
k.SetClientConsensusState(ctx, cs.ClientID, consState.GetHeight(), consState) k.SetClientConsensusState(ctx, cs.ClientID, consState.GetHeight(), consState)
} }
} }
if !gs.CreateLocalhost {
return
}
// NOTE: return if the localhost client was already imported. The chain-id and
// block height will be overwriten to the correct values during BeginBlock.
if _, found := k.GetClientState(ctx, exported.ClientTypeLocalHost); found {
return
}
// client id is always "localhost"
clientState := localhosttypes.NewClientState(
k.ClientStore(ctx, exported.ClientTypeLocalHost),
ctx.ChainID(),
ctx.BlockHeight(),
)
_, err := k.CreateClient(ctx, clientState, nil)
if err != nil {
panic(err)
}
} }
// ExportGenesis returns the ibc client submodule's exported genesis. // ExportGenesis returns the ibc client submodule's exported genesis.
@ -23,5 +47,6 @@ func ExportGenesis(ctx sdk.Context, k Keeper) GenesisState {
return GenesisState{ return GenesisState{
Clients: k.GetAllClients(ctx), Clients: k.GetAllClients(ctx),
ClientsConsensus: k.GetAllConsensusStates(ctx), ClientsConsensus: k.GetAllConsensusStates(ctx),
CreateLocalhost: true,
} }
} }

View File

@ -18,8 +18,6 @@ func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClie
var clientState exported.ClientState var clientState exported.ClientState
switch clientType { switch clientType {
case 0:
return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType())
case exported.Tendermint: case exported.Tendermint:
tmMsg, ok := msg.(ibctmtypes.MsgCreateClient) tmMsg, ok := msg.(ibctmtypes.MsgCreateClient)
if !ok { if !ok {

View File

@ -89,7 +89,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
// override client state and update the block height // override client state and update the block height
clientState = localhosttypes.NewClientState( clientState = localhosttypes.NewClientState(
k.ClientStore(ctx, clientState.GetID()), k.ClientStore(ctx, clientState.GetID()),
clientState.GetChainID(), ctx.ChainID(), // use the chain ID from context since the client is from the running chain (i.e self).
ctx.BlockHeight(), ctx.BlockHeight(),
) )
default: default:
@ -110,17 +110,23 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, clientState.GetLatestHeight())) k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, clientState.GetLatestHeight()))
// Emit events in keeper so antehandler emits them as well // Emit events in keeper so antehandler emits them as well
ctx.EventManager().EmitEvents(sdk.Events{ ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(
types.EventTypeUpdateClient, types.EventTypeUpdateClient,
sdk.NewAttribute(types.AttributeKeyClientID, clientID), sdk.NewAttribute(types.AttributeKeyClientID, clientID),
sdk.NewAttribute(types.AttributeKeyClientType, clientType.String()), sdk.NewAttribute(types.AttributeKeyClientType, clientType.String()),
), ),
sdk.NewEvent( )
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), // localhost client is not updated though messages
), if clientType != exported.Localhost {
}) ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
)
}
return clientState, nil return clientState, nil
} }

View File

@ -184,9 +184,6 @@ func (suite *KeeperTestSuite) TestUpdateClientLocalhost() {
suite.ctx.BlockHeight(), suite.ctx.BlockHeight(),
) )
localhostClient, err := suite.keeper.CreateClient(suite.ctx, localhostClient, nil)
suite.Require().NoError(err, err)
suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1)
updatedClientState, err := suite.keeper.UpdateClient(suite.ctx, exported.ClientTypeLocalHost, nil) updatedClientState, err := suite.keeper.UpdateClient(suite.ctx, exported.ClientTypeLocalHost, nil)

View File

@ -129,6 +129,11 @@ func (suite KeeperTestSuite) TestGetAllClients() {
suite.keeper.SetClientState(suite.ctx, expClients[i]) suite.keeper.SetClientState(suite.ctx, expClients[i])
} }
// add localhost client
localHostClient, found := suite.keeper.GetClientState(suite.ctx, exported.ClientTypeLocalHost)
suite.Require().True(found)
expClients = append(expClients, localHostClient)
clients := suite.keeper.GetAllClients(suite.ctx) clients := suite.keeper.GetAllClients(suite.ctx)
suite.Require().Len(clients, len(expClients)) suite.Require().Len(clients, len(expClients))
suite.Require().Equal(expClients, clients) suite.Require().Equal(expClients, clients)

View File

@ -25,15 +25,17 @@ func NewClientConsensusStates(id string, states []exported.ConsensusState) Clien
type GenesisState struct { type GenesisState struct {
Clients []exported.ClientState `json:"clients" yaml:"clients"` Clients []exported.ClientState `json:"clients" yaml:"clients"`
ClientsConsensus []ClientConsensusStates `json:"clients_consensus" yaml:"clients_consensus"` ClientsConsensus []ClientConsensusStates `json:"clients_consensus" yaml:"clients_consensus"`
CreateLocalhost bool `json:"create_localhost" yaml:"create_localhost"`
} }
// NewGenesisState creates a GenesisState instance. // NewGenesisState creates a GenesisState instance.
func NewGenesisState( func NewGenesisState(
clients []exported.ClientState, clientsConsensus []ClientConsensusStates, clients []exported.ClientState, clientsConsensus []ClientConsensusStates, createLocalhost bool,
) GenesisState { ) GenesisState {
return GenesisState{ return GenesisState{
Clients: clients, Clients: clients,
ClientsConsensus: clientsConsensus, ClientsConsensus: clientsConsensus,
CreateLocalhost: createLocalhost,
} }
} }
@ -42,6 +44,7 @@ func DefaultGenesisState() GenesisState {
return GenesisState{ return GenesisState{
Clients: []exported.ClientState{}, Clients: []exported.ClientState{},
ClientsConsensus: []ClientConsensusStates{}, ClientsConsensus: []ClientConsensusStates{},
CreateLocalhost: true,
} }
} }

View File

@ -67,6 +67,7 @@ func TestValidateGenesis(t *testing.T) {
}, },
}, },
}, },
true,
), ),
expPass: true, expPass: true,
}, },
@ -78,6 +79,7 @@ func TestValidateGenesis(t *testing.T) {
localhosttypes.NewClientState(store, "chaindID", 0), localhosttypes.NewClientState(store, "chaindID", 0),
}, },
nil, nil,
true,
), ),
expPass: false, expPass: false,
}, },
@ -98,6 +100,7 @@ func TestValidateGenesis(t *testing.T) {
}, },
}, },
}, },
true,
), ),
expPass: false, expPass: false,
}, },
@ -118,6 +121,7 @@ func TestValidateGenesis(t *testing.T) {
}, },
), ),
}, },
true,
), ),
expPass: false, expPass: false,
}, },

View File

@ -23,10 +23,9 @@ func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create", Use: "create",
Short: "create new localhost client", Short: "create new localhost client",
Long: strings.TrimSpace(fmt.Sprintf(`create new localhost (loopback) client: Long: strings.TrimSpace(fmt.Sprintf(`create new localhost (loopback) client:
Example:
Example: $ %s tx ibc client localhost create --from node0 --home ../node0/<app>cli --chain-id $CID
$ %s tx ibc client localhost create --from node0 --home ../node0/<app>cli --chain-id $CID
`, version.ClientName), `, version.ClientName),
), ),
Args: cobra.ExactArgs(0), Args: cobra.ExactArgs(0),

View File

@ -10,7 +10,7 @@ import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
tmclient "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli" tmclient "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli"
localhostclient "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/cli" localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost"
"github.com/cosmos/cosmos-sdk/x/ibc/types" "github.com/cosmos/cosmos-sdk/x/ibc/types"
) )
@ -26,7 +26,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
ibcTxCmd.AddCommand(flags.PostCommands( ibcTxCmd.AddCommand(flags.PostCommands(
tmclient.GetTxCmd(cdc, storeKey), tmclient.GetTxCmd(cdc, storeKey),
localhostclient.GetTxCmd(cdc, storeKey), localhost.GetTxCmd(cdc, storeKey),
connection.GetTxCmd(cdc, storeKey), connection.GetTxCmd(cdc, storeKey),
channel.GetTxCmd(cdc, storeKey), channel.GetTxCmd(cdc, storeKey),
)...) )...)

View File

@ -39,7 +39,7 @@ func (gs GenesisState) Validate() error {
// InitGenesis initializes the ibc state from a provided genesis // InitGenesis initializes the ibc state from a provided genesis
// state. // state.
func InitGenesis(ctx sdk.Context, k Keeper, gs GenesisState) { func InitGenesis(ctx sdk.Context, k Keeper, createLocalhost bool, gs GenesisState) {
client.InitGenesis(ctx, k.ClientKeeper, gs.ClientGenesis) client.InitGenesis(ctx, k.ClientKeeper, gs.ClientGenesis)
connection.InitGenesis(ctx, k.ConnectionKeeper, gs.ConnectionGenesis) connection.InitGenesis(ctx, k.ConnectionKeeper, gs.ConnectionGenesis)
channel.InitGenesis(ctx, k.ChannelKeeper, gs.ChannelGenesis) channel.InitGenesis(ctx, k.ChannelKeeper, gs.ChannelGenesis)

View File

@ -41,6 +41,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
}, },
), ),
}, },
true,
), ),
ConnectionGenesis: connection.NewGenesisState( ConnectionGenesis: connection.NewGenesisState(
[]connection.End{ []connection.End{
@ -84,6 +85,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
localhosttypes.NewClientState(suite.store, "chaindID", 0), localhosttypes.NewClientState(suite.store, "chaindID", 0),
}, },
nil, nil,
false,
), ),
ConnectionGenesis: connection.DefaultGenesisState(), ConnectionGenesis: connection.DefaultGenesisState(),
}, },

View File

@ -92,6 +92,9 @@ func (AppModuleBasic) RegisterInterfaceTypes(registry cdctypes.InterfaceRegistry
type AppModule struct { type AppModule struct {
AppModuleBasic AppModuleBasic
keeper *Keeper keeper *Keeper
// create localhost by default
createLocalhost bool
} }
// NewAppModule creates a new AppModule object // NewAppModule creates a new AppModule object
@ -139,7 +142,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, bz jso
if err != nil { if err != nil {
panic(fmt.Sprintf("failed to unmarshal %s genesis state: %s", ModuleName, err)) panic(fmt.Sprintf("failed to unmarshal %s genesis state: %s", ModuleName, err))
} }
InitGenesis(ctx, *am.keeper, gs) InitGenesis(ctx, *am.keeper, am.createLocalhost, gs)
return []abci.ValidatorUpdate{} return []abci.ValidatorUpdate{}
} }