diff --git a/Makefile b/Makefile index 9e5db510..f6c37cde 100644 --- a/Makefile +++ b/Makefile @@ -212,6 +212,9 @@ e2e-test-rollapp-hardfork-evm: clean-e2e e2e-test-rollapp-hardfork-recover-ibc-client-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestHardForkRecoverIbcClient_EVM . +e2e-test-rollapp-hardforkduetodrs-evm: clean-e2e + cd tests && go test -timeout=45m -race -v -run TestHardForkDueToDrs_EVM . + e2e-test-rollapp-hardforkduetofraud-evm: clean-e2e cd tests && go test -timeout=45m -race -v -run TestHardForkDueToFraud_EVM . diff --git a/tests/fullnode_sync_test.go b/tests/fullnode_sync_test.go index e0aaacb2..80492932 100644 --- a/tests/fullnode_sync_test.go +++ b/tests/fullnode_sync_test.go @@ -33,7 +33,7 @@ import ( // StartDA start grpc DALC server func StartDA(ctx context.Context, t *testing.T, client *client.Client, net string) { fmt.Println("Starting pull image ...") - out, err := client.ImagePull(ctx, "ghcr.io/decentrio/dymint:srene-hardfork-fix", types.ImagePullOptions{}) + out, err := client.ImagePull(ctx, "ghcr.io/decentrio/dymint:srene-hardfork-fix-arm", types.ImagePullOptions{}) require.NoError(t, err) defer out.Close() @@ -57,14 +57,14 @@ func StartDA(ctx context.Context, t *testing.T, client *client.Client, net strin DNS: []string{}, ExtraHosts: []string{"host.docker.internal:host-gateway"}, } - time.Sleep(2 * time.Minute) + // time.Sleep(2 * time.Minute) // Create the container fmt.Println("Creating container ...") resp, err := client.ContainerCreate( ctx, &container.Config{ - Image: "ghcr.io/decentrio/dymint:srene-hardfork-fix", // Image to run - Tty: true, // Attach to a TTY + Image: "ghcr.io/decentrio/dymint:srene-hardfork-fix-arm", // Image to run + Tty: true, // Attach to a TTY }, hostConfig, networkConfig, nil, "grpc-da-container", ) diff --git a/tests/hardfork_test.go b/tests/hardfork_test.go index 526bf53c..0ecfb84d 100644 --- a/tests/hardfork_test.go +++ b/tests/hardfork_test.go @@ -848,3 +848,371 @@ func Test_HardFork_KickProposer_EVM(t *testing.T) { erc20MAccAddr = erc20MAcc.Account.BaseAccount.Address testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, rollappOrigBal.Add(transferData.Amount)) } + +func TestHardForkDueToDrs_EVM(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["settlement_node_address"] = fmt.Sprintf("http://dymension_100-1-val-0-%s:26657", t.Name()) + dymintTomlOverrides["rollapp_id"] = "rollappevm_1234-1" + dymintTomlOverrides["settlement_gas_prices"] = "0adym" + dymintTomlOverrides["max_idle_time"] = "3s" + dymintTomlOverrides["max_proof_time"] = "500ms" + dymintTomlOverrides["batch_submit_time"] = "50s" + dymintTomlOverrides["p2p_blocksync_enabled"] = "true" + dymintTomlOverrides["da_config"] = "{\"host\":\"grpc-da-container\",\"port\": 7980}" + + configFileOverrides["config/dymint.toml"] = dymintTomlOverrides + // Create chain factory with dymension + numHubVals := 1 + numHubFullNodes := 1 + numRollAppFn := 1 + numRollAppVals := 1 + + modifyEVMGenesisKV := append( + rollappEVMGenesisKV, + cosmos.GenesisKV{ + Key: "app_state.rollappparams.params.da", + Value: "grpc", + }, + ) + + cf := test.NewBuiltinChainFactory(zaptest.NewLogger(t), []*test.ChainSpec{ + { + Name: "rollapp1", + ChainConfig: ibc.ChainConfig{ + Type: "rollapp-dym", + Name: "rollapp-temp", + ChainID: "rollappevm_1234-1", + Images: []ibc.DockerImage{rollappEVMImage}, + Bin: "rollappd", + Bech32Prefix: "ethm", + Denom: "urax", + CoinType: "60", + GasPrices: "0.0urax", + GasAdjustment: 1.1, + TrustingPeriod: "112h", + EncodingConfig: encodingConfig(), + NoHostMount: false, + ModifyGenesis: modifyRollappEVMGenesis(modifyEVMGenesisKV), + ConfigFileOverrides: configFileOverrides, + }, + NumValidators: &numRollAppVals, + NumFullNodes: &numRollAppFn, + }, + { + Name: "dymension-hub", + ChainConfig: dymensionConfig, + NumValidators: &numHubVals, + NumFullNodes: &numHubFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + rollapp1 := chains[0].(*dym_rollapp.DymRollApp) + dymension := chains[1].(*dym_hub.DymHub) + + // Relayer Factory + client, network := test.DockerSetup(t) + + StartDA(ctx, t, client, network) + + r := test.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t), + relayer.CustomDockerImage(RelayerMainRepo, relayerVersion, "100:1000"), relayer.ImagePull(pullRelayerImage), + ).Build(t, client, "relayer", network) + + ic := test.NewSetup(). + AddRollUp(dymension, rollapp1). + 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: true, + + // 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(), + }, nil, "", nil, true, 1179360) + require.NoError(t, err) + + containerID := fmt.Sprintf("ra-rollappevm_1234-1-val-0-%s", t.Name()) + + // Get the container details + containerJSON, err := client.ContainerInspect(context.Background(), containerID) + require.NoError(t, err) + + // Extract the IP address from the network settings + // If the container is using a custom network, the IP might be under a specific network name + var ipAddress string + for _, network := range containerJSON.NetworkSettings.Networks { + ipAddress = network.IPAddress + break // Assuming we only need the IP from the first network + } + + nodeId, err := rollapp1.Validators[0].GetNodeId(ctx) + require.NoError(t, err) + nodeId = strings.TrimRight(nodeId, "\n") + p2p_bootstrap_node := fmt.Sprintf("/ip4/%s/tcp/26656/p2p/%s", ipAddress, nodeId) + + rollapp1HomeDir := strings.Split(rollapp1.FullNodes[0].HomeDir(), "/") + rollapp1FolderName := rollapp1HomeDir[len(rollapp1HomeDir)-1] + + file, err := os.Open(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + lines := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + lines = append(lines, scanner.Text()) + } + + for i, line := range lines { + if strings.HasPrefix(line, "p2p_bootstrap_nodes =") { + lines[i] = fmt.Sprintf("p2p_bootstrap_nodes = \"%s\"", p2p_bootstrap_node) + } + } + + output := strings.Join(lines, "\n") + file, err = os.Create(fmt.Sprintf("/tmp/%s/config/dymint.toml", rollapp1FolderName)) + require.NoError(t, err) + defer file.Close() + + _, err = file.Write([]byte(output)) + require.NoError(t, err) + + // Start full node + err = rollapp1.FullNodes[0].StopContainer(ctx) + require.NoError(t, err) + + err = rollapp1.FullNodes[0].StartContainer(ctx) + require.NoError(t, err) + + addrDym, _ := r.GetWallet(dymension.GetChainID()) + err = dymension.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrDym.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: dymension.Config().Denom, + }) + require.NoError(t, err) + + addrRA, _ := r.GetWallet(rollapp1.GetChainID()) + err = rollapp1.GetNode().SendFunds(ctx, "faucet", ibc.WalletData{ + Address: addrRA.FormattedAddress(), + Amount: math.NewInt(10_000_000_000_000), + Denom: rollapp1.Config().Denom, + }) + require.NoError(t, err) + + // Check IBC Transfer before switch + CreateChannel(ctx, t, r, eRep, dymension.CosmosChain, rollapp1.CosmosChain, ibcPath) + + // Create some user accounts on both chains + users := test.GetAndFundTestUsers(t, ctx, t.Name(), walletAmount, dymension, rollapp1) + + // Get our Bech32 encoded user addresses + dymensionUser, rollappUser := users[0], users[1] + + dymensionUserAddr := dymensionUser.FormattedAddress() + rollappUserAddr := rollappUser.FormattedAddress() + + channel, err := ibc.GetTransferChannel(ctx, r, eRep, dymension.Config().ChainID, rollapp1.Config().ChainID) + require.NoError(t, err) + + err = r.StartRelayer(ctx, eRep, ibcPath) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + res, err := dymension.QueryShowSequencerByRollapp(ctx, rollapp1.Config().ChainID) + require.NoError(t, err) + require.Equal(t, len(res.Sequencers), 1, "should have 1 sequences") + + // Wait a few blocks for relayer to start and for user accounts to be created + err = testutil.WaitForBlocks(ctx, 5, dymension) + require.NoError(t, err) + + // Create DRS deprecation proposal message + msg := map[string]interface{}{ + "@type": "/dymensionxyz.dymension.rollapp.MsgMarkObsoleteRollapps", + "authority": "dym10d07y265gmmuvt4z0w9aw880jnsr700jgllrna", + "drs_versions": []int{1}, + } + + rawMsg, err := json.Marshal(msg) + if err != nil { + panic(err) + } + + proposal := cosmos.TxDRSDeprecationProposal{ + Deposit: "500000000000" + dymension.Config().Denom, + Title: "drs", + Summary: "SubmitDRSDeprecationProposal", + Messages: []json.RawMessage{rawMsg}, + Metadata: "ipfs://CID", + } + + // Submit DRS deprecation proposal + _, _ = dymension.SubmitDRSDeprecationProposal(ctx, dymensionUser.KeyName(), proposal) + + err = dymension.VoteOnProposalAllValidators(ctx, "1", cosmos.ProposalVoteYes) + require.NoError(t, err, "failed to submit votes") + + height, err := dymension.Height(ctx) + require.NoError(t, err, "error fetching height") + haltHeight := height + haltHeightDelta + + // Assert that the chain is halted + // require.Equal(t, initialHeight, height, "chain is not halted as expected") + + _, err = cosmos.PollForProposalStatus(ctx, dymension.CosmosChain, height, haltHeight, "1", cosmos.ProposalStatusPassed) + require.NoError(t, err, "proposal status did not change to passed") + + command := []string{"sequencer", "opt-in", "true", "--keyring-dir", rollapp1.Validators[0].HomeDir() + "/sequencer_keys"} + + _, err = dymension.Validators[0].ExecTx(ctx, "sequencer", command...) + require.NoError(t, err) + + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + err = rollapp1.StopAllNodes(ctx) + require.NoError(t, err) + + rollapp1ValHomeDir := strings.Split(rollapp1.Validators[0].HomeDir(), "/") + rollapp1ValFolderName := rollapp1ValHomeDir[len(rollapp1ValHomeDir)-1] + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1FolderName)) + require.NoError(t, err) + + err = os.RemoveAll(fmt.Sprintf("/tmp/%s/data", rollapp1ValFolderName)) + require.NoError(t, err) + + err = rollapp1.StartAllNodes(ctx) + + err = testutil.WaitForBlocks(ctx, 50, dymension) + require.NoError(t, err) + + err = rollapp1.StopAllNodes(ctx) + + // rollapp1.UpgradeVersion(ctx, client, "ghcr.io/decentrio/rollapp-evm", "drs-2") + + for _, n := range rollapp1.Validators { + n.Image.Version = "drs-2" + n.Image.Repository = "ghcr.io/decentrio/rollapp-evm" + } + + err = rollapp1.StartAllNodes(ctx) + + err = testutil.WaitForBlocks(ctx, 10, dymension) + require.NoError(t, err) + + for _, n := range rollapp1.FullNodes { + n.Image.Version = "drs-2" + n.Image.Repository = "ghcr.io/decentrio/rollapp-evm" + } + + err = rollapp1.StopAllNodes(ctx) + + err = rollapp1.StartAllNodes(ctx) + 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) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + rollappHeight, err := rollapp1.GetNode().Height(ctx) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, rollapp1, rollappUserAddr, rollapp1.Config().Denom, walletAmount.Sub(transferData.Amount)) + + // wait until the packet is finalized + isFinalized, err := dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), rollappHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + + resp, err := dymension.GetNode().QueryPendingPacketsByAddress(ctx, dymensionUserAddr) + fmt.Println(res) + require.NoError(t, err) + + for _, packet := range resp.RollappPackets { + + proofHeight, _ := strconv.ParseInt(packet.ProofHeight, 10, 64) + isFinalized, err = dymension.WaitUntilRollappHeightIsFinalized(ctx, rollapp1.GetChainID(), proofHeight, 300) + require.NoError(t, err) + require.True(t, isFinalized) + txhash, err := dymension.GetNode().FinalizePacket(ctx, dymensionUserAddr, packet.RollappId, fmt.Sprint(packet.ProofHeight), fmt.Sprint(packet.Type), packet.Packet.SourceChannel, fmt.Sprint(packet.Packet.Sequence)) + require.NoError(t, err) + + fmt.Println(txhash) + } + + err = testutil.WaitForBlocks(ctx, 5, dymension, rollapp1) + require.NoError(t, err) + + // 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() + + // Minus 0.1% of transfer amount for bridge fee + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, rollappIBCDenom, transferAmount.Sub(bridgingFee)) + + // Get original account balances + dymensionOrigBal, err := dymension.GetBalance(ctx, dymensionUserAddr, dymension.Config().Denom) + require.NoError(t, err) + + // Compose an IBC transfer and send from dymension -> rollapp + transferData = ibc.WalletData{ + Address: rollappUserAddr, + Denom: dymension.Config().Denom, + Amount: transferAmount, + } + + // Compose an IBC transfer and send from Hub -> rollapp + _, err = dymension.SendIBCTransfer(ctx, channel.ChannelID, dymensionUserAddr, transferData, ibc.TransferOptions{}) + require.NoError(t, err) + + // Assert balance was updated on the hub + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + + err = testutil.WaitForBlocks(ctx, 10, dymension, rollapp1) + require.NoError(t, err) + + // Get the IBC denom + dymensionTokenDenom := transfertypes.GetPrefixedDenom(channel.Counterparty.PortID, channel.Counterparty.ChannelID, dymension.Config().Denom) + dymensionIBCDenom := transfertypes.ParseDenomTrace(dymensionTokenDenom).IBCDenom() + + testutil.AssertBalance(t, ctx, dymension, dymensionUserAddr, dymension.Config().Denom, dymensionOrigBal.Sub(transferData.Amount)) + erc20MAcc, err := rollapp1.Validators[0].QueryModuleAccount(ctx, "erc20") + require.NoError(t, err) + erc20MAccAddr := erc20MAcc.Account.BaseAccount.Address + testutil.AssertBalance(t, ctx, rollapp1, erc20MAccAddr, dymensionIBCDenom, transferData.Amount) +}