diff --git a/go.mod b/go.mod index 1a4fd38f..886b342d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.4 require ( - cosmossdk.io/api v0.7.4 + cosmossdk.io/api v0.7.5 cosmossdk.io/client/v2 v2.0.0-beta.1 cosmossdk.io/collections v0.4.0 cosmossdk.io/core v0.12.0 @@ -18,16 +18,16 @@ require ( cosmossdk.io/x/circuit v0.1.0 cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/feegrant v0.1.0 - cosmossdk.io/x/tx v0.13.2 + cosmossdk.io/x/tx v0.13.3 cosmossdk.io/x/upgrade v0.1.0 - github.com/cometbft/cometbft v0.38.6 + github.com/cometbft/cometbft v0.38.9 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/cosmos-sdk v0.50.6 + github.com/cosmos/cosmos-sdk v0.50.8 github.com/cosmos/go-bip39 v1.0.0 - github.com/cosmos/gogoproto v1.4.12 + github.com/cosmos/gogoproto v1.5.0 github.com/cosmos/ibc-go/modules/capability v1.0.0 - github.com/cosmos/ibc-go/v8 v8.2.1 + github.com/cosmos/ibc-go/v8 v8.3.2 github.com/cosmos/rosetta v0.0.0-20231205133638-3bc76705a1c6 github.com/ethereum/go-ethereum v1.10.26 github.com/evmos/ethermint v0.22.0 @@ -198,6 +198,7 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect diff --git a/go.sum b/go.sum index b08b3b8d..6a7cb3d4 100644 --- a/go.sum +++ b/go.sum @@ -184,8 +184,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/api v0.7.4 h1:sPo8wKwCty1lht8kgL3J7YL1voJywP3YWuA5JKkBz30= -cosmossdk.io/api v0.7.4/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= +cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/client/v2 v2.0.0-beta.1 h1:XkHh1lhrLYIT9zKl7cIOXUXg2hdhtjTPBUfqERNA1/Q= cosmossdk.io/client/v2 v2.0.0-beta.1/go.mod h1:JEUSu9moNZQ4kU3ir1DKD5eU4bllmAexrGWjmb9k8qU= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= @@ -214,8 +214,8 @@ cosmossdk.io/x/feegrant v0.1.0 h1:c7s3oAq/8/UO0EiN1H5BIjwVntujVTkYs35YPvvrdQk= cosmossdk.io/x/feegrant v0.1.0/go.mod h1:4r+FsViJRpcZif/yhTn+E0E6OFfg4n0Lx+6cCtnZElU= cosmossdk.io/x/nft v0.0.0-20231023160833-026631cd833c h1:EFBlwazEIqkvKV5L1JfQZ6lhUJF9cMguAqQk1xSmbfM= cosmossdk.io/x/nft v0.0.0-20231023160833-026631cd833c/go.mod h1:PELWSey8Y7pq8iSgqEav82APBbgMb/SDbbjyuP8tvWc= -cosmossdk.io/x/tx v0.13.2 h1:Kh90UH30bhnnUdJH+CmWLyaH8IKdY6BBGY3EkdOk82o= -cosmossdk.io/x/tx v0.13.2/go.mod h1:yhPokDCfXVIuAtyp49IFlWB5YAXUgD7Zek+ZHwsHzvU= +cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= +cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= cosmossdk.io/x/upgrade v0.1.0 h1:z1ZZG4UL9ICTNbJDYZ6jOnF9GdEK9wyoEFi4BUScHXE= cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -370,8 +370,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= -github.com/cometbft/cometbft v0.38.6 h1:QSgpCzrGWJ2KUq1qpw+FCfASRpE27T6LQbfEHscdyOk= -github.com/cometbft/cometbft v0.38.6/go.mod h1:8rSPxzUJYquCN8uuBgbUHOMg2KAwvr7CyUw+6ukO4nw= +github.com/cometbft/cometbft v0.38.9 h1:cJBJBG0mPKz+sqelCi/hlfZjadZQGdDNnu6YQ1ZsUHQ= +github.com/cometbft/cometbft v0.38.9/go.mod h1:xOoGZrtUT+A5izWfHSJgl0gYZUE7lu7Z2XIS1vWG/QQ= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -388,23 +388,21 @@ github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAK github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.50.6 h1:efR3MsvMHX5sxS3be+hOobGk87IzlZbSpsI2x/Vw3hk= -github.com/cosmos/cosmos-sdk v0.50.6/go.mod h1:lVkRY6cdMJ0fG3gp8y4hFrsKZqF4z7y0M2UXFb9Yt40= +github.com/cosmos/cosmos-sdk v0.50.8 h1:2UJHssUaGHTl4/dFp8xyREKAnfiRU6VVfqtKG9n8w5g= +github.com/cosmos/cosmos-sdk v0.50.8/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= -github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= -github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= -github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= -github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= +github.com/cosmos/gogoproto v1.5.0 h1:SDVwzEqZDDBoslaeZg+dGE55hdzHfgUA40pEanMh52o= +github.com/cosmos/gogoproto v1.5.0/go.mod h1:iUM31aofn3ymidYG6bUR5ZFrk+Om8p5s754eMUcyp8I= github.com/cosmos/iavl v1.1.4 h1:Z0cVVjeQqOUp78/nWt/uhQy83vYluWlAMGQ4zbH9G34= github.com/cosmos/iavl v1.1.4/go.mod h1:vCYmRQUJU1wwj0oRD3wMEtOM9sJNDP+GFMaXmIxZ/rU= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= -github.com/cosmos/ibc-go/v8 v8.2.1 h1:MTsnZZjxvGD4Fv5pYyx5UkELafSX0rlPt6IfsE2BpTQ= -github.com/cosmos/ibc-go/v8 v8.2.1/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8= +github.com/cosmos/ibc-go/v8 v8.3.2 h1:8X1oHHKt2Bh9hcExWS89rntLaCKZp2EjFTUSxKlPhGI= +github.com/cosmos/ibc-go/v8 v8.3.2/go.mod h1:WVVIsG39jGrF9Cjggjci6LzySyWGloz194sjTxiGNIE= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -753,6 +751,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= diff --git a/ibc/testing/README.md b/ibc/testing/README.md deleted file mode 100644 index d17d2ce5..00000000 --- a/ibc/testing/README.md +++ /dev/null @@ -1,326 +0,0 @@ -# IBC Testing Package - -## Components - -The testing package comprises of four parts constructed as a stack: - -- coordinator -- chain -- path -- endpoint - -A coordinator sits at the highest level and contains all the chains which have been initialized. -It also stores and updates the current global time. The time is manually incremented by a `TimeIncrement`. -This allows all the chains to remain in synchrony avoiding the issue of a counterparty being perceived to -be in the future. The coordinator also contains functions to do basic setup of clients, connections, and channels -between two chains. - -A chain is an SDK application (as represented by an app.go file). Inside the chain is an `TestingApp` which allows -the chain to simulate block production and transaction processing. The chain contains by default a single tendermint -validator. A chain is used to process SDK messages. - -A path connects two channel endpoints. It contains all the information needed to relay between two endpoints. - -An endpoint represents a channel (and its associated client and connections) on some specific chain. It contains -references to the chain it is on and the counterparty endpoint it is connected to. The endpoint contains functions -to interact with initialization and updates of its associated clients, connections, and channels. It can send, receive, -and acknowledge packets. - -In general: - -- endpoints are used for initialization and execution of IBC logic on one side of an IBC connection -- paths are used to relay packets -- chains are used to commit SDK messages -- coordinator is used to setup a path between two chains - -## Integration - -To integrate the testing package into your tests, you will need to define: - -- a testing application -- a function to initialize the testing application - -### TestingApp - -Your project will likely already have an application defined. This application -will need to be extended to fulfill the `TestingApp` interface. - -```go -type TestingApp interface { - abci.Application - - // ibc-go additions - GetBaseApp() *baseapp.BaseApp - GetStakingKeeper() stakingkeeper.Keeper - GetIBCKeeper() *keeper.Keeper - GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper - GetTxConfig() client.TxConfig - - // Implemented by SimApp - AppCodec() codec.Codec - - // Implemented by BaseApp - LastCommitID() sdk.CommitID - LastBlockHeight() int64 -} -``` - -To begin, you will need to extend your application by adding the following functions: - -```go -// TestingApp functions -// Example using SimApp to implement TestingApp - -// GetBaseApp implements the TestingApp interface. -func (app *SimApp) GetBaseApp() *baseapp.BaseApp { - return app.BaseApp -} - -// GetStakingKeeper implements the TestingApp interface. -func (app *SimApp) GetStakingKeeper() stakingkeeper.Keeper { - return app.StakingKeeper -} - -// GetIBCKeeper implements the TestingApp interface. -func (app *SimApp) GetIBCKeeper() *ibckeeper.Keeper { - return app.IBCKeeper -} - -// GetScopedIBCKeeper implements the TestingApp interface. -func (app *SimApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { - return app.ScopedIBCKeeper -} - -// GetTxConfig implements the TestingApp interface. -func (app *SimApp) GetTxConfig() client.TxConfig { - return MakeTestEncodingConfig().TxConfig -} - -``` - -Your application may need to define `AppCodec()` if it does not already exist: - -```go -// AppCodec returns SimApp's app codec. -// -// NOTE: This is solely to be used for testing purposes as it may be desirable -// for modules to register their own custom testing types. -func (app *SimApp) AppCodec() codec.Codec { - return app.appCodec -} -``` - -It is assumed your application contains an embedded BaseApp and thus implements the abci.Application interface, `LastCommitID()` and `LastBlockHeight()` - -### Initialize TestingApp - -The testing package requires that you provide a function to initialize your TestingApp. This is how ibc-go implements the initialize function with its `SimApp`: - -```go -func SetupTestingApp() (TestingApp, map[string]json.RawMessage) { - db := dbm.NewMemDB() - encCdc := simapp.MakeTestEncodingConfig() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{}) - return app, simapp.NewDefaultGenesisState(encCdc.Marshaler) -} -``` - -This function returns the TestingApp and the default genesis state used to initialize the testing app. - -Change the value of `DefaultTestingAppInit` to use your function: - -```go -func init() { - ibctesting.DefaultTestingAppInit = MySetupTestingAppFunction -} - -``` - -## Example - -Here is an example of how to setup your testing environment in every package you are testing: - -```go -// KeeperTestSuite is a testing suite to test keeper functions. -type KeeperTestSuite struct { - suite.Suite - - coordinator *ibctesting.Coordinator - - // testing chains used for convenience and readability - chainA *ibctesting.TestChain - chainB *ibctesting.TestChain -} - -// TestKeeperTestSuite runs all the tests within this package. -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) -} - -// SetupTest creates a coordinator with 2 test chains. -func (suite *KeeperTestSuite) SetupTest() { - suite.coordinator = ibctesting.NewCoordinator(suite.T(), 2) // initializes 2 test chains - suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) // convenience and readability - suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(2)) // convenience and readability -} -``` - -To create interaction between chainA and chainB, we need to contruct a `Path` these chains will use. -A path contains two endpoints, `EndpointA` and `EndpointB` (corresponding to the order of the chains passed -into the `NewPath` function). A path is a pointer and its values will be filled in as necessary during the -setup portion of testing. - -Endpoint Struct: - -```go -// Endpoint is a which represents a channel endpoint and its associated -// client and connections. It contains client, connection, and channel -// configuration parameters. Endpoint functions will utilize the parameters -// set in the configuration structs when executing IBC messages. -type Endpoint struct { - Chain *TestChain - Counterparty *Endpoint - ClientID string - ConnectionID string - ChannelID string - - ClientConfig ClientConfig - ConnectionConfig *ConnectionConfig - ChannelConfig *ChannelConfig -} -``` - -The fields empty after `NewPath` is called are `ClientID`, `ConnectionID` and -`ChannelID` as the clients, connections, and channels for these endpoints have not yet been created. The -`ClientConfig`, `ConnectionConfig` and `ChannelConfig` contain all the necessary information for clients, -connections, and channels to be initialized. If you would like to use endpoints which are initialized to -use your Port IDs, you might add a helper function similar to the one found in transfer: - -```go -func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - - return path -} - -``` - -Path configurations should be set to the desired values before calling any `Setup` coordinator functions. - -To initialize the clients, connections, and channels for a path we can call the Setup functions of the coordinator: - -- Setup() -> setup clients, connections, channels -- SetupClients() -> setup clients only -- SetupConnections() -> setup clients and connections only - -Here is a basic example of the testing package being used to simulate IBC functionality: - -```go - path := ibctesting.NewPath(suite.chainA, suite.chainB) // clientID, connectionID, channelID empty - suite.coordinator.Setup(path) // clientID, connectionID, channelID filled - suite.Require().Equal("07-tendermint-0", path.EndpointA.ClientID) - suite.Require().Equal("connection-0", path.EndpointA.ClientID) - suite.Require().Equal("channel-0", path.EndpointA.ClientID) - - // create packet 1 - packet1 := NewPacket() // NewPacket would construct your packet - - // send on endpointA - path.EndpointA.SendPacket(packet1) - - // receive on endpointB - path.EndpointB.RecvPacket(packet1) - - // acknowledge the receipt of the packet - path.EndpointA.AcknowledgePacket(packet1, ack) - - // we can also relay - packet2 := NewPacket() - - path.EndpointA.SendPacket(packet2) - - path.Relay(packet2, expectedAck) - - // if needed we can update our clients - path.EndpointB.UpdateClient() -``` - -### Transfer Testing Example - -If ICS 20 had its own simapp, its testing setup might include a `testing/app.go` file with the following contents: - -```go -package transfertesting - -import ( - "encoding/json" - - "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" - - "github.com/cosmos/ibc-go/v3/modules/apps/transfer/simapp" - ibctesting "github.com/cosmos/ibc-go/v3/testing" -) - -func SetupTransferTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { - db := dbm.NewMemDB() - encCdc := simapp.MakeTestEncodingConfig() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 5, encCdc, simapp.EmptyAppOptions{}) - return app, simapp.NewDefaultGenesisState(encCdc.Marshaler) -} - -func init() { - ibctesting.DefaultTestingAppInit = SetupTransferTestingApp -} - -func NewTransferPath(chainA, chainB *ibctesting.TestChain) *ibctesting.Path { - path := ibctesting.NewPath(chainA, chainB) - path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort - path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - - return path -} - -func GetTransferSimApp(chain *ibctesting.TestChain) *simapp.SimApp { - app, ok := chain.App.(*simapp.SimApp) - if !ok { - panic("not transfer app") - } - - return app -} -``` - -### Middleware Testing - -When writing IBC applications acting as middleware, it might be desirable to test integration points. -This can be done by wiring a middleware stack in the app.go file using existing applications as middleware and IBC base applications. -The mock module may also be leveraged to act as a base application in the instance that such an application is not available for testing or causes dependency concerns. - -The mock IBC module contains a `MockIBCApp`. This struct contains a function field for every IBC App Module callback. -Each of these functions can be individually set to mock expected behavior of a base application. - -For example, if one wanted to test that the base application cannot affect the outcome of the `OnChanOpenTry` callback, the mock module base application callback could be updated as such: - -```go - mockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, portID, channelID, version string) error { - return fmt.Errorf("mock base app must not be called for OnChanOpenTry") - } -``` - -Using a mock module as a base application in a middleware stack may require adding the module to your `SimApp`. -This is because IBC will route to the top level IBC module of a middleware stack, so a module which never -sits at the top of middleware stack will need to be accessed via a public field in `SimApp` - -This might look like: - -```go - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, version string, - ) error { - return fmt.Errorf("mock ica auth fails") - } -``` diff --git a/ibc/testing/app.go b/ibc/testing/app.go index f9549eec..1d091ccc 100644 --- a/ibc/testing/app.go +++ b/ibc/testing/app.go @@ -72,6 +72,10 @@ func SetupTestingCantoApp() (TestingApp, map[string]json.RawMessage) { return app, cantoapp.NewDefaultGenesisState() } +// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts +// that also act as delegators. For simplicity, each validator is bonded with a delegation +// of one consensus engine unit (10^6) in the default token of the simapp from first genesis +// account. A Nop logger is set in SimApp. func SetupWithGenesisValSet(tb testing.TB, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, powerReduction sdkmath.Int, balances ...banktypes.Balance) TestingApp { tb.Helper() app, genesisState := DefaultTestingAppInit() diff --git a/ibc/testing/chain.go b/ibc/testing/chain.go index 48ecbfcf..554f581b 100644 --- a/ibc/testing/chain.go +++ b/ibc/testing/chain.go @@ -2,7 +2,6 @@ package ibctesting import ( "fmt" - "math/rand" "testing" "time" @@ -11,19 +10,23 @@ import ( errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/staking/testutil" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/Canto-Network/Canto/v7/ibc/testing/simapp" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + cmtprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" + cmttypes "github.com/cometbft/cometbft/types" + cmtversion "github.com/cometbft/cometbft/version" + capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -34,18 +37,13 @@ import ( ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v8/testing/mock" - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cometbft/cometbft/crypto/tmhash" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmprotoversion "github.com/cometbft/cometbft/proto/tendermint/version" - tmtypes "github.com/cometbft/cometbft/types" - tmversion "github.com/cometbft/cometbft/version" - "github.com/ethereum/go-ethereum/common" "github.com/evmos/ethermint/crypto/ethsecp256k1" ethermint "github.com/evmos/ethermint/types" evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/Canto-Network/Canto/v7/ibc/testing/simapp" ) var MaxAccounts = 10 @@ -69,25 +67,25 @@ type TestChain struct { Coordinator *Coordinator App TestingApp ChainID string - LastHeader *ibctm.Header // header for last block height committed - CurrentHeader tmproto.Header // header for current block height + LastHeader *ibctm.Header // header for last block height committed + CurrentHeader cmtproto.Header // header for current block height QueryServer types.QueryServer TxConfig client.TxConfig - Codec codec.BinaryCodec + Codec codec.Codec - Vals *tmtypes.ValidatorSet - NextVals *tmtypes.ValidatorSet + Vals *cmttypes.ValidatorSet + NextVals *cmttypes.ValidatorSet // Signers is a map from validator address to the PrivValidator // The map is converted into an array that is the same order as the validators right before signing commit // This ensures that signers will always be in correct order even as validator powers change. // If a test adds a new validator after chain creation, then the signer map must be updated to include // the new PrivValidator entry. - Signers map[string]tmtypes.PrivValidator + Signers map[string]cmttypes.PrivValidator // autogenerated sender private key SenderPrivKey cryptotypes.PrivKey - SenderAccount authtypes.AccountI + SenderAccount sdk.AccountI SenderAccounts []SenderAccount @@ -109,9 +107,9 @@ type TestChain struct { // NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this // constructor function. // -// CONTRACT: Validator and signer array must be provided in the order expected by Tendermint. +// CONTRACT: Validator array must be provided in the order expected by Tendermint. // i.e. sorted first by power and then lexicographically by address. -func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *TestChain { +func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *TestChain { tb.Helper() genAccs := []authtypes.GenesisAccount{} genBals := []banktypes.Balance{} @@ -124,6 +122,7 @@ func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, v amount, ok := sdkmath.NewIntFromString("10000000000000000000") require.True(tb, ok) + // add sender account balance := banktypes.Balance{ Address: acc.GetAddress().String(), Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), @@ -143,7 +142,7 @@ func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, v app := SetupWithGenesisValSet(tb, valSet, genAccs, chainID, sdk.DefaultPowerReduction, genBals...) // create current header and call begin block - header := tmproto.Header{ + header := cmtproto.Header{ ChainID: chainID, Height: 1, Time: coord.CurrentTime.UTC(), @@ -169,7 +168,7 @@ func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, v SenderAccounts: senderAccs, } - // commit genesis blocks + // commit genesis block chain.NextBlock() return chain @@ -182,22 +181,22 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain { // generate validators private/public key var ( validatorsPerChain = 4 - validators []*tmtypes.Validator - signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain) + validators []*cmttypes.Validator + signersByAddress = make(map[string]cmttypes.PrivValidator, validatorsPerChain) ) for i := 0; i < validatorsPerChain; i++ { - _, privVal := tmtypes.RandValidator(false, 100) + _, privVal := cmttypes.RandValidator(false, 100) pubKey, err := privVal.GetPubKey() require.NoError(t, err) - validators = append(validators, tmtypes.NewValidator(pubKey, 1)) + validators = append(validators, cmttypes.NewValidator(pubKey, 1)) signersByAddress[pubKey.Address().String()] = privVal } // construct validator set; // Note that the validators are sorted by voting power // or, if equal, by address lexical order - valSet := tmtypes.NewValidatorSet(validators) + valSet := cmttypes.NewValidatorSet(validators) return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress) } @@ -218,9 +217,9 @@ func NewTestChainCanto(t *testing.T, coord *Coordinator, chainID string) *TestCh require.NoError(t, err) // create validator set with single validator - validator := tmtypes.NewValidator(pubKey, 1) - valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - signers := map[string]tmtypes.PrivValidator{ + validator := cmttypes.NewValidator(pubKey, 1) + valSet := cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}) + signers := map[string]cmttypes.PrivValidator{ pubKey.Address().String(): privVal, } @@ -247,7 +246,7 @@ func NewTestChainCanto(t *testing.T, coord *Coordinator, chainID string) *TestCh app := SetupWithGenesisValSetCanto(t, valSet, []authtypes.GenesisAccount{acc}, chainID, balance) // create current header and call begin block - header := tmproto.Header{ + header := cmtproto.Header{ ChainID: chainID, Height: 1, Time: coord.CurrentTime.UTC(), @@ -272,7 +271,7 @@ func NewTestChainCanto(t *testing.T, coord *Coordinator, chainID string) *TestCh SenderPrivKey: senderPrivKey, SenderAccount: acc, SenderAccounts: []SenderAccount{ - SenderAccount{ + { SenderAccount: acc, SenderPrivKey: senderPrivKey, }, @@ -286,7 +285,6 @@ func NewTestChainCanto(t *testing.T, coord *Coordinator, chainID string) *TestCh // GetContext returns the current context for the application. func (chain *TestChain) GetContext() sdk.Context { - // return chain.App.GetBaseApp().NewContextLegacy(false, chain.CurrentHeader) return chain.App.GetBaseApp().NewUncachedContext(false, chain.CurrentHeader) } @@ -374,9 +372,9 @@ func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clien consensusHeight := clientState.GetLatestHeight().(clienttypes.Height) consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) - proofConsensus, _ := chain.QueryProof(consensusKey) + consensusProof, _ := chain.QueryProof(consensusKey) - return proofConsensus, consensusHeight + return consensusProof, consensusHeight } // NextBlock sets the last header to the current header and increments the current header to be @@ -390,7 +388,6 @@ func (chain *TestChain) NextBlock() { Height: chain.CurrentHeader.Height, Time: chain.CurrentHeader.GetTime(), NextValidatorsHash: chain.NextVals.Hash(), - ProposerAddress: chain.CurrentHeader.ProposerAddress, }) require.NoError(chain.TB, err) chain.commitBlock(res) @@ -407,10 +404,10 @@ func (chain *TestChain) commitBlock(res *abci.ResponseFinalizeBlock) { // val set changes returned from previous block get applied to the next validators // of this block. See tendermint spec for details. chain.Vals = chain.NextVals - chain.NextVals = ApplyValSetChanges(chain, chain.Vals, res.ValidatorUpdates) + chain.NextVals = simapp.ApplyValSetChanges(chain, chain.Vals, res.ValidatorUpdates) // increment the current header - chain.CurrentHeader = tmproto.Header{ + chain.CurrentHeader = cmtproto.Header{ ChainID: chain.ChainID, Height: chain.App.LastBlockHeight() + 1, AppHash: chain.App.LastCommitID().Hash, @@ -440,7 +437,15 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { // ensure the chain has the latest time chain.Coordinator.UpdateTimeForChain(chain) - resp, err := SignAndDeliver( + // increment acc sequence regardless of success or failure tx execution + defer func() { + err := chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) + if err != nil { + panic(err) + } + }() + + resp, err := simapp.SignAndDeliver( chain.TB, chain.TxConfig, chain.App.GetBaseApp(), @@ -467,12 +472,6 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) { return txResult, fmt.Errorf("%s/%d: %q", txResult.Codespace, txResult.Code, txResult.Log) } - // increment sequence for successful transaction execution - err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) - if err != nil { - return nil, err - } - chain.Coordinator.IncrementTime() return txResult, nil @@ -493,9 +492,9 @@ func (chain *TestChain) GetConsensusState(clientID string, height exported.Heigh return chain.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height) } -// GetValsAtHeight will return the validator set of the chain at a given height. It will return +// GetValsAtHeight will return the trusted validator set of the chain for the given trusted height. It will return // a success boolean depending on if the validator set exists or not at that height. -func (chain *TestChain) GetValsAtHeight(trustedHeight int64) (*tmtypes.ValidatorSet, bool) { +func (chain *TestChain) GetValsAtHeight(trustedHeight int64) (*cmttypes.ValidatorSet, bool) { // historical information does not store the validator set which committed the header at // height h. During BeginBlock, it stores the last updated validator set. This is equivalent to // the next validator set at height h. This is because cometbft processes the validator set @@ -523,7 +522,7 @@ func (chain *TestChain) GetValsAtHeight(trustedHeight int64) (*tmtypes.Validator if err != nil { panic(err) } - return tmtypes.NewValidatorSet(tmValidators), true + return cmttypes.NewValidatorSet(tmValidators), true } // GetAcknowledgement retrieves an acknowledgement for the provided packet. If the @@ -555,7 +554,7 @@ func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterpa trustedHeight = chain.GetClientState(clientID).GetLatestHeight().(clienttypes.Height) } var ( - tmTrustedVals *tmtypes.ValidatorSet + tmTrustedVals *cmttypes.ValidatorSet ok bool ) @@ -600,52 +599,52 @@ func (chain *TestChain) CurrentTMClientHeader() *ibctm.Header { // CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow // caller flexibility to use params that differ from the chain. -func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctm.Header { +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, cmtValSet, nextVals, tmTrustedVals *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *ibctm.Header { var ( - valSet *tmproto.ValidatorSet - trustedVals *tmproto.ValidatorSet + valSet *cmtproto.ValidatorSet + trustedVals *cmtproto.ValidatorSet ) - require.NotNil(chain.TB, tmValSet) + require.NotNil(chain.TB, cmtValSet) - tmHeader := tmtypes.Header{ - Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2}, + tmHeader := cmttypes.Header{ + Version: cmtprotoversion.Consensus{Block: cmtversion.BlockProtocol, App: 2}, ChainID: chainID, Height: blockHeight, Time: timestamp, LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)), LastCommitHash: chain.App.LastCommitID().Hash, DataHash: tmhash.Sum([]byte("data_hash")), - ValidatorsHash: tmValSet.Hash(), + ValidatorsHash: cmtValSet.Hash(), NextValidatorsHash: nextVals.Hash(), ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: chain.CurrentHeader.AppHash, LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), - ProposerAddress: tmValSet.Proposer.Address, //nolint:staticcheck + ProposerAddress: cmtValSet.Proposer.Address, //nolint:staticcheck } hhash := tmHeader.Hash() blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) - voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) + voteSet := cmttypes.NewVoteSet(chainID, blockHeight, 1, cmtproto.PrecommitType, cmtValSet) // MakeCommit expects a signer array in the same order as the validator array. // Thus we iterate over the ordered validator set and construct a signer array // from the signer map in the same order. - var signerArr []tmtypes.PrivValidator //nolint:prealloc // using prealloc here would be needlessly complex - for _, v := range tmValSet.Validators { //nolint:staticcheck // need to check for nil validator set + var signerArr []cmttypes.PrivValidator //nolint:prealloc // using prealloc here would be needlessly complex + for _, v := range cmtValSet.Validators { //nolint:staticcheck // need to check for nil validator set signerArr = append(signerArr, signers[v.Address.String()]) } - extCommit, err := tmtypes.MakeExtCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp, false) + extCommit, err := cmttypes.MakeExtCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp, false) require.NoError(chain.TB, err) - signedHeader := &tmproto.SignedHeader{ + signedHeader := &cmtproto.SignedHeader{ Header: tmHeader.ToProto(), Commit: extCommit.ToCommit().ToProto(), } - if tmValSet != nil { - valSet, err = tmValSet.ToProto() + if cmtValSet != nil { //nolint:staticcheck + valSet, err = cmtValSet.ToProto() require.NoError(chain.TB, err) } @@ -664,11 +663,11 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, } } -// MakeBlockID copied unimported test functions from tmtypes to use them here -func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.BlockID { - return tmtypes.BlockID{ +// MakeBlockID copied unimported test functions from cmttypes to use them here +func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) cmttypes.BlockID { + return cmttypes.BlockID{ Hash: hash, - PartSetHeader: tmtypes.PartSetHeader{ + PartSetHeader: cmttypes.PartSetHeader{ Total: partSetSize, Hash: partSetHash, }, @@ -684,11 +683,11 @@ func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.Scope _, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), host.PortPath(portID)) if !ok { // create capability using the IBC capability keeper - cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), host.PortPath(portID)) + capability, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), host.PortPath(portID)) require.NoError(chain.TB, err) // claim capability using the scopedKeeper - err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID)) + err = scopedKeeper.ClaimCapability(chain.GetContext(), capability, host.PortPath(portID)) require.NoError(chain.TB, err) } @@ -712,9 +711,9 @@ func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.Sc // check if the portId is already binded, if not bind it _, ok := chain.App.GetScopedIBCKeeper().GetCapability(chain.GetContext(), capName) if !ok { - cap, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), capName) + capability, err := chain.App.GetScopedIBCKeeper().NewCapability(chain.GetContext(), capName) require.NoError(chain.TB, err) - err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, capName) + err = scopedKeeper.ClaimCapability(chain.GetContext(), capability, capName) require.NoError(chain.TB, err) } @@ -736,51 +735,9 @@ func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100) } -// SignAndDeliver signs and delivers a transaction. No simulation occurs as the -// ibc testing package causes checkState and deliverState to diverge in block time. -// -// CONTRACT: BeginBlock must be called before this function. -func SignAndDeliver( - tb testing.TB, txCfg client.TxConfig, app *bam.BaseApp, header tmproto.Header, msgs []sdk.Msg, - chainID string, accNums, accSeqs []uint64, expPass bool, blockTime time.Time, nextValHash []byte, priv ...cryptotypes.PrivKey, -) (*abci.ResponseFinalizeBlock, error) { - tb.Helper() - tx, err := simtestutil.GenSignedMockTx( - rand.New(rand.NewSource(time.Now().UnixNano())), - txCfg, - msgs, - sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}, - simtestutil.DefaultGenTxGas, - chainID, - accNums, - accSeqs, - priv..., - ) - require.NoError(tb, err) - - txBytes, err := txCfg.TxEncoder()(tx) - require.NoError(tb, err) - - return app.FinalizeBlock(&abci.RequestFinalizeBlock{ - Height: app.LastBlockHeight() + 1, - Time: blockTime, - NextValidatorsHash: nextValHash, - Txs: [][]byte{txBytes}, - ProposerAddress: header.ProposerAddress, - }) -} - -// ApplyValSetChanges takes in tmtypes.ValidatorSet and []abci.ValidatorUpdate and will return a new tmtypes.ValidatorSet which has the -// provided validator updates applied to the provided validator set. -func ApplyValSetChanges(tb testing.TB, valSet *tmtypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) *tmtypes.ValidatorSet { - tb.Helper() - updates, err := tmtypes.PB2TM.ValidatorUpdates(valUpdates) - require.NoError(tb, err) - - // must copy since validator set will mutate with UpdateWithChangeSet - newVals := valSet.Copy() - err = newVals.UpdateWithChangeSet(updates) - require.NoError(tb, err) - - return newVals +// DeleteKey deletes the specified key from the ibc store. +func (chain *TestChain) DeleteKey(key []byte) { + storeKey := chain.GetSimApp().GetKey(exported.StoreKey) + kvStore := chain.GetContext().KVStore(storeKey) + kvStore.Delete(key) } diff --git a/ibc/testing/config.go b/ibc/testing/config.go index cdccbce0..4c1cba80 100644 --- a/ibc/testing/config.go +++ b/ibc/testing/config.go @@ -15,26 +15,22 @@ type ClientConfig interface { } type TendermintConfig struct { - TrustLevel ibctm.Fraction - TrustingPeriod time.Duration - UnbondingPeriod time.Duration - MaxClockDrift time.Duration - AllowUpdateAfterExpiry bool - AllowUpdateAfterMisbehaviour bool + TrustLevel ibctm.Fraction + TrustingPeriod time.Duration + UnbondingPeriod time.Duration + MaxClockDrift time.Duration } func NewTendermintConfig() *TendermintConfig { return &TendermintConfig{ - TrustLevel: DefaultTrustLevel, - TrustingPeriod: TrustingPeriod, - UnbondingPeriod: UnbondingPeriod, - MaxClockDrift: MaxClockDrift, - AllowUpdateAfterExpiry: false, - AllowUpdateAfterMisbehaviour: false, + TrustLevel: DefaultTrustLevel, + TrustingPeriod: TrustingPeriod, + UnbondingPeriod: UnbondingPeriod, + MaxClockDrift: MaxClockDrift, } } -func (tmcfg *TendermintConfig) GetClientType() string { +func (*TendermintConfig) GetClientType() string { return exported.Tendermint } @@ -51,9 +47,10 @@ func NewConnectionConfig() *ConnectionConfig { } type ChannelConfig struct { - PortID string - Version string - Order channeltypes.Order + PortID string + Version string + Order channeltypes.Order + ProposedUpgrade channeltypes.Upgrade } func NewChannelConfig() *ChannelConfig { diff --git a/ibc/testing/coordinator.go b/ibc/testing/coordinator.go index 4fae8ab1..4caa13bb 100644 --- a/ibc/testing/coordinator.go +++ b/ibc/testing/coordinator.go @@ -10,7 +10,9 @@ import ( ) var ( - ChainIDPrefix = "testchain" + ChainIDPrefix = "testchain" + // to disable revision format, set ChainIDSuffix to "" + ChainIDSuffix = "-1" globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) TimeIncrement = time.Second * 5 ) @@ -26,6 +28,7 @@ type Coordinator struct { // NewCoordinator initializes Coordinator with N EVM TestChain's (canto apps) and M Cosmos chains (Simulation Apps) func NewCoordinator(t *testing.T, nEVMChains, mCosmosChains int) *Coordinator { + t.Helper() chains := make(map[string]*TestChain) coord := &Coordinator{ T: t, @@ -183,7 +186,7 @@ func (coord *Coordinator) GetChain(chainID string) *TestChain { // GetChainID returns the chainID used for the provided index. func GetChainID(index int) string { - return ChainIDPrefix + strconv.Itoa(index) + return ChainIDPrefix + strconv.Itoa(index) + ChainIDSuffix } // GetChainID returns the chainID used for the provided index. @@ -208,42 +211,3 @@ func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { coord.IncrementTime() } } - -// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT -// using the OpenInit handshake call. -func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { - if err := path.EndpointA.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ConnOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} - -// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain -// with the state INIT using the OpenInit handshake call. -func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { - // NOTE: only creation of a capability for a transfer or mock port is supported - // Other applications must bind to the port in InitGenesis or modify this code. - - if err := path.EndpointA.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointB.ChanOpenInit(); err != nil { - return err - } - - if err := path.EndpointA.UpdateClient(); err != nil { - return err - } - - return path.EndpointB.UpdateClient() -} diff --git a/ibc/testing/endpoint.go b/ibc/testing/endpoint.go index 51eaa938..a240cd1a 100644 --- a/ibc/testing/endpoint.go +++ b/ibc/testing/endpoint.go @@ -2,9 +2,14 @@ package ibctesting import ( "fmt" + "strings" "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + abci "github.com/cometbft/cometbft/abci/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -79,7 +84,7 @@ func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, // NOTE: a solo machine client will be created with an empty diversifier. func (endpoint *Endpoint) CreateClient() (err error) { // ensure counterparty has committed state - endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) + endpoint.Counterparty.Chain.NextBlock() var ( clientState exported.ClientState @@ -94,8 +99,7 @@ func (endpoint *Endpoint) CreateClient() (err error) { height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) clientState = ibctm.NewClientState( endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, - height, commitmenttypes.GetSDKSpecs(), UpgradePath, - ) + height, commitmenttypes.GetSDKSpecs(), UpgradePath) consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() case exported.Solomachine: // TODO @@ -155,6 +159,56 @@ func (endpoint *Endpoint) UpdateClient() (err error) { return endpoint.Chain.sendMsgs(msg) } +// UpgradeChain will upgrade a chain's chainID to the next revision number. +// It will also update the counterparty client. +// TODO: implement actual upgrade chain functionality via scheduling an upgrade +// and upgrading the client via MsgUpgradeClient +// see reference https://github.com/cosmos/ibc-go/pull/1169 +func (endpoint *Endpoint) UpgradeChain() error { + if strings.TrimSpace(endpoint.Counterparty.ClientID) == "" { + return fmt.Errorf("cannot upgrade chain if there is no counterparty client") + } + + clientState := endpoint.Counterparty.GetClientState().(*ibctm.ClientState) + + // increment revision number in chainID + + oldChainID := clientState.ChainId + if !clienttypes.IsRevisionFormat(oldChainID) { + return fmt.Errorf("cannot upgrade chain which is not of revision format: %s", oldChainID) + } + + revisionNumber := clienttypes.ParseChainID(oldChainID) + newChainID, err := clienttypes.SetRevisionNumber(oldChainID, revisionNumber+1) + if err != nil { + return err + } + + // update chain + baseapp.SetChainID(newChainID)(endpoint.Chain.GetSimApp().GetBaseApp()) + endpoint.Chain.ChainID = newChainID + endpoint.Chain.CurrentHeader.ChainID = newChainID + endpoint.Chain.NextBlock() // commit changes + + // update counterparty client manually + clientState.ChainId = newChainID + clientState.LatestHeight = clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1) + endpoint.Counterparty.SetClientState(clientState) + + consensusState := &ibctm.ConsensusState{ + Timestamp: endpoint.Chain.LastHeader.GetTime(), + Root: commitmenttypes.NewMerkleRoot(endpoint.Chain.LastHeader.Header.GetAppHash()), + NextValidatorsHash: endpoint.Chain.LastHeader.Header.NextValidatorsHash, + } + endpoint.Counterparty.SetConsensusState(consensusState, clientState.GetLatestHeight()) + + // ensure the next update isn't identical to the one set in state + endpoint.Chain.Coordinator.IncrementTime() + endpoint.Chain.NextBlock() + + return endpoint.Counterparty.UpdateClient() +} + // ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. func (endpoint *Endpoint) ConnOpenInit() error { msg := connectiontypes.NewMsgConnectionOpenInit( @@ -179,12 +233,12 @@ func (endpoint *Endpoint) ConnOpenTry() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() + counterpartyClient, clientProof, consensusProof, consensusHeight, initProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenTry( endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod, - proofInit, proofClient, proofConsensus, + initProof, clientProof, consensusProof, proofHeight, consensusHeight, endpoint.Chain.SenderAccount.GetAddress().String(), ) @@ -194,7 +248,7 @@ func (endpoint *Endpoint) ConnOpenTry() error { } if endpoint.ConnectionID == "" { - endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.GetEvents()) + endpoint.ConnectionID, err = ParseConnectionIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) } @@ -206,11 +260,11 @@ func (endpoint *Endpoint) ConnOpenAck() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) - counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() + counterpartyClient, clientProof, consensusProof, consensusHeight, tryProof, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenAck( endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection - proofTry, proofClient, proofConsensus, + tryProof, clientProof, consensusProof, proofHeight, consensusHeight, ConnectionVersion, endpoint.Chain.SenderAccount.GetAddress().String(), @@ -239,28 +293,28 @@ func (endpoint *Endpoint) ConnOpenConfirm() error { // client state, proof of the counterparty consensus state, the consensus state height, proof of // the counterparty connection, and the proof height for all the proofs returned. func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( - clientState exported.ClientState, proofClient, - proofConsensus []byte, consensusHeight clienttypes.Height, - proofConnection []byte, proofHeight clienttypes.Height, + clientState exported.ClientState, clientProof, + consensusProof []byte, consensusHeight clienttypes.Height, + connectioProof []byte, proofHeight clienttypes.Height, ) { // obtain the client state on the counterparty chain clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) // query proof for the client state on the counterparty clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) - proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey) + clientProof, proofHeight = endpoint.Counterparty.QueryProof(clientKey) consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) // query proof for the consensus state on the counterparty consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) - proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) + consensusProof, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) // query proof for the connection on the counterparty connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) - proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) + connectioProof, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) - return + return clientState, clientProof, consensusProof, consensusHeight, connectioProof, proofHeight } // ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint. @@ -276,9 +330,14 @@ func (endpoint *Endpoint) ChanOpenInit() error { return err } - endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) + endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) + // update version to selected app version + // NOTE: this update must be performed after SendMsgs() + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version + return nil } @@ -303,13 +362,14 @@ func (endpoint *Endpoint) ChanOpenTry() error { } if endpoint.ChannelID == "" { - endpoint.ChannelID, err = ParseChannelIDFromEvents(res.GetEvents()) + endpoint.ChannelID, err = ParseChannelIDFromEvents(res.Events) require.NoError(endpoint.Chain.TB, err) } // update version to selected app version // NOTE: this update must be performed after the endpoint channelID is set endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + endpoint.Counterparty.ChannelConfig.Version = endpoint.GetChannel().Version return nil } @@ -328,7 +388,14 @@ func (endpoint *Endpoint) ChanOpenAck() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - return endpoint.Chain.sendMsgs(msg) + + if err = endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + + return nil } // ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. @@ -461,8 +528,9 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) } - proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) - nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + counterparty := endpoint.Counterparty + proof, proofHeight := counterparty.QueryProof(packetKey) + nextSeqRecv, found := counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(counterparty.Chain.GetContext(), counterparty.ChannelConfig.PortID, counterparty.ChannelID) require.True(endpoint.Chain.TB, found) timeoutMsg := channeltypes.NewMsgTimeout( @@ -490,24 +558,216 @@ func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) - proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + closedProof, _ := endpoint.Counterparty.QueryProof(channelKey) nextSeqRecv, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) require.True(endpoint.Chain.TB, found) - timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( + timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnCloseWithCounterpartyUpgradeSequence( packet, nextSeqRecv, - proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + proof, closedProof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + endpoint.Counterparty.GetChannel().UpgradeSequence, ) return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) } -// SetChannelClosed sets a channel state to CLOSED. -func (endpoint *Endpoint) SetChannelClosed() error { +// QueryChannelUpgradeProof returns all the proofs necessary to execute UpgradeTry/UpgradeAck/UpgradeOpen. +// It returns the proof for the channel on the endpoint's chain, the proof for the upgrade attempt on the +// endpoint's chain, and the height at which the proof was queried. +func (endpoint *Endpoint) QueryChannelUpgradeProof() ([]byte, []byte, clienttypes.Height) { + channelKey := host.ChannelKey(endpoint.ChannelConfig.PortID, endpoint.ChannelID) + channelProof, height := endpoint.QueryProof(channelKey) + + upgradeKey := host.ChannelUpgradeKey(endpoint.ChannelConfig.PortID, endpoint.ChannelID) + upgradeProof, _ := endpoint.QueryProof(upgradeKey) + + return channelProof, upgradeProof, height +} + +// ChanUpgradeInit sends a MsgChannelUpgradeInit on the associated endpoint. +// A default upgrade proposal is used with overrides from the ProposedUpgrade +// in the channel config, and submitted via governance proposal +func (endpoint *Endpoint) ChanUpgradeInit() error { + upgrade := endpoint.GetProposedUpgrade() + + // create upgrade init message via gov proposal and submit the proposal + msg := channeltypes.NewMsgChannelUpgradeInit( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + upgrade.Fields, + endpoint.Chain.GetSimApp().IBCKeeper.GetAuthority(), + ) + + proposal, err := govtypesv1.NewMsgSubmitProposal( + []sdk.Msg{msg}, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, govtypesv1.DefaultMinDepositTokens)), + endpoint.Chain.SenderAccount.GetAddress().String(), + endpoint.ChannelID, + "upgrade-init", + fmt.Sprintf("gov proposal for initialising channel upgrade: %s", endpoint.ChannelID), + false, + ) + require.NoError(endpoint.Chain.TB, err) + + var proposalID uint64 + res, err := endpoint.Chain.SendMsgs(proposal) + if err != nil { + return err + } + + proposalID, err = ParseProposalIDFromEvents(res.Events) + require.NoError(endpoint.Chain.TB, err) + + return VoteAndCheckProposalStatus(endpoint, proposalID) +} + +// ChanUpgradeTry sends a MsgChannelUpgradeTry on the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeTry() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + upgrade := endpoint.GetProposedUpgrade() + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + if !found { + return fmt.Errorf("could not find upgrade for channel %s", endpoint.ChannelID) + } + + msg := channeltypes.NewMsgChannelUpgradeTry( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + upgrade.Fields.ConnectionHops, + counterpartyUpgrade.Fields, + endpoint.Counterparty.GetChannel().UpgradeSequence, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeAck sends a MsgChannelUpgradeAck to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeAck() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeAck( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + counterpartyUpgrade, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeConfirm sends a MsgChannelUpgradeConfirm to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeConfirm() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelProof, upgradeProof, height := endpoint.Counterparty.QueryChannelUpgradeProof() + + counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeConfirm( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel().State, + counterpartyUpgrade, + channelProof, + upgradeProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeOpen sends a MsgChannelUpgradeOpen to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeOpen() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + channelProof, height := endpoint.Counterparty.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelUpgradeOpen( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel().State, + endpoint.Counterparty.GetChannel().UpgradeSequence, + channelProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeTimeout sends a MsgChannelUpgradeTimeout to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeTimeout() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + channelProof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelUpgradeTimeout( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + endpoint.Counterparty.GetChannel(), + channelProof, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// ChanUpgradeCancel sends a MsgChannelUpgradeCancel to the associated endpoint. +func (endpoint *Endpoint) ChanUpgradeCancel() error { + err := endpoint.UpdateClient() + require.NoError(endpoint.Chain.TB, err) + + errorReceiptKey := host.ChannelUpgradeErrorKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proofErrorReceipt, height := endpoint.Counterparty.Chain.QueryProof(errorReceiptKey) + + errorReceipt, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + require.True(endpoint.Chain.TB, found) + + msg := channeltypes.NewMsgChannelUpgradeCancel( + endpoint.ChannelConfig.PortID, + endpoint.ChannelID, + errorReceipt, + proofErrorReceipt, + height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(msg) +} + +// SetChannelState sets a channel state +func (endpoint *Endpoint) SetChannelState(state channeltypes.State) error { channel := endpoint.GetChannel() - channel.State = channeltypes.CLOSED + channel.State = state endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) @@ -568,6 +828,25 @@ func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) { endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) } +// GetChannelUpgrade retrieves an IBC Channel Upgrade for the endpoint. The upgrade +// is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetChannelUpgrade() channeltypes.Upgrade { + upgrade, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.TB, found) + + return upgrade +} + +// SetChannelUpgrade sets the channel upgrade for this endpoint. +func (endpoint *Endpoint) SetChannelUpgrade(upgrade channeltypes.Upgrade) { + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, upgrade) +} + +// SetChannelCounterpartyUpgrade sets the channel counterparty upgrade for this endpoint. +func (endpoint *Endpoint) SetChannelCounterpartyUpgrade(upgrade channeltypes.Upgrade) { + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetCounterpartyUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, upgrade) +} + // QueryClientStateProof performs and abci query for a client stat associated // with this endpoint and returns the ClientState along with the proof. func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) { @@ -575,7 +854,44 @@ func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) clientState := endpoint.GetClientState() clientKey := host.FullClientStateKey(endpoint.ClientID) - proofClient, _ := endpoint.QueryProof(clientKey) + clientProof, _ := endpoint.QueryProof(clientKey) + + return clientState, clientProof +} + +// GetProposedUpgrade returns a valid upgrade which can be used for UpgradeInit and UpgradeTry. +// By default, the endpoint's existing channel fields will be used for the upgrade fields and +// a sane default timeout will be used by querying the counterparty's latest height. +// If any non-empty values are specified in the ChannelConfig's ProposedUpgrade, +// those values will be used in the returned upgrade. +func (endpoint *Endpoint) GetProposedUpgrade() channeltypes.Upgrade { + // create a default upgrade + upgrade := channeltypes.Upgrade{ + Fields: channeltypes.UpgradeFields{ + Ordering: endpoint.ChannelConfig.Order, + ConnectionHops: []string{endpoint.ConnectionID}, + Version: endpoint.ChannelConfig.Version, + }, + Timeout: channeltypes.NewTimeout(endpoint.Counterparty.Chain.GetTimeoutHeight(), 0), + NextSequenceSend: 0, + } + + override := endpoint.ChannelConfig.ProposedUpgrade + if override.Timeout.IsValid() { + upgrade.Timeout = override.Timeout + } + + if override.Fields.Ordering != channeltypes.NONE { + upgrade.Fields.Ordering = override.Fields.Ordering + } + + if override.Fields.Version != "" { + upgrade.Fields.Version = override.Fields.Version + } + + if len(override.Fields.ConnectionHops) != 0 { + upgrade.Fields.ConnectionHops = override.Fields.ConnectionHops + } - return clientState, proofClient + return upgrade } diff --git a/ibc/testing/events.go b/ibc/testing/events.go index 1c14ee0d..b26b9706 100644 --- a/ibc/testing/events.go +++ b/ibc/testing/events.go @@ -2,8 +2,11 @@ package ibctesting import ( "fmt" + "slices" "strconv" + testifysuite "github.com/stretchr/testify/suite" + abci "github.com/cometbft/cometbft/abci/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -11,14 +14,16 @@ import ( channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ) +type EventsMap map[string]map[string]string + // ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the // client identifier. func ParseClientIDFromEvents(events []abci.Event) (string, error) { for _, ev := range events { if ev.Type == clienttypes.EventTypeCreateClient { for _, attr := range ev.Attributes { - if string(attr.Key) == clienttypes.AttributeKeyClientID { - return string(attr.Value), nil + if attr.Key == clienttypes.AttributeKeyClientID { + return attr.Value, nil } } } @@ -33,8 +38,8 @@ func ParseConnectionIDFromEvents(events []abci.Event) (string, error) { if ev.Type == connectiontypes.EventTypeConnectionOpenInit || ev.Type == connectiontypes.EventTypeConnectionOpenTry { for _, attr := range ev.Attributes { - if string(attr.Key) == connectiontypes.AttributeKeyConnectionID { - return string(attr.Value), nil + if attr.Key == connectiontypes.AttributeKeyConnectionID { + return attr.Value, nil } } } @@ -48,8 +53,8 @@ func ParseChannelIDFromEvents(events []abci.Event) (string, error) { for _, ev := range events { if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { for _, attr := range ev.Attributes { - if string(attr.Key) == channeltypes.AttributeKeyChannelID { - return string(attr.Value), nil + if attr.Key == channeltypes.AttributeKeyChannelID { + return attr.Value, nil } } } @@ -64,13 +69,12 @@ func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { if ev.Type == channeltypes.EventTypeSendPacket { packet := channeltypes.Packet{} for _, attr := range ev.Attributes { - - switch string(attr.Key) { - case channeltypes.AttributeKeyData: + switch attr.Key { + case channeltypes.AttributeKeyData: //nolint:staticcheck // DEPRECATED packet.Data = []byte(attr.Value) case channeltypes.AttributeKeySequence: - seq, err := strconv.ParseUint(string(attr.Value), 10, 64) + seq, err := strconv.ParseUint(attr.Value, 10, 64) if err != nil { return channeltypes.Packet{}, err } @@ -78,19 +82,19 @@ func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { packet.Sequence = seq case channeltypes.AttributeKeySrcPort: - packet.SourcePort = string(attr.Value) + packet.SourcePort = attr.Value case channeltypes.AttributeKeySrcChannel: - packet.SourceChannel = string(attr.Value) + packet.SourceChannel = attr.Value case channeltypes.AttributeKeyDstPort: - packet.DestinationPort = string(attr.Value) + packet.DestinationPort = attr.Value case channeltypes.AttributeKeyDstChannel: - packet.DestinationChannel = string(attr.Value) + packet.DestinationChannel = attr.Value case channeltypes.AttributeKeyTimeoutHeight: - height, err := clienttypes.ParseHeight(string(attr.Value)) + height, err := clienttypes.ParseHeight(attr.Value) if err != nil { return channeltypes.Packet{}, err } @@ -98,7 +102,7 @@ func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { packet.TimeoutHeight = height case channeltypes.AttributeKeyTimeoutTimestamp: - timestamp, err := strconv.ParseUint(string(attr.Value), 10, 64) + timestamp, err := strconv.ParseUint(attr.Value, 10, 64) if err != nil { return channeltypes.Packet{}, err } @@ -122,7 +126,7 @@ func ParseAckFromEvents(events []abci.Event) ([]byte, error) { for _, ev := range events { if ev.Type == channeltypes.EventTypeWriteAck { for _, attr := range ev.Attributes { - if string(attr.Key) == channeltypes.AttributeKeyAck { + if attr.Key == channeltypes.AttributeKeyAck { //nolint:staticcheck // DEPRECATED return []byte(attr.Value), nil } } @@ -130,3 +134,81 @@ func ParseAckFromEvents(events []abci.Event) ([]byte, error) { } return nil, fmt.Errorf("acknowledgement event attribute not found") } + +// ParseProposalIDFromEvents parses events emitted from MsgSubmitProposal and returns proposalID +func ParseProposalIDFromEvents(events []abci.Event) (uint64, error) { + for _, event := range events { + for _, attribute := range event.Attributes { + if attribute.Key == "proposal_id" { + return strconv.ParseUint(attribute.Value, 10, 64) + } + } + } + + return 0, fmt.Errorf("proposalID event attribute not found") +} + +// AssertEventsLegacy asserts that expected events are present in the actual events. +// Expected map needs to be a subset of actual events to pass. +func AssertEventsLegacy( + suite *testifysuite.Suite, + expected EventsMap, + actual []abci.Event, +) { + hasEvents := make(map[string]bool) + for eventType := range expected { + hasEvents[eventType] = false + } + + for _, event := range actual { + expEvent, eventFound := expected[event.Type] + if eventFound { + hasEvents[event.Type] = true + suite.Require().Len(event.Attributes, len(expEvent)) + for _, attr := range event.Attributes { + expValue, found := expEvent[attr.Key] + suite.Require().True(found) + suite.Require().Equal(expValue, attr.Value) + } + } + } + + for eventName, hasEvent := range hasEvents { + suite.Require().True(hasEvent, "event: %s was not found in events", eventName) + } +} + +// AssertEvents asserts that expected events are present in the actual events. +func AssertEvents( + suite *testifysuite.Suite, + expected []abci.Event, + actual []abci.Event, +) { + foundEvents := make(map[int]bool) + + for i, expectedEvent := range expected { + for _, actualEvent := range actual { + // the actual event will have an extra attribute added automatically + // by Cosmos SDK since v0.50, that's why we subtract 1 when comparing + // with the number of attributes in the expected event. + if expectedEvent.Type == actualEvent.Type && (len(expectedEvent.Attributes) == len(actualEvent.Attributes)-1) { + // multiple events with the same type may be emitted, only mark the expected event as found + // if all of the attributes match + attributeMatch := true + for _, expectedAttr := range expectedEvent.Attributes { + // any expected attributes that are not contained in the actual events will cause this event + // not to match + attributeMatch = attributeMatch && slices.Contains(actualEvent.Attributes, expectedAttr) + } + + if attributeMatch { + foundEvents[i] = true + } + } + } + } + + for i, expectedEvent := range expected { + suite.Require().True(foundEvents[i], "event: %s was not found in events", expectedEvent.Type) + } +} diff --git a/ibc/testing/path.go b/ibc/testing/path.go index 64785c9b..64738b1c 100644 --- a/ibc/testing/path.go +++ b/ibc/testing/path.go @@ -32,13 +32,12 @@ func NewPath(chainA, chainB *TestChain) *Path { } } +// NewTransferPath constructs a new path between each chain suitable for use with +// the transfer module. func NewTransferPath(chainA, chainB *TestChain) *Path { path := NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = TransferPort path.EndpointB.ChannelConfig.PortID = TransferPort - - path.EndpointA.ChannelConfig.Order = channeltypes.UNORDERED - path.EndpointB.ChannelConfig.Order = channeltypes.UNORDERED path.EndpointA.ChannelConfig.Version = transfertypes.Version path.EndpointB.ChannelConfig.Version = transfertypes.Version diff --git a/ibc/testing/simapp/README.md b/ibc/testing/simapp/README.md deleted file mode 100644 index a3488dc0..00000000 --- a/ibc/testing/simapp/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# simapp - -simapp is an application built using the Cosmos SDK for testing and educational purposes. - -## Running testnets with `simd` - -If you want to spin up a quick testnet with your friends, you can follow these steps. -Unless otherwise noted, every step must be done by everyone who wants to participate -in this testnet. - -1. `$ make build`. This will build the `simd` binary and install it in your Cosmos SDK repo, - inside a new `build` directory. The following instructions are run from inside - that directory. -2. If you've run `simd` before, you may need to reset your database before starting a new - testnet: `$ ./simd unsafe-reset-all` -3. `$ ./simd init [moniker]`. This will initialize a new working directory, by default at - `~/.simapp`. You need a provide a "moniker," but it doesn't matter what it is. -4. `$ ./simd keys add [key_name]`. This will create a new key, with a name of your choosing. - Save the output of this command somewhere; you'll need the address generated here later. -5. `$ ./simd add-genesis-account $(simd keys show [key_name] -a) [amount]`, where `key_name` - is the same key name as before; and `amount` is something like `10000000000000000000000000stake`. -6. `$ ./simd gentx [key_name] [amount] --chain-id [chain-id]`. This will create the - genesis transaction for your new chain. -7. Now, one person needs to create the genesis file `genesis.json` using the genesis transactions - from every participant, by gathering all the genesis transactions under `config/gentx` and then - calling `./simd collect-gentxs`. This will create a new `genesis.json` file that includes data - from all the validators (we sometimes call it the "super genesis file" to distinguish it from - single-validator genesis files). -8. Once you've received the super genesis file, overwrite your original `genesis.json` file with - the new super `genesis.json`. -9. Modify your `config/config.toml` (in the simapp working directory) to include the other participants as - persistent peers: - - ```text - # Comma separated list of nodes to keep persistent connections to - persistent_peers = "[validator address]@[ip address]:[port],[validator address]@[ip address]:[port]" - ``` - - You can find `validator address` by running `./simd tendermint show-node-id`. (It will be hex-encoded.) - By default, `port` is 26656. -10. Now you can start your nodes: `$ ./simd start`. - -Now you have a small testnet that you can use to try out changes to the Cosmos SDK or Tendermint! - -NOTE: Sometimes creating the network through the `collect-gentxs` will fail, and validators will start -in a funny state (and then panic). If this happens, you can try to create and start the network first -with a single validator and then add additional validators using a `create-validator` transaction. diff --git a/ibc/testing/simapp/app.go b/ibc/testing/simapp/app.go index 5a329c5a..20182c29 100644 --- a/ibc/testing/simapp/app.go +++ b/ibc/testing/simapp/app.go @@ -214,6 +214,7 @@ type SimApp struct { // make IBC modules public for test purposes // these modules are never directly routed to by the IBC Router + IBCMockModule ibcmock.IBCModule ICAAuthModule ibcmock.IBCModule FeeMockModule ibcmock.IBCModule @@ -340,6 +341,7 @@ func NewSimApp( // NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do // not replicate if you do not need to test core IBC or light clients. scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName) + scopedIBCMockBlockUpgradeKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.MockBlockUpgrade) scopedFeeMockKeeper := app.CapabilityKeeper.ScopeToModule(MockFeePort) scopedICAMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName + icacontrollertypes.SubModuleName) @@ -456,10 +458,11 @@ func NewSimApp( app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack - app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, - app.AccountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, + scopedICAHostKeeper, app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter()) // Create IBC Router ibcRouter := porttypes.NewRouter() @@ -485,8 +488,16 @@ func NewSimApp( // The mock module is used for testing IBC mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) + app.IBCMockModule = mockIBCModule ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) + // Mock IBC app wrapped with a middleware which does not implement the UpgradeableModule interface. + // NOTE: this is used to test integration with apps which do not yet fulfill the UpgradeableModule interface and error when + // an upgrade is tried on the channel. + mockBlockUpgradeIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.MockBlockUpgrade, scopedIBCMockBlockUpgradeKeeper)) + mockBlockUpgradeMw := ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockBlockUpgradeIBCModule.IBCApp) + ibcRouter.AddRoute(ibcmock.MockBlockUpgrade, mockBlockUpgradeMw) + // Create Transfer Stack // SendPacket, since it is originating from the application to core IBC: // transferKeeper.SendPacket -> fee.SendPacket -> channel.SendPacket diff --git a/ibc/testing/simapp/genesis_account.go b/ibc/testing/simapp/genesis_account.go deleted file mode 100644 index 5c9c7f9a..00000000 --- a/ibc/testing/simapp/genesis_account.go +++ /dev/null @@ -1,47 +0,0 @@ -package simapp - -import ( - "errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -var _ authtypes.GenesisAccount = (*SimGenesisAccount)(nil) - -// SimGenesisAccount defines a type that implements the GenesisAccount interface -// to be used for simulation accounts in the genesis state. -type SimGenesisAccount struct { - *authtypes.BaseAccount - - // vesting account fields - OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // total vesting coins upon initialization - DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // delegated vested coins at time of delegation - DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // delegated vesting coins at time of delegation - StartTime int64 `json:"start_time" yaml:"start_time"` // vesting start time (UNIX Epoch time) - EndTime int64 `json:"end_time" yaml:"end_time"` // vesting end time (UNIX Epoch time) - - // module account fields - ModuleName string `json:"module_name" yaml:"module_name"` // name of the module account - ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"` // permissions of module account -} - -// Validate checks for errors on the vesting and module account parameters -func (sga SimGenesisAccount) Validate() error { - if !sga.OriginalVesting.IsZero() { - if sga.StartTime >= sga.EndTime { - return errors.New("vesting start-time cannot be before end-time") - } - } - - if sga.ModuleName != "" { - ma := authtypes.ModuleAccount{ - BaseAccount: sga.BaseAccount, Name: sga.ModuleName, Permissions: sga.ModulePermissions, - } - if err := ma.Validate(); err != nil { - return err - } - } - - return sga.BaseAccount.Validate() -} diff --git a/ibc/testing/simapp/params/amino.go b/ibc/testing/simapp/params/amino.go deleted file mode 100644 index d603987d..00000000 --- a/ibc/testing/simapp/params/amino.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build test_amino -// +build test_amino - -package params - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" -) - -// MakeTestEncodingConfig creates an EncodingConfig for an amino based test configuration. -// This function should be used only internally (in the SDK). -// App user should'nt create new codecs - use the app.AppCodec instead. -// [DEPRECATED] -func MakeTestEncodingConfig() EncodingConfig { - cdc := codec.NewLegacyAmino() - interfaceRegistry := types.NewInterfaceRegistry() - marshaler := codec.NewAminoCodec(cdc) - - return EncodingConfig{ - InterfaceRegistry: interfaceRegistry, - Marshaler: marshaler, - TxConfig: legacytx.StdTxConfig{Cdc: cdc}, - Amino: cdc, - } -} diff --git a/ibc/testing/simapp/params/doc.go b/ibc/testing/simapp/params/doc.go deleted file mode 100644 index a2f3620a..00000000 --- a/ibc/testing/simapp/params/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Package params defines the simulation parameters in the simapp. - -It contains the default weights used for each transaction used on the module's -simulation. These weights define the chance for a transaction to be simulated at -any given operation. - -You can replace the default values for the weights by providing a params.json -file with the weights defined for each of the transaction operations: - - { - "op_weight_msg_send": 60, - "op_weight_msg_delegate": 100, - } - -In the example above, the `MsgSend` has 60% chance to be simulated, while the -`MsgDelegate` will always be simulated. -*/ -package params diff --git a/ibc/testing/simapp/params/encoding.go b/ibc/testing/simapp/params/encoding.go deleted file mode 100644 index 8ff9ea04..00000000 --- a/ibc/testing/simapp/params/encoding.go +++ /dev/null @@ -1,16 +0,0 @@ -package params - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" -) - -// EncodingConfig specifies the concrete encoding types to use for a given app. -// This is provided for compatibility between protobuf and amino implementations. -type EncodingConfig struct { - InterfaceRegistry types.InterfaceRegistry - Codec codec.Codec - TxConfig client.TxConfig - Amino *codec.LegacyAmino -} diff --git a/ibc/testing/simapp/params/params.go b/ibc/testing/simapp/params/params.go deleted file mode 100644 index b6aa5fb5..00000000 --- a/ibc/testing/simapp/params/params.go +++ /dev/null @@ -1,7 +0,0 @@ -package params - -// Simulation parameter constants -const ( - StakePerAccount = "stake_per_account" - InitiallyBondedValidators = "initially_bonded_validators" -) diff --git a/ibc/testing/simapp/params/proto.go b/ibc/testing/simapp/params/proto.go deleted file mode 100644 index 4270c2b0..00000000 --- a/ibc/testing/simapp/params/proto.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build !test_amino -// +build !test_amino - -package params - -import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/x/auth/tx" -) - -// MakeTestEncodingConfig creates an EncodingConfig for a non-amino based test configuration. -// This function should be used only internally (in the SDK). -// App user should'nt create new codecs - use the app.AppCodec instead. -// [DEPRECATED] -func MakeTestEncodingConfig() EncodingConfig { - cdc := codec.NewLegacyAmino() - interfaceRegistry := types.NewInterfaceRegistry() - protoCdc := codec.NewProtoCodec(interfaceRegistry) - - return EncodingConfig{ - InterfaceRegistry: interfaceRegistry, - Codec: protoCdc, - TxConfig: tx.NewTxConfig(protoCdc, tx.DefaultSignModes), - Amino: cdc, - } -} diff --git a/ibc/testing/simapp/params/weights.go b/ibc/testing/simapp/params/weights.go deleted file mode 100644 index 81400a2f..00000000 --- a/ibc/testing/simapp/params/weights.go +++ /dev/null @@ -1,28 +0,0 @@ -package params - -// Default simulation operation weights for messages and gov proposals -const ( - DefaultWeightMsgSend int = 100 - DefaultWeightMsgMultiSend int = 10 - DefaultWeightMsgSetWithdrawAddress int = 50 - DefaultWeightMsgWithdrawDelegationReward int = 50 - DefaultWeightMsgWithdrawValidatorCommission int = 50 - DefaultWeightMsgFundCommunityPool int = 50 - DefaultWeightMsgDeposit int = 100 - DefaultWeightMsgVote int = 67 - DefaultWeightMsgVoteWeighted int = 33 - DefaultWeightMsgUnjail int = 100 - DefaultWeightMsgCreateValidator int = 100 - DefaultWeightMsgEditValidator int = 5 - DefaultWeightMsgDelegate int = 100 - DefaultWeightMsgUndelegate int = 100 - DefaultWeightMsgBeginRedelegate int = 100 - - DefaultWeightCommunitySpendProposal int = 5 - DefaultWeightTextProposal int = 5 - DefaultWeightParamChangeProposal int = 5 - - // feegrant - DefaultWeightGrantFeeAllowance int = 100 - DefaultWeightRevokeFeeAllowance int = 100 -) diff --git a/ibc/testing/simapp/simd/cmd/cmd_test.go b/ibc/testing/simapp/simd/cmd/cmd_test.go deleted file mode 100644 index 9216ce75..00000000 --- a/ibc/testing/simapp/simd/cmd/cmd_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package cmd_test - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - - "github.com/cosmos/ibc-go/v8/testing/simapp" - "github.com/cosmos/ibc-go/v8/testing/simapp/simd/cmd" -) - -func TestInitCmd(t *testing.T) { - rootCmd := cmd.NewRootCmd() - rootCmd.SetArgs([]string{ - "init", // Test the init cmd - "simapp-test", // Moniker - fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists - }) - - require.NoError(t, svrcmd.Execute(rootCmd, "", simapp.DefaultNodeHome)) -} diff --git a/ibc/testing/simapp/simd/cmd/root.go b/ibc/testing/simapp/simd/cmd/root.go deleted file mode 100644 index 58990794..00000000 --- a/ibc/testing/simapp/simd/cmd/root.go +++ /dev/null @@ -1,372 +0,0 @@ -package cmd - -import ( - "errors" - "io" - "os" - - dbm "github.com/cosmos/cosmos-db" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "cosmossdk.io/client/v2/autocli" - "cosmossdk.io/log" - confixcmd "cosmossdk.io/tools/confix/cmd" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/config" - "github.com/cosmos/cosmos-sdk/client/debug" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/client/keys" - "github.com/cosmos/cosmos-sdk/client/pruning" - "github.com/cosmos/cosmos-sdk/client/rpc" - "github.com/cosmos/cosmos-sdk/client/snapshot" - "github.com/cosmos/cosmos-sdk/codec" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/server" - serverconfig "github.com/cosmos/cosmos-sdk/server/config" - servertypes "github.com/cosmos/cosmos-sdk/server/types" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - "github.com/cosmos/cosmos-sdk/x/auth/tx" - txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" - "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/crisis" - genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - - cmtcfg "github.com/cometbft/cometbft/config" - - "github.com/cosmos/ibc-go/v8/testing/simapp" - "github.com/cosmos/ibc-go/v8/testing/simapp/params" -) - -// NewRootCmd creates a new root command for simd. It is called once in the -// main function. -func NewRootCmd() *cobra.Command { - // we "pre"-instantiate the application for getting the injected/configured encoding configuration - // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) - tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(tempDir())) - encodingConfig := params.EncodingConfig{ - InterfaceRegistry: tempApp.InterfaceRegistry(), - Codec: tempApp.AppCodec(), - TxConfig: tempApp.TxConfig(), - Amino: tempApp.LegacyAmino(), - } - - initClientCtx := client.Context{}. - WithCodec(encodingConfig.Codec). - WithInterfaceRegistry(encodingConfig.InterfaceRegistry). - WithLegacyAmino(encodingConfig.Amino). - WithInput(os.Stdin). - WithAccountRetriever(types.AccountRetriever{}). - WithHomeDir(simapp.DefaultNodeHome). - WithViper("") // In simapp, we don't use any prefix for env variables. - - rootCmd := &cobra.Command{ - Use: "simd", - Short: "simulation app", - SilenceErrors: true, - PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { - // set the default command outputs - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) - - initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) - initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) - if err != nil { - return err - } - - initClientCtx, err = config.ReadFromClientConfig(initClientCtx) - if err != nil { - return err - } - - // This needs to go after ReadFromClientConfig, as that function - // sets the RPC client needed for SIGN_MODE_TEXTUAL. This sign mode - // is only available if the client is online. - if !initClientCtx.Offline { - txConfigOpts := tx.ConfigOptions{ - EnabledSignModes: append(tx.DefaultSignModes, signing.SignMode_SIGN_MODE_TEXTUAL), - TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), - } - txConfigWithTextual, err := tx.NewTxConfigWithOptions( - codec.NewProtoCodec(encodingConfig.InterfaceRegistry), - txConfigOpts, - ) - if err != nil { - return err - } - initClientCtx = initClientCtx.WithTxConfig(txConfigWithTextual) - } - - if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { - return err - } - - customAppTemplate, customAppConfig := initAppConfig() - customCMTConfig := initCometBFTConfig() - - return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customCMTConfig) - }, - } - - initRootCmd(rootCmd, encodingConfig, tempApp.BasicModuleManager) - - autoCliOpts, err := enrichAutoCliOpts(tempApp.AutoCliOpts(), initClientCtx) - if err != nil { - panic(err) - } - - if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { - panic(err) - } - - return rootCmd -} - -func enrichAutoCliOpts(autoCliOpts autocli.AppOptions, clientCtx client.Context) (autocli.AppOptions, error) { - autoCliOpts.AddressCodec = addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()) - autoCliOpts.ValidatorAddressCodec = addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()) - autoCliOpts.ConsensusAddressCodec = addresscodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()) - - var err error - clientCtx, err = config.ReadFromClientConfig(clientCtx) - if err != nil { - return autocli.AppOptions{}, err - } - - autoCliOpts.ClientCtx = clientCtx - autoCliOpts.Keyring, err = keyring.NewAutoCLIKeyring(clientCtx.Keyring) - if err != nil { - return autocli.AppOptions{}, err - } - - return autoCliOpts, nil -} - -// initCometBFTConfig helps to override default CometBFT Config values. -// return cmtcfg.DefaultConfig if no custom configuration is required for the application. -func initCometBFTConfig() *cmtcfg.Config { - cfg := cmtcfg.DefaultConfig() - - // these values put a higher strain on node memory - // cfg.P2P.MaxNumInboundPeers = 100 - // cfg.P2P.MaxNumOutboundPeers = 40 - - return cfg -} - -// initAppConfig helps to override default appConfig template and configs. -// return "", nil if no custom configuration is required for the application. -func initAppConfig() (string, interface{}) { - // The following code snippet is just for reference. - - // WASMConfig defines configuration for the wasm module. - type WASMConfig struct { - // This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries - QueryGasLimit uint64 `mapstructure:"query_gas_limit"` - - // Address defines the gRPC-web server to listen on - LruSize uint64 `mapstructure:"lru_size"` - } - - type CustomAppConfig struct { - serverconfig.Config - - WASM WASMConfig `mapstructure:"wasm"` - } - - // Optionally allow the chain developer to overwrite the SDK's default - // server config. - srvCfg := serverconfig.DefaultConfig() - // The SDK's default minimum gas price is set to "" (empty value) inside - // app.toml. If left empty by validators, the node will halt on startup. - // However, the chain developer can set a default app.toml value for their - // validators here. - // - // In summary: - // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their - // own app.toml config, - // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their - // own app.toml to override, or use this default value. - // - // In simapp, we set the min gas prices to 0. - srvCfg.MinGasPrices = "0stake" - // srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default - - customAppConfig := CustomAppConfig{ - Config: *srvCfg, - WASM: WASMConfig{ - LruSize: 1, - QueryGasLimit: 300000, - }, - } - - customAppTemplate := serverconfig.DefaultConfigTemplate + ` -[wasm] -# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries -query_gas_limit = 300000 -# This is the number of wasm vm instances we keep cached in memory for speed-up -# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally -lru_size = 0` - - return customAppTemplate, customAppConfig -} - -func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, basicManager module.BasicManager) { - cfg := sdk.GetConfig() - cfg.Seal() - - rootCmd.AddCommand( - genutilcli.InitCmd(basicManager, simapp.DefaultNodeHome), - debug.Cmd(), - confixcmd.ConfigCommand(), - pruning.Cmd(newApp, simapp.DefaultNodeHome), - snapshot.Cmd(newApp), - server.QueryBlockResultsCmd(), - ) - - server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, appExport, addModuleInitFlags) - - // add keybase, auxiliary RPC, query, genesis, and tx child commands - rootCmd.AddCommand( - server.StatusCommand(), - genesisCommand(encodingConfig, basicManager), - txCommand(), - queryCommand(), - keys.Commands(), - ) -} - -func addModuleInitFlags(startCmd *cobra.Command) { - crisis.AddModuleInitFlags(startCmd) -} - -func queryCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "query", - Aliases: []string{"q"}, - Short: "Querying subcommands", - DisableFlagParsing: false, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - rpc.ValidatorCommand(), - server.QueryBlockCmd(), - authcmd.QueryTxsByEventsCmd(), - server.QueryBlocksCmd(), - authcmd.QueryTxCmd(), - authcmd.GetSimulateCmd(), - ) - - return cmd -} - -func txCommand() *cobra.Command { - cmd := &cobra.Command{ - Use: "tx", - Short: "Transactions subcommands", - DisableFlagParsing: false, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - cmd.AddCommand( - authcmd.GetSignCommand(), - authcmd.GetSignBatchCommand(), - authcmd.GetMultiSignCommand(), - authcmd.GetMultiSignBatchCmd(), - authcmd.GetValidateSignaturesCommand(), - authcmd.GetBroadcastCommand(), - authcmd.GetEncodeCommand(), - authcmd.GetDecodeCommand(), - authcmd.GetSimulateCmd(), - ) - - return cmd -} - -// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter -func genesisCommand(encodingConfig params.EncodingConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command { - cmd := genutilcli.Commands(encodingConfig.TxConfig, basicManager, simapp.DefaultNodeHome) - - for _, subCmd := range cmds { - cmd.AddCommand(subCmd) - } - return cmd -} - -// newApp creates the application -func newApp( - logger log.Logger, - db dbm.DB, - traceStore io.Writer, - appOpts servertypes.AppOptions, -) servertypes.Application { - baseappOptions := server.DefaultBaseappOptions(appOpts) - - return simapp.NewSimApp( - logger, db, traceStore, true, - appOpts, - baseappOptions..., - ) -} - -// appExport creates a new simapp (optionally at a given height) and exports state. -func appExport( - logger log.Logger, - db dbm.DB, - traceStore io.Writer, - height int64, - forZeroHeight bool, - jailAllowedAddrs []string, - appOpts servertypes.AppOptions, - modulesToExport []string, -) (servertypes.ExportedApp, error) { - var simApp *simapp.SimApp - - // this check is necessary as we use the flag in x/upgrade. - // we can exit more gracefully by checking the flag here. - homePath, ok := appOpts.Get(flags.FlagHome).(string) - if !ok || homePath == "" { - return servertypes.ExportedApp{}, errors.New("application home not set") - } - - viperAppOpts, ok := appOpts.(*viper.Viper) - if !ok { - return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") - } - - // overwrite the FlagInvCheckPeriod - viperAppOpts.Set(server.FlagInvCheckPeriod, 1) - appOpts = viperAppOpts - - if height != -1 { - simApp = simapp.NewSimApp(logger, db, traceStore, false, appOpts) - - if err := simApp.LoadHeight(height); err != nil { - return servertypes.ExportedApp{}, err - } - } else { - simApp = simapp.NewSimApp(logger, db, traceStore, true, appOpts) - } - - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) -} - -var tempDir = func() string { - dir, err := os.MkdirTemp("", "simapp") - if err != nil { - dir = simapp.DefaultNodeHome - } - defer os.RemoveAll(dir) - - return dir -} diff --git a/ibc/testing/simapp/simd/main.go b/ibc/testing/simapp/simd/main.go deleted file mode 100644 index 153d8468..00000000 --- a/ibc/testing/simapp/simd/main.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "os" - - "cosmossdk.io/log" - - svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" - - "github.com/cosmos/ibc-go/v8/testing/simapp" - "github.com/cosmos/ibc-go/v8/testing/simapp/simd/cmd" -) - -func main() { - rootCmd := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, "", simapp.DefaultNodeHome); err != nil { - log.NewLogger(rootCmd.OutOrStderr()).Error("failure when running app", "err", err) - os.Exit(1) - } -} diff --git a/ibc/testing/simapp/test_helpers.go b/ibc/testing/simapp/test_helpers.go index a3c4e876..d0e74dda 100644 --- a/ibc/testing/simapp/test_helpers.go +++ b/ibc/testing/simapp/test_helpers.go @@ -12,6 +12,7 @@ import ( "cosmossdk.io/log" sdkmath "cosmossdk.io/math" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" bam "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -107,7 +108,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *cmttypes.ValidatorSet, genAccs // // CONTRACT: BeginBlock must be called before this function. func SignAndDeliver( - tb testing.TB, txCfg client.TxConfig, app *bam.BaseApp, msgs []sdk.Msg, + tb testing.TB, txCfg client.TxConfig, app *bam.BaseApp, header cmtproto.Header, msgs []sdk.Msg, chainID string, accNums, accSeqs []uint64, expPass bool, blockTime time.Time, nextValHash []byte, priv ...cryptotypes.PrivKey, ) (*abci.ResponseFinalizeBlock, error) { tb.Helper() @@ -132,5 +133,21 @@ func SignAndDeliver( Time: blockTime, NextValidatorsHash: nextValHash, Txs: [][]byte{txBytes}, + ProposerAddress: header.ProposerAddress, }) } + +// ApplyValSetChanges takes in cmttypes.ValidatorSet and []abci.ValidatorUpdate and will return a new cmttypes.ValidatorSet which has the +// provided validator updates applied to the provided validator set. +func ApplyValSetChanges(tb testing.TB, valSet *cmttypes.ValidatorSet, valUpdates []abci.ValidatorUpdate) *cmttypes.ValidatorSet { + tb.Helper() + updates, err := cmttypes.PB2TM.ValidatorUpdates(valUpdates) + require.NoError(tb, err) + + // must copy since validator set will mutate with UpdateWithChangeSet + newVals := valSet.Copy() + err = newVals.UpdateWithChangeSet(updates) + require.NoError(tb, err) + + return newVals +} diff --git a/ibc/testing/simapp/upgrades/upgrades.go b/ibc/testing/simapp/upgrades/upgrades.go deleted file mode 100644 index ff9b6579..00000000 --- a/ibc/testing/simapp/upgrades/upgrades.go +++ /dev/null @@ -1,116 +0,0 @@ -package upgrades - -import ( - "context" - - storetypes "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - consensusparamskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" - paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" - - capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" - v6 "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/migrations/v6" - clientkeeper "github.com/cosmos/ibc-go/v8/modules/core/02-client/keeper" - "github.com/cosmos/ibc-go/v8/modules/core/exported" - ibctmmigrations "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/migrations" -) - -const ( - // V5 defines the upgrade name for the ibc-go/v5 upgrade handler. - V5 = "normal upgrade" // NOTE: keeping as "normal upgrade" as existing tags depend on this name - // V6 defines the upgrade name for the ibc-go/v6 upgrade handler. - V6 = "v6" - // V7 defines the upgrade name for the ibc-go/v7 upgrade handler. - V7 = "v7" - // V7_1 defines the upgrade name for the ibc-go/v7.1 upgrade handler. - V7_1 = "v7.1" - // V8 defines the upgrade name for the ibc-go/v8 upgrade handler. - V8 = "v8" -) - -// CreateDefaultUpgradeHandler creates an upgrade handler which can be used for regular upgrade tests -// that do not require special logic -func CreateDefaultUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - return mm.RunMigrations(ctx, configurator, vm) - } -} - -// CreateV6UpgradeHandler creates an upgrade handler for the ibc-go/v6 SimApp upgrade. -// NOTE: The v6.MigrateICS27ChannelCapabiliity function can be omitted if chains do not yet implement an ICS27 controller module -func CreateV6UpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - cdc codec.BinaryCodec, - capabilityStoreKey *storetypes.KVStoreKey, - capabilityKeeper *capabilitykeeper.Keeper, - moduleName string, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := v6.MigrateICS27ChannelCapability(sdkCtx, cdc, capabilityStoreKey, capabilityKeeper, moduleName); err != nil { - return nil, err - } - - return mm.RunMigrations(ctx, configurator, vm) - } -} - -// CreateV7UpgradeHandler creates an upgrade handler for the ibc-go/v7 SimApp upgrade. -func CreateV7UpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - cdc codec.BinaryCodec, - clientKeeper clientkeeper.Keeper, - consensusParamsKeeper consensusparamskeeper.Keeper, - paramsKeeper paramskeeper.Keeper, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) - // OPTIONAL: prune expired tendermint consensus states to save storage space - if _, err := ibctmmigrations.PruneExpiredConsensusStates(sdkCtx, cdc, clientKeeper); err != nil { - return nil, err - } - - legacyBaseAppSubspace := paramsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()) - err := baseapp.MigrateParams(sdkCtx, legacyBaseAppSubspace, consensusParamsKeeper.ParamsStore) - if err != nil { - panic(err) - } - - return mm.RunMigrations(ctx, configurator, vm) - } -} - -// CreateV7LocalhostUpgradeHandler creates an upgrade handler for the ibc-go/v7.1 SimApp upgrade. -func CreateV7LocalhostUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - clientKeeper clientkeeper.Keeper, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) - // explicitly update the IBC 02-client params, adding the localhost client type - params := clientKeeper.GetParams(sdkCtx) - params.AllowedClients = append(params.AllowedClients, exported.Localhost) - clientKeeper.SetParams(sdkCtx, params) - - return mm.RunMigrations(ctx, configurator, vm) - } -} - -// CreateV8UpgradeHandler creates an upgrade handler for the ibc-go/v8 SimApp upgrade. -func CreateV8UpgradeHandler(mm *module.Manager, configurator module.Configurator) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - return mm.RunMigrations(ctx, configurator, vm) - } -} diff --git a/ibc/testing/utils.go b/ibc/testing/utils.go new file mode 100644 index 00000000..9667228e --- /dev/null +++ b/ibc/testing/utils.go @@ -0,0 +1,32 @@ +package ibctesting + +import ( + "fmt" + + "github.com/stretchr/testify/require" + + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" +) + +// VoteAndCheckProposalStatus votes on a gov proposal, checks if the proposal has passed, and returns an error if it has not with the failure reason. +func VoteAndCheckProposalStatus(endpoint *Endpoint, proposalID uint64) error { + // vote on proposal + ctx := endpoint.Chain.GetContext() + require.NoError(endpoint.Chain.TB, endpoint.Chain.GetSimApp().GovKeeper.AddVote(ctx, proposalID, endpoint.Chain.SenderAccount.GetAddress(), govtypesv1.NewNonSplitVoteOption(govtypesv1.OptionYes), "")) + + // fast forward the chain context to end the voting period + params, err := endpoint.Chain.GetSimApp().GovKeeper.Params.Get(ctx) + require.NoError(endpoint.Chain.TB, err) + + endpoint.Chain.Coordinator.IncrementTimeBy(*params.VotingPeriod + *params.MaxDepositPeriod) + endpoint.Chain.NextBlock() + + // check if proposal passed or failed on msg execution + // we need to grab the context again since the previous context is no longer valid as the chain header time has been incremented + p, err := endpoint.Chain.GetSimApp().GovKeeper.Proposals.Get(endpoint.Chain.GetContext(), proposalID) + require.NoError(endpoint.Chain.TB, err) + if p.Status != govtypesv1.StatusPassed { + return fmt.Errorf("proposal failed: %s", p.FailedReason) + } + return nil +} diff --git a/ibc/testing/values.go b/ibc/testing/values.go index 9e38849c..115f3b39 100644 --- a/ibc/testing/values.go +++ b/ibc/testing/values.go @@ -8,6 +8,7 @@ import ( "time" sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -15,10 +16,12 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "github.com/cosmos/ibc-go/v8/testing/mock" + "github.com/cosmos/ibc-go/v8/testing/simapp" ) const ( FirstClientID = "07-tendermint-0" + SecondClientID = "07-tendermint-1" FirstChannelID = "channel-0" FirstConnectionID = "connection-0" @@ -34,20 +37,25 @@ const ( // Application Ports TransferPort = ibctransfertypes.ModuleName MockPort = mock.ModuleName + MockFeePort = simapp.MockFeePort // used for testing proposals Title = "title" Description = "description" - LongString = "LoremipsumdolorsitameconsecteturadipiscingeliseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquUtenimadminimveniamquisnostrudexercitationullamcolaborisnisiutaliquipexeacommodoconsequDuisauteiruredolorinreprehenderitinvoluptateelitsseillumoloreufugiatnullaariaturEcepteurintoccaectupidatatonroidentuntnulpauifficiaeseruntmollitanimidestlaborum" + // character set used for generating a random string in GenerateString + charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ) var ( DefaultOpenInitVersion *connectiontypes.Version - // Default params variables used to create a TM client - DefaultTrustLevel ibctm.Fraction = ibctm.DefaultTrustLevel - TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) + // DefaultTrustLevel sets params variables used to create a TM client + DefaultTrustLevel = ibctm.DefaultTrustLevel + + TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) + TestCoins = sdk.NewCoins(TestCoin) UpgradePath = []string{"upgrade", "upgradedIBCState"}