diff --git a/.github/workflows/e2e-test-workflow-call.yml b/.github/workflows/e2e-test-workflow-call.yml index de990ce2..ff209836 100644 --- a/.github/workflows/e2e-test-workflow-call.yml +++ b/.github/workflows/e2e-test-workflow-call.yml @@ -20,6 +20,7 @@ jobs: tests: - "e2e-test-ibc-success" - "e2e-test-ibc-timeout" + - "e2e-test-ibc-grace-period" fail-fast: false runs-on: ubuntu-latest steps: diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml index 81251353..040c98ea 100644 --- a/.github/workflows/e2e_test.yml +++ b/.github/workflows/e2e_test.yml @@ -27,6 +27,7 @@ jobs: tests: - "e2e-test-ibc-success" - "e2e-test-ibc-timeout" + - "e2e-test-ibc-grace-period" fail-fast: false runs-on: ubuntu-latest steps: diff --git a/Makefile b/Makefile index 1483f0c7..3d3ed7f3 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,12 @@ e2e-test-ibc-success: # Executes IBC tests via rollup-e2e-testing e2e-test-ibc-timeout: cd tests && go test -timeout=25m -race -v -run TestIBCTransferTimeout . - + +e2e-test-ibc-grace-period: + cd tests && go test -timeout=25m -race -v -run TestIBCGracePeriodCompliance . + # Executes all tests via rollup-e2e-testing -e2e-test-all: e2e-test-ibc-success e2e-test-ibc-timeout +e2e-test-all: e2e-test-ibc-success e2e-test-ibc-timeout e2e-test-ibc-grace-period -.PHONY: e2e-test-ibc-success e2e-test-ibc-timeout e2e-test-all +.PHONY: e2e-test-ibc-success e2e-test-ibc-timeout e2e-test-ibc-grace-period e2e-test-all diff --git a/tests/ibc_grace_period_test.go b/tests/ibc_grace_period_test.go new file mode 100644 index 00000000..b21a9e1d --- /dev/null +++ b/tests/ibc_grace_period_test.go @@ -0,0 +1,226 @@ +package tests + +import ( + "context" + "testing" + + "cosmossdk.io/math" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + test "github.com/decentrio/rollup-e2e-testing" + "github.com/decentrio/rollup-e2e-testing/cosmos" + "github.com/decentrio/rollup-e2e-testing/ibc" + "github.com/decentrio/rollup-e2e-testing/relayer" + "github.com/decentrio/rollup-e2e-testing/testreporter" + "github.com/decentrio/rollup-e2e-testing/testutil" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +// TestIBCGracePeriodCompliance ensures that the grace period for transaction finalization is correctly enforced on hub and rollapp. +func TestIBCGracePeriodCompliance(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + + configFileOverrides := make(map[string]any) + dymintTomlOverrides := make(testutil.Toml) + dymintTomlOverrides["settlement_layer"] = "dymension" + dymintTomlOverrides["node_address"] = "http://dymension_100-1-val-0-TestIBCGracePeriodCompliance:26657" + dymintTomlOverrides["rollapp_id"] = "demo-dymension-rollapp" + + modifyGenesisKV := []cosmos.GenesisKV{ + { + Key: "app_state.rollapp.params.dispute_period_in_blocks", + Value: "20", + }, + } + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 0 + numRollAppVals := 1 + cf := cosmos.NewBuiltinChainFactory(zaptest.NewLogger(t), []*cosmos.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp", + Name: "rollapp-temp", + ChainID: "demo-dymension-rollapp", + Images: []ibc.DockerImage{rollappImage}, + Bin: "rollappd", + Bech32Prefix: "rol", + Denom: "urax", + CoinType: "118", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + NoHostMount: false, + ModifyGenesis: nil, + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: ibc.ChainConfig{ + Type: "hub", + Name: "dymension", + ChainID: "dymension_100-1", + Images: []ibc.DockerImage{dymensionImage}, + Bin: "dymd", + Bech32Prefix: "dym", + Denom: "udym", + CoinType: "118", + GasPrices: "0.0udym", + EncodingConfig: evmConfig(), + GasAdjustment: 1.1, + TrustingPeriod: "112h", + NoHostMount: false, + ModifyGenesis: cosmos.ModifyGenesis(modifyGenesisKV), + ConfigFileOverrides: nil, + }, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*cosmos.CosmosChain) + dymension := chains[1].(*cosmos.CosmosChain) + + // Relayer Factory + client, network := test.DockerSetup(t) + + r := relayer.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage("ghcr.io/cosmos/relayer", "reece-v2.3.1-ethermint", "100:1000"), + ).Build(t, client, network) + + ic := test.NewSetup(). + AddChain(rollapp1). + AddChain(dymension). + AddRelayer(r, "relayer"). + AddLink(test.InterchainLink{ + Chain1: dymension, + Chain2: rollapp1, + Relayer: r, + Path: ibcPath, + }) + + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + + err = ic.Build(ctx, eRep, test.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + + // This can be used to write to the block database which will index all block data e.g. txs, msgs, events, etc. + // BlockDatabaseFile: test.DefaultBlockDatabaseFilepath(), + }) + require.NoError(t, err) + + walletAmount := math.NewInt(1_000_000_000_000) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + // Assert the accounts were funded + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount) + + // Compose an IBC transfer and send from rollapp -> dymension + var transferAmount = math.NewInt(1_000_000) + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, rollapp1.Config().ChainID, dymension.Config().ChainID) + require.NoError(t, err) + + transferData := ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from dymension -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the Hub because transfer amount was deducted from wallet balance + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // Get the IBC denom for dymension on roll app + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, math.NewInt(0)) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 5, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the Rollapp + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, dymensionIBCDenom, transferData.Amount) + + channel, err = ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + transferData = ibc.WalletData{ + Address: dymensionUserAddr, + Denom: rollapp1.Config().Denom, + Amount: transferAmount, + } + + _, err = rollapp1.SendIBCTransfer(ctx, channel.ChannelID, rollappUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the rollapp because transfer amount was deducted from wallet balance + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // Get the IBC denom for urax on Hub + rollappTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, rollapp1.Config().Denom) + rollappIBCDenom := transfertypes.ParseDenomTrace(rollappTokenDenom).IBCDenom() + + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + // Assert funds are waiting + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, math.NewInt(0)) + + // Wait a 30 blocks + err = testutil.WaitForBlocks(ctx, 30, dymension, rollapp1) + require.NoError(t, err) + + // Assert balance was updated on the Hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferData.Amount) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) +} diff --git a/tests/ibc_transfer_test.go b/tests/ibc_transfer_test.go index ecc64bef..493e8f74 100644 --- a/tests/ibc_transfer_test.go +++ b/tests/ibc_transfer_test.go @@ -18,7 +18,7 @@ import ( const ibcPath = "dymension-demo" -// TestStart is a basic test to assert that spinning up a dymension network with 1 validator works properly. +// TestIBCTransferSuccess ensure that the transfer between Hub and Rollapp is accurate. func TestIBCTransferSuccess(t *testing.T) { if testing.Short() { t.Skip()