From ebf2e1ade882a67c8da0cd7615f796701df866ad Mon Sep 17 00:00:00 2001 From: Steve Miskovetz Date: Tue, 24 Oct 2023 11:48:29 -0600 Subject: [PATCH] Add igp testing to cosmos e2e --- interchaintest/tests/cosmos_e2e_test.go | 72 ++++++++++++++++++++++--- interchaintest/tests/hyperlane-rly.txt | 1 + interchaintest/tests/hyperlane_cfg.go | 11 +++- x/igp/keeper/msg_server.go | 3 +- 4 files changed, 79 insertions(+), 8 deletions(-) diff --git a/interchaintest/tests/cosmos_e2e_test.go b/interchaintest/tests/cosmos_e2e_test.go index 640ba6b..997dfd0 100644 --- a/interchaintest/tests/cosmos_e2e_test.go +++ b/interchaintest/tests/cosmos_e2e_test.go @@ -5,13 +5,15 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math/big" "os" "path/filepath" "strconv" "strings" "testing" "time" - + + "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" @@ -128,8 +130,9 @@ func TestHyperlaneCosmosE2E(t *testing.T) { verifyDomain(t, ctx, simd2, uint64(simd2Domain)) // Now we need to configure the Hyperlane modules and setup some test users... - userSimd := icv7.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), simd1)[0] + userSimd1 := icv7.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), simd1)[0] userSimd2 := icv7.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), simd2)[0] + simd1Oracle := icv7.GetAndFundTestUsers(t, ctx, "default", int64(10_000_000_000), simd1)[0] // Fund this wallet since the validator will announce its storage location with this mnemonic's private key. _, err = icv7.GetAndFundTestUserWithMnemonic(ctx, "valannounce", mnemonic, int64(10_000_000_000), simd1) @@ -138,12 +141,12 @@ func TestHyperlaneCosmosE2E(t *testing.T) { require.NoError(t, err) msg := `{}` - _, contract := helpers.SetupContract(t, ctx, simd1, userSimd.KeyName(), "../contracts/hyperlane.wasm", msg) + _, contract := helpers.SetupContract(t, ctx, simd1, userSimd1.KeyName(), "../contracts/hyperlane.wasm", msg) logger.Info("simd1 contract", zap.String("address", contract)) _, contract2 := helpers.SetupContract(t, ctx, simd2, userSimd2.KeyName(), "../contracts/hyperlane.wasm", msg) logger.Info("simd2 contract", zap.String("address", contract2)) - verifyContractEntryPoints(t, ctx, simd1, userSimd, contract) + verifyContractEntryPoints(t, ctx, simd1, userSimd1, contract) verifyContractEntryPoints(t, ctx, simd2, userSimd2, contract2) // Create counter chain 1 with val set signing legacy multisig. @@ -153,7 +156,7 @@ func TestHyperlaneCosmosE2E(t *testing.T) { simd2IsmValidator := counterchain.CreateEmperorValidator(t, simd2Domain, counterchain.LEGACY_MULTISIG, valSimd2PrivKey) // Set default isms for counter chains for SIMD - helpers.SetDefaultIsm(t, ctx, simd1, userSimd.KeyName(), simd2IsmValidator) + helpers.SetDefaultIsm(t, ctx, simd1, userSimd1.KeyName(), simd2IsmValidator) // Set default isms for counter chains for SIMD2 helpers.SetDefaultIsm(t, ctx, simd2, userSimd2.KeyName(), simd1IsmValidator) @@ -229,7 +232,7 @@ func TestHyperlaneCosmosE2E(t *testing.T) { // Dispatch the hyperlane message to simd1 dipatchMsg, err := json.Marshal(dispatchMsgStruct) require.NoError(t, err) - dispatchedTxHash, err := simd1.ExecuteContract(ctx, userSimd.KeyName(), contract, string(dipatchMsg)) + dispatchedTxHash, err := simd1.ExecuteContract(ctx, userSimd1.KeyName(), contract, string(dipatchMsg)) require.NoError(t, err) logger.Info("Message dispatched to simd1") dispatchedDestDomain, dispatchedRecipientAddrHex, dispatchedMsgBody, dispatchedMsgId, dispatchSender, _, err := helpers.VerifyDispatchEvents(simd1, dispatchedTxHash) @@ -239,6 +242,63 @@ func TestHyperlaneCosmosE2E(t *testing.T) { require.Equal(t, fmt.Sprintf("%d", simd2Domain), dispatchedDestDomain) // Finished sending message to simd1! + // ***************** IGP setup, copied from *************************************** + exchangeRate := math.NewInt(1e10) + gasPrice := math.NewInt(1) + testGasAmount := math.NewInt(300000) + quoteExpected := math.NewInt(300000) + beneficiary := "cosmos12aqqagjkk3y7mtgkgy5fuun3j84zr3c6e0zr6n" + + // This should be IGP 0, which we will ignore and not use for anything + out := helpers.CallCreateIgp(t, ctx, simd1, userSimd1.KeyName(), beneficiary) + igpTxHash := helpers.ParseTxHash(string(out)) + igpIdUint, err := helpers.VerifyIgpEvents(simd1, igpTxHash) + require.NoError(t, err) + require.Equal(t, uint32(0), igpIdUint) + + // This should be IGP 1 + createigpout := helpers.CallCreateIgp(t, ctx, simd1, userSimd1.KeyName(), beneficiary) + igpTxHash = helpers.ParseTxHash(string(createigpout)) + igpIdUint, err = helpers.VerifyIgpEvents(simd1, igpTxHash) + require.NoError(t, err) + require.Equal(t, uint32(1), igpIdUint) + igpId := strconv.FormatUint(uint64(igpIdUint), 10) + + destDomainStr := strconv.FormatUint(uint64(simd2Domain), 10) + createOracleOutput := helpers.CallCreateOracle(t, ctx, simd1, userSimd1.KeyName(), simd1Oracle.FormattedAddress(), igpId, destDomainStr) + createOracleTxHash := helpers.ParseTxHash(string(createOracleOutput)) + oracleEvtAddr, err := helpers.VerifyCreateOracleEvents(simd1, createOracleTxHash) + require.NoError(t, err) + require.Equal(t, simd1Oracle.FormattedAddress(), oracleEvtAddr) + + + // This should succeed, and we verify the events contain the expected domain/exchange rate/gas price. + setGasOutput := helpers.CallSetGasPriceMsg(t, ctx, simd1, simd1Oracle.KeyName(), igpId, destDomainStr, gasPrice.String(), exchangeRate.String()) + setGasTxHash2 := helpers.ParseTxHash(string(setGasOutput)) + setGasDomain, setGasRate, setGasPrice, err := helpers.VerifySetGasPriceEvents(simd1, setGasTxHash2) + require.NoError(t, err) + require.Equal(t, setGasDomain, destDomainStr) + require.Equal(t, setGasRate, exchangeRate.String()) + require.Equal(t, setGasPrice, gasPrice.String()) + + // Look up the expected payment and verify it matches what we expected (according to the gas price, exchange rate, and scale). + quoteGasPaymentOutput := helpers.QueryQuoteGasPayment(t, ctx, simd1, userSimd1.KeyName(), igpId, destDomainStr, testGasAmount.String()) + nativeTokensOwed, denom := helpers.ParseQuoteGasPayment(string(quoteGasPaymentOutput)) + amountActual, _ := big.NewInt(0).SetString(nativeTokensOwed, 10) + require.Equal(t, amountActual.String(), quoteExpected.String()) + require.Equal(t, denom, "stake") + + maxPayment := sdk.NewCoin(denom, math.NewIntFromBigInt(amountActual)) + payForGasOutput := helpers.CallPayForGasMsg(t, ctx, simd1, simd1Oracle.KeyName(), dispatchedMsgId, destDomainStr, testGasAmount.String(), igpId, maxPayment.String()) + payForGasTxHash := helpers.ParseTxHash(string(payForGasOutput)) + paidMsgId, nativePayment, gasAmount, err := helpers.VerifyPayForGasEvents(simd1, payForGasTxHash) + require.NoError(t, err) + require.Equal(t, dispatchedMsgId, paidMsgId) + require.Equal(t, nativePayment, nativeTokensOwed) + require.Equal(t, gasAmount, testGasAmount.String()) + + // *************** Continue with non-IGP testing *********************** + // Wait for the hyperlane validator to sign it. The first message will show up as 0.json expectedSigFile := "0.json" simd1FirstSignedCheckpoint := filepath.Join(simd1ValidatorSignaturesDir, expectedSigFile) diff --git a/interchaintest/tests/hyperlane-rly.txt b/interchaintest/tests/hyperlane-rly.txt index f6100a5..c58908c 100644 --- a/interchaintest/tests/hyperlane-rly.txt +++ b/interchaintest/tests/hyperlane-rly.txt @@ -4,4 +4,5 @@ HYP_BASE_REORGPERIOD=1 HYP_BASE_DEFAULTSIGNER_KEY=8166f546bab6da521a8369cab06c5d2b9e46670292d85c875ee9ec20e84ffb61 HYP_BASE_DEFAULTSIGNER_TYPE=hexKey HYP_BASE_ALLOWLOCALCHECKPOINTSYNCERS=true +HYP_BASE_GASPAYMENTENFORCEMENT=[{"type": "minimum", "payment": 1000}] RUST_BACKTRACE=full \ No newline at end of file diff --git a/interchaintest/tests/hyperlane_cfg.go b/interchaintest/tests/hyperlane_cfg.go index 0bd86d2..a7491fe 100644 --- a/interchaintest/tests/hyperlane_cfg.go +++ b/interchaintest/tests/hyperlane_cfg.go @@ -102,10 +102,15 @@ type hyperlaneAddresses struct { Igp string `json:"interchainGasPaymaster,omitempty"` Announce string `json:"validatorAnnounce,omitempty"` } +type hyperlaneIndex struct { + From int `json:"from,omitempty"` + Chunk int `json:"chunk,omitempty"` +} type hyperlaneChainCfg struct { Connection *hyperlaneChainConnection `json:"connection,omitempty"` Signer *hyperlaneSigner `json:"signer,omitempty"` Addresses *hyperlaneAddresses `json:"addresses,omitempty"` + Index *hyperlaneIndex `json:"index,omitempty"` Name string `json:"name,omitempty"` Domain uint32 `json:"domain,omitempty"` Protocol string `json:"protocol,omitempty"` @@ -146,9 +151,13 @@ func generateHyperlaneRelayerConfig(chains []chainCfg) string { }, Addresses: &hyperlaneAddresses{ Mailbox: chain.originMailboxHex, - Igp: "0x6cA0B6D22da47f091B7613223cD4BB03a2d77918", + Igp: "0x0000000000000000000000000000000000000001", Announce: "0x9bBdef63594D5FFc2f370Fe52115DdFFe97Bc524", }, + Index: &hyperlaneIndex{ + From: 1, + Chunk: 5, + }, Name: chain.chainName, Domain: chain.domain, Protocol: "cosmosModules", diff --git a/x/igp/keeper/msg_server.go b/x/igp/keeper/msg_server.go index 6cf21c2..c87f329 100644 --- a/x/igp/keeper/msg_server.go +++ b/x/igp/keeper/msg_server.go @@ -80,7 +80,8 @@ func (k Keeper) PayForGas(goCtx context.Context, msg *types.MsgPayForGas) (*type sdk.NewAttribute(types.AttributeGasAmount, msg.GasAmount.String()), sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeBeneficiary, beneficiary), - sdk.NewAttribute(types.AttributePayment, gasPayment.String()), + sdk.NewAttribute(types.AttributePayment, gasPayment.Amount.String()), + sdk.NewAttribute(types.AttributeIgpId, strconv.FormatUint(uint64(msg.IgpId), 10)), ), sdk.NewEvent( sdk.EventTypeMessage,