From 74fdc71867aeda0decd24584c4af7aedb1f7d59b Mon Sep 17 00:00:00 2001 From: Reece Williams Date: Fri, 29 Nov 2024 13:19:06 -0600 Subject: [PATCH] latest setup --- Makefile | 12 +- interchaintest/basic_test.go | 58 +++++ interchaintest/cosmwasm_test.go | 102 ++++++++ interchaintest/ibc_rate_limit_test.go | 102 ++++++++ interchaintest/ibc_test.go | 125 ++++++++++ interchaintest/integration/README.md | 3 + .../{ => integration}/chainsuite/chain.go | 0 .../chainsuite/chain_spec_provider.go | 0 .../{ => integration}/chainsuite/config.go | 0 .../{ => integration}/chainsuite/context.go | 0 .../chainsuite/query_types.go | 0 .../{ => integration}/provider_suite.go | 2 +- .../{ => integration}/provider_test.go | 4 +- .../{ => integration}/provider_utils.go | 0 interchaintest/old.zip | Bin 8761 -> 0 bytes interchaintest/packetforward_test.go | 232 ++++++++++++++++++ interchaintest/tokenfactory_test.go | 88 +++++++ 17 files changed, 717 insertions(+), 11 deletions(-) create mode 100644 interchaintest/basic_test.go create mode 100644 interchaintest/cosmwasm_test.go create mode 100644 interchaintest/ibc_rate_limit_test.go create mode 100644 interchaintest/ibc_test.go create mode 100644 interchaintest/integration/README.md rename interchaintest/{ => integration}/chainsuite/chain.go (100%) rename interchaintest/{ => integration}/chainsuite/chain_spec_provider.go (100%) rename interchaintest/{ => integration}/chainsuite/config.go (100%) rename interchaintest/{ => integration}/chainsuite/context.go (100%) rename interchaintest/{ => integration}/chainsuite/query_types.go (100%) rename interchaintest/{ => integration}/provider_suite.go (89%) rename interchaintest/{ => integration}/provider_test.go (99%) rename interchaintest/{ => integration}/provider_utils.go (100%) delete mode 100644 interchaintest/old.zip create mode 100644 interchaintest/packetforward_test.go create mode 100644 interchaintest/tokenfactory_test.go diff --git a/Makefile b/Makefile index 4501452..afc561f 100644 --- a/Makefile +++ b/Makefile @@ -251,7 +251,7 @@ endif ############################################################################### ictest-basic: - @echo "Running basic e2e test" + @echo "Running Basic e2e test" @cd interchaintest && go test -race -v -run TestBasicChain . ictest-ibc: @@ -260,20 +260,16 @@ ictest-ibc: ictest-ics: @echo "Running ICS e2e test" - @cd interchaintest && go test -race -v -run TestICSConnection . + @cd interchaintest && go test -race -v -run TestICSProviderSuite ./integration ictest-wasm: - @echo "Running cosmwasm e2e test" + @echo "Running Cosmwasm e2e test" @cd interchaintest && go test -race -v -run TestCosmWasmIntegration . ictest-packetforward: - @echo "Running packet forward middleware e2e test" + @echo "Running PacketForward e2e test" @cd interchaintest && go test -race -v -run TestPacketForwardMiddleware . -ictest-poa: - @echo "Running proof of authority e2e test" - @cd interchaintest && go test -race -v -run TestPOA . - ictest-tokenfactory: @echo "Running token factory e2e test" @cd interchaintest && go test -race -v -run TestTokenFactory . diff --git a/interchaintest/basic_test.go b/interchaintest/basic_test.go new file mode 100644 index 0000000..9435fad --- /dev/null +++ b/interchaintest/basic_test.go @@ -0,0 +1,58 @@ +package e2e + +import ( + "context" + "testing" + + "cosmossdk.io/math" + + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +func TestBasicChain(t *testing.T) { + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + &DefaultChainSpec, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + + // Setup Interchain + ic := interchaintest.NewInterchain(). + AddChain(chain) + + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + })) + t.Cleanup(func() { + _ = ic.Close() + }) + + amt := math.NewInt(10_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", amt, + chain, + ) + user := users[0] + + t.Run("validate funding", func(t *testing.T) { + bal, err := chain.BankQueryBalance(ctx, user.FormattedAddress(), chain.Config().Denom) + require.NoError(t, err) + require.EqualValues(t, amt, bal) + + }) + +} diff --git a/interchaintest/cosmwasm_test.go b/interchaintest/cosmwasm_test.go new file mode 100644 index 0000000..cdfdbfa --- /dev/null +++ b/interchaintest/cosmwasm_test.go @@ -0,0 +1,102 @@ +package e2e + +import ( + "context" + "encoding/json" + "testing" + + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +type GetCountResponse struct { + // {"data":{"count":0}} + Data *GetCountObj `json:"data"` +} + +type GetCountObj struct { + Count int64 `json:"count"` +} + +func TestCosmWasmIntegration(t *testing.T) { + t.Parallel() + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + &DefaultChainSpec, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + + // Setup Interchain + ic := interchaintest.NewInterchain(). + AddChain(chain) + + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + })) + t.Cleanup(func() { + _ = ic.Close() + }) + + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), GenesisFundsAmount, chain) + user := users[0] + + StdExecute(t, ctx, chain, user) +} + +func StdExecute(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user ibc.Wallet) (contractAddr string) { + _, contractAddr = SetupContract(t, ctx, chain, user.KeyName(), "contracts/cw_template.wasm", `{"count":0}`) + chain.ExecuteContract(ctx, user.KeyName(), contractAddr, `{"increment":{}}`, "--fees", "10000"+chain.Config().Denom) + + var res GetCountResponse + err := SmartQueryString(t, ctx, chain, contractAddr, `{"get_count":{}}`, &res) + require.NoError(t, err) + + require.Equal(t, int64(1), res.Data.Count) + + return contractAddr +} + +func SmartQueryString(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, contractAddr, queryMsg string, res interface{}) error { + var jsonMap map[string]interface{} + if err := json.Unmarshal([]byte(queryMsg), &jsonMap); err != nil { + t.Fatal(err) + } + err := chain.QueryContract(ctx, contractAddr, jsonMap, &res) + return err +} + +func SetupContract(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, keyname string, fileLoc string, message string, extraFlags ...string) (codeId, contract string) { + codeId, err := chain.StoreContract(ctx, keyname, fileLoc) + if err != nil { + t.Fatal(err) + } + + needsNoAdminFlag := true + for _, flag := range extraFlags { + if flag == "--admin" { + needsNoAdminFlag = false + } + } + + contractAddr, err := chain.InstantiateContract(ctx, keyname, codeId, message, needsNoAdminFlag, extraFlags...) + if err != nil { + t.Fatal(err) + } + + return codeId, contractAddr +} diff --git a/interchaintest/ibc_rate_limit_test.go b/interchaintest/ibc_rate_limit_test.go new file mode 100644 index 0000000..d32c5e6 --- /dev/null +++ b/interchaintest/ibc_rate_limit_test.go @@ -0,0 +1,102 @@ +package e2e + +import ( + "context" + "fmt" + "testing" + + "cosmossdk.io/math" + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + interchaintestrelayer "github.com/strangelove-ventures/interchaintest/v8/relayer" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest" +) + +func TestIBCRateLimit(t *testing.T) { + if testing.Short() { + t.Skip() + } + + t.Parallel() + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + cs := &DefaultChainSpec + cs.ModifyGenesis = cosmos.ModifyGenesis([]cosmos.GenesisKV{cosmos.NewGenesisKV("app_state.ratelimit.blacklisted_denoms", []string{cs.Denom})}) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + cs, + &SecondDefaultChainSpec, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + secondary := chains[1].(*cosmos.CosmosChain) + + // Relayer Factory + r := interchaintest.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t, zaptest.Level(zapcore.DebugLevel)), + interchaintestrelayer.CustomDockerImage(RelayerRepo, RelayerVersion, "100:1000"), + interchaintestrelayer.StartupFlags("--processor", "events", "--block-history", "200"), + ).Build(t, client, network) + + ic := interchaintest.NewInterchain(). + AddChain(chain). + AddChain(secondary). + AddRelayer(r, "relayer") + + ic = ic.AddLink(interchaintest.InterchainLink{ + Chain1: chain, + Chain2: secondary, + Relayer: r, + Path: ibcPath, + }) + + // Build interchain + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + })) + + // Create and Fund User Wallets + fundAmount := math.NewInt(10_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", fundAmount, chain, secondary) + userA, userB := users[0], users[1] + + userAInitial, err := chain.GetBalance(ctx, userA.FormattedAddress(), chain.Config().Denom) + fmt.Println("userAInitial", userAInitial) + require.NoError(t, err) + require.True(t, userAInitial.Equal(fundAmount)) + + // Get Channel ID + aInfo, err := r.GetChannels(ctx, eRep, chain.Config().ChainID) + require.NoError(t, err) + aChannelID, err := getTransferChannel(aInfo) + require.NoError(t, err) + fmt.Println("aChannelID", aChannelID) + + // Send Transaction + amountToSend := math.NewInt(1_000_000) + dstAddress := userB.FormattedAddress() + transfer := ibc.WalletAmount{ + Address: dstAddress, + Denom: chain.Config().Denom, + Amount: amountToSend, + } + + // Validate transfer error occurs + _, err = chain.SendIBCTransfer(ctx, aChannelID, userA.KeyName(), transfer, ibc.TransferOptions{}) + require.Error(t, err) + require.Contains(t, err.Error(), "denom is blacklisted") +} diff --git a/interchaintest/ibc_test.go b/interchaintest/ibc_test.go new file mode 100644 index 0000000..6ce4dfc --- /dev/null +++ b/interchaintest/ibc_test.go @@ -0,0 +1,125 @@ +package e2e + +import ( + "context" + "testing" + + "cosmossdk.io/math" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + interchaintestrelayer "github.com/strangelove-ventures/interchaintest/v8/relayer" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/strangelove-ventures/interchaintest/v8/testutil" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest" +) + +const ( + ibcPath = "ibc-path" +) + +func TestIBCBasic(t *testing.T) { + t.Parallel() + + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + cs := &DefaultChainSpec + cs.ModifyGenesis = cosmos.ModifyGenesis([]cosmos.GenesisKV{cosmos.NewGenesisKV("app_state.ratelimit.blacklisted_denoms", []string{})}) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + cs, + &SecondDefaultChainSpec, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chainA, chainB := chains[0].(*cosmos.CosmosChain), chains[1].(*cosmos.CosmosChain) + + // Relayer Factory + r := interchaintest.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t, zaptest.Level(zapcore.DebugLevel)), + interchaintestrelayer.CustomDockerImage(RelayerRepo, RelayerVersion, "100:1000"), + interchaintestrelayer.StartupFlags("--processor", "events", "--block-history", "200"), + ).Build(t, client, network) + + ic := interchaintest.NewInterchain(). + AddChain(chainA). + AddChain(chainB). + AddRelayer(r, "relayer") + + ic = ic.AddLink(interchaintest.InterchainLink{ + Chain1: chainA, + Chain2: chainB, + Relayer: r, + Path: ibcPath, + }) + + // Build interchain + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + })) + + require.NoError(t, testutil.WaitForBlocks(ctx, 5, chainA)) + + // Create and Fund User Wallets + fundAmount := math.NewInt(10_000_000) + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", fundAmount, chainA, chainB) + userA := users[0] + userB := users[1] + + userAInitial, err := chainA.GetBalance(ctx, userA.FormattedAddress(), chainA.Config().Denom) + require.NoError(t, err) + require.True(t, userAInitial.Equal(fundAmount)) + + // Get Channel ID + aInfo, err := r.GetChannels(ctx, eRep, chainA.Config().ChainID) + require.NoError(t, err) + aChannelID, err := getTransferChannel(aInfo) + require.NoError(t, err) + + bInfo, err := r.GetChannels(ctx, eRep, chainB.Config().ChainID) + require.NoError(t, err) + bChannelID, err := getTransferChannel(bInfo) + require.NoError(t, err) + + // Send Transaction + amountToSend := math.NewInt(1_000_000) + dstAddress := userB.FormattedAddress() + transfer := ibc.WalletAmount{ + Address: dstAddress, + Denom: chainA.Config().Denom, + Amount: amountToSend, + } + + _, err = chainA.SendIBCTransfer(ctx, aChannelID, userA.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + + // relay MsgRecvPacket to chainB, then MsgAcknowledgement back to chainA + require.NoError(t, r.Flush(ctx, eRep, ibcPath, aChannelID)) + + // test source wallet has decreased funds + expectedBal := userAInitial.Sub(amountToSend) + aNewBal, err := chainA.GetBalance(ctx, userA.FormattedAddress(), chainA.Config().Denom) + require.NoError(t, err) + require.True(t, aNewBal.Equal(expectedBal)) + + // Trace IBC Denom + srcDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", bChannelID, chainA.Config().Denom)) + dstIbcDenom := srcDenomTrace.IBCDenom() + + // Test destination wallet has increased funds + bNewBal, err := chainB.GetBalance(ctx, userB.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.True(t, bNewBal.Equal(amountToSend)) +} diff --git a/interchaintest/integration/README.md b/interchaintest/integration/README.md new file mode 100644 index 0000000..e73a267 --- /dev/null +++ b/interchaintest/integration/README.md @@ -0,0 +1,3 @@ +# ICS Integration Test + +Prysm Provider E2E Integration Test to verify the ICS implementation with consumer chains. diff --git a/interchaintest/chainsuite/chain.go b/interchaintest/integration/chainsuite/chain.go similarity index 100% rename from interchaintest/chainsuite/chain.go rename to interchaintest/integration/chainsuite/chain.go diff --git a/interchaintest/chainsuite/chain_spec_provider.go b/interchaintest/integration/chainsuite/chain_spec_provider.go similarity index 100% rename from interchaintest/chainsuite/chain_spec_provider.go rename to interchaintest/integration/chainsuite/chain_spec_provider.go diff --git a/interchaintest/chainsuite/config.go b/interchaintest/integration/chainsuite/config.go similarity index 100% rename from interchaintest/chainsuite/config.go rename to interchaintest/integration/chainsuite/config.go diff --git a/interchaintest/chainsuite/context.go b/interchaintest/integration/chainsuite/context.go similarity index 100% rename from interchaintest/chainsuite/context.go rename to interchaintest/integration/chainsuite/context.go diff --git a/interchaintest/chainsuite/query_types.go b/interchaintest/integration/chainsuite/query_types.go similarity index 100% rename from interchaintest/chainsuite/query_types.go rename to interchaintest/integration/chainsuite/query_types.go diff --git a/interchaintest/provider_suite.go b/interchaintest/integration/provider_suite.go similarity index 89% rename from interchaintest/provider_suite.go rename to interchaintest/integration/provider_suite.go index b9b3536..35dd3b0 100644 --- a/interchaintest/provider_suite.go +++ b/interchaintest/integration/provider_suite.go @@ -3,7 +3,7 @@ package e2e import ( "context" - "github.com/lightlabs-dev/prysm/interchaintest/chainsuite" + "github.com/lightlabs-dev/prysm/interchaintest/integration/chainsuite" "github.com/stretchr/testify/suite" ) diff --git a/interchaintest/provider_test.go b/interchaintest/integration/provider_test.go similarity index 99% rename from interchaintest/provider_test.go rename to interchaintest/integration/provider_test.go index 742e779..36a20f3 100644 --- a/interchaintest/provider_test.go +++ b/interchaintest/integration/provider_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/lightlabs-dev/prysm/interchaintest/chainsuite" + "github.com/lightlabs-dev/prysm/interchaintest/integration/chainsuite" govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" providertypes "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/suite" ) -func TestProviderSuite(t *testing.T) { +func TestICSProviderSuite(t *testing.T) { s := &ProviderSuite{} suite.Run(t, s) diff --git a/interchaintest/provider_utils.go b/interchaintest/integration/provider_utils.go similarity index 100% rename from interchaintest/provider_utils.go rename to interchaintest/integration/provider_utils.go diff --git a/interchaintest/old.zip b/interchaintest/old.zip deleted file mode 100644 index ad4740cce5bf2bbf3ff688b39887d59eb547aebf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8761 zcma)?bx<5z+wBK;cXtWyE&(RE3?2yXHh6Fe?vM$t2^J(+28Y4j-8D#n1P$&t=R4=# zI_JILTXnjtckR8a_pkbo-m6zVt3fIVi0FVn4ouTPga7IL)gS^W0WMBf+`2kw00c#V zvMtH)>#Yw401j~<0RTWe_}zehuO|F`KPuptk*xv5xDHzRd$th`03iKqwWo`twX==6 zrKgL#uc@cChbNb<%l{Bx-*edhas3CeQg6d$OCC3<;W@UFhK-;ZgQQ+9wHybr`(TzD zOt74;?YX>Y`Pv-TzV;U1Z}>Tg-_kM}Q5~$qSR;8pR_$Ulpu=YTg$Y$8f@d~+_%-(y zPqdb{pU)}Yx}U2_`Uq?9eeuL2eTeF>(e<`G<#6%|gOCyyUE z9nU&i-0#_!?`Ija8bUK&q>y>**VOBs%Sb)wmiAR9=XeymcfO3#1WI}zlSz9$XZs z(hXOuYCVfxA^x)S&FMB@_BTu|i(tH1<(=VziUWg`=tfZJOronZtP8?~DQeFh#te_N zskj&|@4g(jz6zpd8xhOMA#2rKmy3jLD|riii{Bqr$1(5z)T=#LpBtM|_)bvjqpZD9 z%+2B$VaV>&SDO#-+|+Ph;Lm^2-eP1Boqy;Vn6d+!st&7AUWyowBEHGRm~Di#i+waP znX{&BQ)uWLf9=x)H-*HRn=a1m1L0YcR=Ean8!N~7^cc)EwCF~#Y477KCVq{RpYmgz zzW)$pb0Msl%O%3VVf7itW>LkCN{zJX8M7{}_K>u(Ed*r1e41r-kXc02SdKQX!`LK! zh2F(ZS+<~6&-0vCQLE|hIsYUcSMp4fU~6i5c1Ro3)OvdKLZ_jtQqi&>jmoxKk|8P) z)t@}MP?9`20^It=?<$KlW%R4%DPv!UZa%+6U=!?k1*j``bta&BAAkF(^IXy8e9d<> zv3nLTHnv-0NR*+C1-s_?K)FD@vAXQC5vHF}{^1bj;xb#L2DSrgslM%>NEIYnv|!&4 zjvs+QORIym-m#q}jOaFCy*xg9%l9I_@Um}k;1uJZ+kYTC0<{4V0Jy*a0LcH^{`MA@ zrtapR)}~JOV0+JhBLKO2Y8u;$xRTqZQ@_l2Xtz6a^dMI+@kw9xK%;98;pk?+vL_M^ z6hi%_qN(|7*@?j(64^Y|xHW6X>nKYVud*^r8~0pMw6KeKm89ykpkJ z%Xk#(3n@_gTNP`-6^gDEIzv-{&78m6#p!;Z$?5si9LA&^OPp-8i8L984ne}l5BX{~ zOz&7REMNE!muj&S^lyE`69KI1>+slodvh|TD<(aO|L(x%q%9o%AsK~5Oc)9wLiXhqXZGOG1 zv+cUCxb)tI>s>FO^>aMl-#RA zGDfD~JC0p{*I~3ujZrx?IZNttyG>886YRok2=;34)@qP&4RX5YRj@75prs3T<8c(p zL`b=jxq=Oga0w6QCs-0P5Za6h!ToG7u#m1j`V??+{`%B&1 zgZZ8+#148?`;9Mh4yo1^Msw=)<+&bh&DY`T6VNgmgxl+1gg9}*rE!+VkQ@E<9=5+) zYLIIfeJu@5!|Xxm>0ODeUO&Tkgwef4ICZRbU-YDHfV&-S%0D+310oCA(RW%jZZ`S$ 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 T@*l4e%I_2WTSFUY{uuoq6H~P< diff --git a/interchaintest/packetforward_test.go b/interchaintest/packetforward_test.go new file mode 100644 index 0000000..a8fe8b4 --- /dev/null +++ b/interchaintest/packetforward_test.go @@ -0,0 +1,232 @@ +package e2e + +import ( + "context" + "encoding/json" + "testing" + "time" + + "cosmossdk.io/math" + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + interchaintestrelayer "github.com/strangelove-ventures/interchaintest/v8/relayer" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/strangelove-ventures/interchaintest/v8/testutil" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" + + transfertypes "github.com/cosmos/ibc-go/v8/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"` +} + +func TestPacketForwardMiddleware(t *testing.T) { + if testing.Short() { + t.Skip() + } + + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + var ( + chainID_A, chainID_B, chainID_C = "chain-a", "chain-b", "chain-c" + chainA, chainB, chainC *cosmos.CosmosChain + ) + + // base config which all networks will use as defaults. + baseCfg := DefaultChainConfig + + // 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 + + // Create chain factory with multiple individual networks. + numVals := 1 + numFullNodes := 0 + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + { + Name: configA.Name, + ChainConfig: configA, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + { + Name: configA.Name, + ChainConfig: configB, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + { + Name: configA.Name, + ChainConfig: configC, + NumValidators: &numVals, + NumFullNodes: &numFullNodes, + }, + }) + + // Get chains from the chain factory + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chainA, chainB, chainC = chains[0].(*cosmos.CosmosChain), chains[1].(*cosmos.CosmosChain), chains[2].(*cosmos.CosmosChain) + + r := interchaintest.NewBuiltinRelayerFactory( + ibc.CosmosRly, + zaptest.NewLogger(t), + interchaintestrelayer.CustomDockerImage(RelayerRepo, RelayerVersion, "100:1000"), + interchaintestrelayer.StartupFlags("--processor", "events", "--block-history", "100"), + ).Build(t, client, network) + + const pathAB = "ab" + const pathBC = "bc" + + ic := interchaintest.NewInterchain(). + AddChain(chainA). + AddChain(chainB). + AddChain(chainC). + 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, + }) + + 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() + }) + + users := interchaintest.GetAndFundTestUsers(t, ctx, t.Name(), GenesisFundsAmount, chainA, chainB, chainC) + + 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 + + // Start the relayer on all paths + err = r.StartRelayer(ctx, eRep, pathAB, pathBC) + 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 := users[0], users[1], users[2] + + var transferAmount math.Int = math.NewInt(100_000) + + // 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) + + firstHopDenomTrace := transfertypes.ParseDenomTrace(firstHopDenom) + secondHopDenomTrace := transfertypes.ParseDenomTrace(secondHopDenom) + + firstHopIBCDenom := firstHopDenomTrace.IBCDenom() + secondHopIBCDenom := secondHopDenomTrace.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)) + + t.Run("multi-hop a->b->c", func(t *testing.T) { + // Send packet from Chain A->Chain B->Chain C + + transfer := ibc.WalletAmount{ + Address: userB.FormattedAddress(), + Denom: chainA.Config().Denom, + Amount: transferAmount, + } + + firstHopMetadata := &PacketMetadata{ + Forward: &ForwardMetadata{ + Receiver: userC.FormattedAddress(), + Channel: bcChan.ChannelID, + Port: bcChan.PortID, + }, + } + + 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) + + require.Equal(t, GenesisFundsAmount.Sub(transferAmount).Int64(), chainABalance.Int64()) + require.Equal(t, int64(0), chainBBalance.Int64()) + require.Equal(t, int64(100000), chainCBalance.Int64()) + + firstHopEscrowBalance, err := chainA.GetBalance(ctx, firstHopEscrowAccount, chainA.Config().Denom) + require.NoError(t, err) + + secondHopEscrowBalance, err := chainB.GetBalance(ctx, secondHopEscrowAccount, firstHopIBCDenom) + require.NoError(t, err) + + require.Equal(t, transferAmount.Int64(), firstHopEscrowBalance.Int64()) + require.Equal(t, transferAmount.Int64(), secondHopEscrowBalance.Int64()) + }) +} diff --git a/interchaintest/tokenfactory_test.go b/interchaintest/tokenfactory_test.go new file mode 100644 index 0000000..d25cc04 --- /dev/null +++ b/interchaintest/tokenfactory_test.go @@ -0,0 +1,88 @@ +package e2e + +import ( + "context" + "testing" + + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" + "github.com/strangelove-ventures/interchaintest/v8/testreporter" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zaptest" +) + +func TestTokenFactory(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + + ctx := context.Background() + rep := testreporter.NewNopReporter() + eRep := rep.RelayerExecReporter(t) + client, network := interchaintest.DockerSetup(t) + + cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{ + &DefaultChainSpec, + }) + + chains, err := cf.Chains(t.Name()) + require.NoError(t, err) + + chain := chains[0].(*cosmos.CosmosChain) + + ic := interchaintest.NewInterchain().AddChain(chain) + + require.NoError(t, ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: t.Name(), + Client: client, + NetworkID: network, + SkipPathCreation: false, + })) + + users := interchaintest.GetAndFundTestUsers(t, ctx, "default", GenesisFundsAmount, chain, chain) + user := users[0] + user2 := users[1] + + uaddr := user.FormattedAddress() + uaddr2 := user2.FormattedAddress() + + node := chain.GetNode() + + tfDenom, _, err := node.TokenFactoryCreateDenom(ctx, user, "ictestdenom", 5_000_000) + t.Log("TF Denom: ", tfDenom) + require.NoError(t, err) + + t.Run("Mint TF Denom to user", func(t *testing.T) { + node.TokenFactoryMintDenom(ctx, user.FormattedAddress(), tfDenom, 100) + if balance, err := chain.GetBalance(ctx, uaddr, tfDenom); err != nil { + t.Fatal(err) + } else if balance.Int64() != 100 { + t.Fatal("balance not 100") + } + }) + + t.Run("Mint TF Denom to another user", func(t *testing.T) { + node.TokenFactoryMintDenomTo(ctx, user.FormattedAddress(), tfDenom, 70, user2.FormattedAddress()) + if balance, err := chain.GetBalance(ctx, uaddr2, tfDenom); err != nil { + t.Fatal(err) + } else if balance.Int64() != 70 { + t.Fatal("balance not 70") + } + }) + + t.Run("Change admin to uaddr2", func(t *testing.T) { + _, err = node.TokenFactoryChangeAdmin(ctx, user.KeyName(), tfDenom, uaddr2) + require.NoError(t, err) + }) + + t.Run("Validate new admin address", func(t *testing.T) { + res, err := chain.TokenFactoryQueryAdmin(ctx, tfDenom) + require.NoError(t, err) + require.EqualValues(t, res.AuthorityMetadata.Admin, uaddr2, "admin not uaddr2. Did not properly transfer.") + }) + + t.Cleanup(func() { + _ = ic.Close() + }) + +}