From 9220bc56b2de67c654c7077ddcabb9257a854460 Mon Sep 17 00:00:00 2001 From: javiersuweijie Date: Wed, 30 Aug 2023 14:18:24 +0800 Subject: [PATCH 1/2] fix: pfm integration + e2e --- .github/workflows/interchaine2e.yml | 1 + Makefile | 5 ++++- app/app.go | 31 ++++++++++++++++------------- interchaintest/config.go | 1 + interchaintest/pmf_test.go | 1 + 5 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 interchaintest/config.go create mode 100644 interchaintest/pmf_test.go diff --git a/.github/workflows/interchaine2e.yml b/.github/workflows/interchaine2e.yml index 5d3be131..071c745f 100644 --- a/.github/workflows/interchaine2e.yml +++ b/.github/workflows/interchaine2e.yml @@ -57,6 +57,7 @@ jobs: # names of `make` commands to run tests test: - "test-e2e-pob" + - "test-e2e-pmf" fail-fast: false steps: diff --git a/Makefile b/Makefile index 635755b7..f2710cd7 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,10 @@ simulate: test-e2e-pob: cd interchaintest && go test -race -v -run TestPOB . -.PHONY: test test-all test-cover test-unit test-race simulate test-e2e-pob +test-e2e-pmf: + cd interchaintest && go test -race -v -run TestPMF . + +.PHONY: test test-all test-cover test-unit test-race simulate test-e2e-pob test-e2e-pmf ############################################################################### ### Linting ### diff --git a/app/app.go b/app/app.go index c901714c..4837fff9 100644 --- a/app/app.go +++ b/app/app.go @@ -340,7 +340,7 @@ type TerraApp struct { // IBC hooks IBCHooksKeeper *ibchookskeeper.Keeper - TransferStack *ibchooks.IBCMiddleware + TransferStack porttypes.Middleware Ics20WasmHooks *ibchooks.WasmHooks HooksICS4Wrapper ibchooks.ICS4Middleware @@ -593,7 +593,21 @@ func NewTerraApp( // Hooks Middleware hooksTransferStack := ibchooks.NewIBCMiddleware(&transferIBCModule, &app.HooksICS4Wrapper) - app.TransferStack = &hooksTransferStack + + // Packet forwarding middleware + app.RouterKeeper = *routerkeeper.NewKeeper( + appCodec, + app.keys[routertypes.StoreKey], + app.GetSubspace(routertypes.ModuleName), + app.TransferKeeper, + app.IBCKeeper.ChannelKeeper, + app.DistrKeeper, + app.BankKeeper, + app.IBCKeeper.ChannelKeeper, + ) + pmfTransferStack := router.NewIBCMiddleware(hooksTransferStack, &app.RouterKeeper, 5, routerkeeper.DefaultForwardTransferPacketTimeoutTimestamp, routerkeeper.DefaultRefundTransferPacketTimeoutTimestamp) + + app.TransferStack = &pmfTransferStack app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( appCodec, keys[ibcfeetypes.StoreKey], @@ -626,17 +640,6 @@ func NewTerraApp( icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack := ibcfee.NewIBCMiddleware(icaHostIBCModule, app.IBCFeeKeeper) - app.RouterKeeper = *routerkeeper.NewKeeper( - appCodec, - app.keys[routertypes.StoreKey], - app.GetSubspace(routertypes.ModuleName), - app.TransferKeeper, - app.IBCKeeper.ChannelKeeper, - app.DistrKeeper, - app.BankKeeper, - app.IBCKeeper.ChannelKeeper, - ) - // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( appCodec, keys[evidencetypes.StoreKey], app.StakingKeeper, app.SlashingKeeper, @@ -687,7 +690,7 @@ func NewTerraApp( ibcRouter := porttypes.NewRouter(). AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). AddRoute(icahosttypes.SubModuleName, icaHostStack). - AddRoute(ibctransfertypes.ModuleName, hooksTransferStack). + AddRoute(ibctransfertypes.ModuleName, pmfTransferStack). AddRoute(wasmtypes.ModuleName, wasmStack) app.IBCKeeper.SetRouter(ibcRouter) diff --git a/interchaintest/config.go b/interchaintest/config.go new file mode 100644 index 00000000..086ed3b3 --- /dev/null +++ b/interchaintest/config.go @@ -0,0 +1 @@ +package interchaintest diff --git a/interchaintest/pmf_test.go b/interchaintest/pmf_test.go new file mode 100644 index 00000000..086ed3b3 --- /dev/null +++ b/interchaintest/pmf_test.go @@ -0,0 +1 @@ +package interchaintest From 6ada68d9a50b86d0bb81fed4b41b3fc7a50ceff4 Mon Sep 17 00:00:00 2001 From: javiersuweijie Date: Wed, 30 Aug 2023 14:32:41 +0800 Subject: [PATCH 2/2] test: e2e for pfm --- interchaintest/config.go | 60 ++++++++ interchaintest/pmf_test.go | 276 +++++++++++++++++++++++++++++++++++++ interchaintest/pob_test.go | 60 +------- 3 files changed, 342 insertions(+), 54 deletions(-) diff --git a/interchaintest/config.go b/interchaintest/config.go index 086ed3b3..962e5dfd 100644 --- a/interchaintest/config.go +++ b/interchaintest/config.go @@ -1 +1,61 @@ package interchaintest + +import ( + "fmt" + + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + + "github.com/cosmos/cosmos-sdk/types/module/testutil" +) + +var ( + Denom = "uluna" + VotingPeriod = "15s" + MaxDepositPeriod = "10s" + Image = ibc.DockerImage{ + Repository: "terramoneycore", + Version: "latest", + UidGid: "1025:1025", + } + IBCRelayerImage = "ghcr.io/cosmos/relayer" + IBCRelayerVersion = "main" + config = ibc.ChainConfig{ + Type: "cosmos", + Name: "terra", + ChainID: "phoenix-1", + Images: []ibc.DockerImage{Image}, + Bin: "terrad", + Bech32Prefix: "terra", + Denom: Denom, + CoinType: "330", + GasPrices: fmt.Sprintf("0%s", Denom), + GasAdjustment: 2.0, + TrustingPeriod: "112h", + NoHostMount: false, + ConfigFileOverrides: nil, + EncodingConfig: encoding(), + UsingNewGenesisCommand: true, + ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), + } + // SDK v47 Genesis + defaultGenesisKV = []cosmos.GenesisKV{ + { + Key: "app_state.gov.params.voting_period", + Value: VotingPeriod, + }, + { + Key: "app_state.gov.params.max_deposit_period", + Value: MaxDepositPeriod, + }, + { + Key: "app_state.gov.params.min_deposit.0.denom", + Value: Denom, + }, + } +) + +func encoding() *testutil.TestEncodingConfig { + cfg := cosmos.DefaultEncoding() + return &cfg +} diff --git a/interchaintest/pmf_test.go b/interchaintest/pmf_test.go index 086ed3b3..6611996f 100644 --- a/interchaintest/pmf_test.go +++ b/interchaintest/pmf_test.go @@ -1 +1,277 @@ package interchaintest + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/strangelove-ventures/interchaintest/v7" + "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v7/ibc" + interchaintestrelayer "github.com/strangelove-ventures/interchaintest/v7/relayer" + "github.com/strangelove-ventures/interchaintest/v7/testreporter" + "github.com/strangelove-ventures/interchaintest/v7/testutil" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type PacketMetadata struct { + Forward *ForwardMetadata `json:"forward"` +} + +type ForwardMetadata struct { + Receiver string `json:"receiver"` + Port string `json:"port"` + Channel string `json:"channel"` + Timeout time.Duration `json:"timeout"` + Retries *uint8 `json:"retries,omitempty"` + Next *string `json:"next,omitempty"` + RefundSequence *uint64 `json:"refund_sequence,omitempty"` +} + +// TestPacketForwardMiddlewareRouter ensures the PFM module is set up properly and works as expected. +func TestPMF(t *testing.T) { + if testing.Short() { + t.Skip() + } + + var ( + ctx = context.Background() + client, network = interchaintest.DockerSetup(t) + rep = testreporter.NewNopReporter() + eRep = rep.RelayerExecReporter(t) + chainID_A, chainID_B, chainID_C, chainID_D = "chain-a", "chain-b", "chain-c", "chain-d" + chainA, chainB, chainC, chainD *cosmos.CosmosChain + ) + + baseCfg := config + + // Set specific chain ids for each so they are their own unique networks + baseCfg.ChainID = chainID_A + configA := baseCfg + + baseCfg.ChainID = chainID_B + configB := baseCfg + + baseCfg.ChainID = chainID_C + configC := baseCfg + + baseCfg.ChainID = chainID_D + configD := baseCfg + + // Create chain factory with multiple Juno individual networks. + numVals := 1 + numFullNodes := 0 + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + Name: "juno", + ChainConfig: configA, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + { + Name: "juno", + ChainConfig: configB, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + { + Name: "juno", + ChainConfig: configC, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + { + Name: "juno", + ChainConfig: configD, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chainA, chainB, chainC, chainD = chains[0].(*cosmos.CosmosChain), chains[1].(*cosmos.CosmosChain), chains[2].(*cosmos.CosmosChain), chains[3].(*cosmos.CosmosChain) + + r := interchaintest.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t), + interchaintestrelayer.CustomDockerImage(IBCRelayerImage, IBCRelayerVersion, "100:1000"), + interchaintestrelayer.StartupFlags("--processor", "events", "--block-history", "100"), + ).Build(t, client, network) + + const pathAB = "ab" + const pathBC = "bc" + const pathCD = "cd" + + ic := interchaintest.NewInterchain(). + AddChain(chainA). + AddChain(chainB). + AddChain(chainC). + AddChain(chainD). + AddRelayer(r, "relayer"). + AddLink(interchaintest.InterchainLink{ + Chain1: chainA, + Chain2: chainB, + Relayer: r, + Path: pathAB, + }). + AddLink(interchaintest.InterchainLink{ + Chain1: chainB, + Chain2: chainC, + Relayer: r, + Path: pathBC, + }). + AddLink(interchaintest.InterchainLink{ + Chain1: chainC, + Chain2: chainD, + Relayer: r, + Path: pathCD, + }) + + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + BlockDatabaseFile: interchaintest.DefaultBlockDatabaseFilepath(), + + SkipPathCreation: false, + })) + t.Cleanup(func() { + _ = ic.Close() + }) + + const userFunds = int64(10_000_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), userFunds, chainA, chainB, chainC, chainD) + + abChan, err := ibc.GetTransferChannel(ctx, r, eRep, chainID_A, chainID_B) + require.NoError(t, err) + + baChan := abChan.Counterparty + + cbChan, err := ibc.GetTransferChannel(ctx, r, eRep, chainID_C, chainID_B) + require.NoError(t, err) + + bcChan := cbChan.Counterparty + + dcChan, err := ibc.GetTransferChannel(ctx, r, eRep, chainID_D, chainID_C) + require.NoError(t, err) + + cdChan := dcChan.Counterparty + + // Start the relayer on all paths + err = r.StartRelayer(ctx, eRep, pathAB, pathBC, pathCD) + require.NoError(t, err) + + t.Cleanup( + func() { + err := r.StopRelayer(ctx, eRep) + if err != nil { + t.Logf("an error occurred while stopping the relayer: %s", err) + } + }, + ) + + // Get original account balances + userA, userB, userC, userD := users[0], users[1], users[2], users[3] + + const transferAmount int64 = 100000 + + // Compose the prefixed denoms and ibc denom for asserting balances + firstHopDenom := transfertypes.GetPrefixedDenom(baChan.PortID, baChan.ChannelID, chainA.Config().Denom) + secondHopDenom := transfertypes.GetPrefixedDenom(cbChan.PortID, cbChan.ChannelID, firstHopDenom) + thirdHopDenom := transfertypes.GetPrefixedDenom(dcChan.PortID, dcChan.ChannelID, secondHopDenom) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + thirdHopDenomTrace := transfertypes.ParseDenomTrace(thirdHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.IBCDenom() + thirdHopIBCDenom := thirdHopDenomTrace.IBCDenom() + + firstHopEscrowAccount := sdk.MustBech32ifyAddressBytes(chainA.Config().Bech32Prefix, transfertypes.GetEscrowAddress(abChan.PortID, abChan.ChannelID)) + secondHopEscrowAccount := sdk.MustBech32ifyAddressBytes(chainB.Config().Bech32Prefix, transfertypes.GetEscrowAddress(bcChan.PortID, bcChan.ChannelID)) + thirdHopEscrowAccount := sdk.MustBech32ifyAddressBytes(chainC.Config().Bech32Prefix, transfertypes.GetEscrowAddress(cdChan.PortID, abChan.ChannelID)) + + t.Run("multi-hop a->b->c->d", func(t *testing.T) { + // Send packet from Chain A->Chain B->Chain C->Chain D + + transfer := ibc.WalletAmount{ + Address: userB.FormattedAddress(), + Denom: chainA.Config().Denom, + Amount: transferAmount, + } + + secondHopMetadata := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: userD.FormattedAddress(), + Channel: cdChan.ChannelID, + Port: cdChan.PortID, + }, + } + nextBz, err := json.Marshal(secondHopMetadata) + require.NoError(t, err) + next := string(nextBz) + + firstHopMetadata := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: userC.FormattedAddress(), + Channel: bcChan.ChannelID, + Port: bcChan.PortID, + Next: &next, + }, + } + + memo, err := json.Marshal(firstHopMetadata) + require.NoError(t, err) + + chainAHeight, err := chainA.Height(ctx) + require.NoError(t, err) + + transferTx, err := chainA.SendIBCTransfer(ctx, abChan.ChannelID, userA.KeyName(), transfer, ibc.TransferOptions{Memo: string(memo)}) + require.NoError(t, err) + _, err = testutil.PollForAck(ctx, chainA, chainAHeight, chainAHeight+30, transferTx.Packet) + require.NoError(t, err) + err = testutil.WaitForBlocks(ctx, 1, chainA) + require.NoError(t, err) + + chainABalance, err := chainA.GetBalance(ctx, userA.FormattedAddress(), chainA.Config().Denom) + require.NoError(t, err) + + chainBBalance, err := chainB.GetBalance(ctx, userB.FormattedAddress(), firstHopIBCDenom) + require.NoError(t, err) + + chainCBalance, err := chainC.GetBalance(ctx, userC.FormattedAddress(), secondHopIBCDenom) + require.NoError(t, err) + + chainDBalance, err := chainD.GetBalance(ctx, userD.FormattedAddress(), thirdHopIBCDenom) + require.NoError(t, err) + + require.Equal(t, userFunds-transferAmount, chainABalance) + require.Equal(t, int64(0), chainBBalance) + require.Equal(t, int64(0), chainCBalance) + require.Equal(t, transferAmount, chainDBalance) + + firstHopEscrowBalance, err := chainA.GetBalance(ctx, firstHopEscrowAccount, chainA.Config().Denom) + require.NoError(t, err) + + secondHopEscrowBalance, err := chainB.GetBalance(ctx, secondHopEscrowAccount, firstHopIBCDenom) + require.NoError(t, err) + + thirdHopEscrowBalance, err := chainC.GetBalance(ctx, thirdHopEscrowAccount, secondHopIBCDenom) + require.NoError(t, err) + + require.Equal(t, transferAmount, firstHopEscrowBalance) + require.Equal(t, transferAmount, secondHopEscrowBalance) + require.Equal(t, transferAmount, thirdHopEscrowBalance) + }) +} diff --git a/interchaintest/pob_test.go b/interchaintest/pob_test.go index 4ee1e140..0c036682 100644 --- a/interchaintest/pob_test.go +++ b/interchaintest/pob_test.go @@ -1,70 +1,22 @@ package interchaintest import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module/testutil" - "github.com/strangelove-ventures/interchaintest/v7" - "github.com/strangelove-ventures/interchaintest/v7/ibc" "testing" + "github.com/strangelove-ventures/interchaintest/v7" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/skip-mev/pob/tests/integration" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" "github.com/stretchr/testify/suite" ) var ( - numVals = 4 - numFull = 0 - Denom = "uluna" - VotingPeriod = "15s" - MaxDepositPeriod = "10s" - config = ibc.ChainConfig{ - Type: "cosmos", - Name: "terra", - ChainID: "phoenix-1", - Images: []ibc.DockerImage{ - { - Repository: "terramoneycore", - Version: "latest", - UidGid: "1025:1025", - }, - }, - Bin: "terrad", - Bech32Prefix: "terra", - Denom: Denom, - CoinType: "330", - GasPrices: fmt.Sprintf("0%s", Denom), - GasAdjustment: 2.0, - TrustingPeriod: "112h", - NoHostMount: false, - ConfigFileOverrides: nil, - EncodingConfig: encoding(), - UsingNewGenesisCommand: true, - ModifyGenesis: cosmos.ModifyGenesis(defaultGenesisKV), - } - // SDK v47 Genesis - defaultGenesisKV = []cosmos.GenesisKV{ - { - Key: "app_state.gov.params.voting_period", - Value: VotingPeriod, - }, - { - Key: "app_state.gov.params.max_deposit_period", - Value: MaxDepositPeriod, - }, - { - Key: "app_state.gov.params.min_deposit.0.denom", - Value: Denom, - }, - } + numVals = 4 + numFull = 0 ) -func encoding() *testutil.TestEncodingConfig { - cfg := cosmos.DefaultEncoding() - return &cfg -} - func GetInterchainSpecForPOB() *interchaintest.ChainSpec { // update the genesis kv for juno updatedChainConfig := config