From d7cd5f86d6f216b7d40d6ae6020f7c868ca9411f Mon Sep 17 00:00:00 2001 From: Charlie <31941002+CharlieMc0@users.noreply.github.com> Date: Sat, 20 Jan 2024 12:13:52 -0700 Subject: [PATCH 1/5] docs: updated release instructions (#1585) * updated readme * updated readme * updated readme * Update changelog.md Co-authored-by: Lucas Bertrand * Update readme.md Co-authored-by: Lucas Bertrand * Update readme.md Co-authored-by: Lucas Bertrand --------- Co-authored-by: Lucas Bertrand --- changelog.md | 5 +++++ readme.md | 28 ++++++++++++++-------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index f7049e9a7d..26932679a2 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,10 @@ ## Unreleased +### Chores + +* [1585](https://github.com/zeta-chain/node/pull/1585) - Updated release instructions + ### Features ### Fixes @@ -11,6 +15,7 @@ ## Version: v12.0.0 + ### Breaking Changes TSS and chain validation related queries have been moved from `crosschain` module to `observer` module: diff --git a/readme.md b/readme.md index b9db6be3c2..a3a931f7fa 100644 --- a/readme.md +++ b/readme.md @@ -81,27 +81,27 @@ to [run the smoke test](./contrib/localnet/README.md). [Discord](https://discord.com/invite/zetachain) | [Telegram](https://t.me/zetachainofficial) | [Website](https://zetachain.com) -## Creating a Release for Mainnet -Creating a release for mainnet is a straightforward process. Here are the steps to follow: -### Steps - - Step 1. Open a Pull Request (PR): Begin by opening a PR from the release candidate branch (e.g., vx.x.x-rc) to the main branch. - - Step 2. Testing and Validation: Allow the automated tests, including smoke tests, linting, and upgrade path testing, to run. Ensure that these tests pass successfully. - - Step 3. Approval Process: Obtain the necessary approvals from relevant stakeholders or team members. - - Step 4. Merging PR: Once all requirements have been met and the PR has received the required approvals, merge the PR. The automation will then be triggered to proceed with the release. - -By following these steps, you can efficiently create a release for Mainnet, ensuring that the code has been thoroughly tested and validated before deployment. - -## Creating a Release for Testnet -Creating a release for testnet is a straightforward process. Here are the steps to follow: +## Creating a Release Candidate +Creating a release candidate for testing is a straightforward process. Here are the steps to follow: ### Steps - Step 1. Create the release candidate tag with the following format (e.g., vx.x.x-rc) ex. v11.0.0-rc. - Step 2. Once a RC branch is created the automation will kickoff to build and upload the release and its binaries. -By following these steps, you can efficiently create a release candidate for testnet for QA and validation. In the future we will make this automatically deploy to testnet when a -rc branch is created. -Currently, raising the proposal to deploy to testnet is a manual process via GitHub Action pipeline located in the infrastructure repo. +By following these steps, you can efficiently create a release candidate for QA and validation. In the future we will make this automatically deploy to a testnet when a -rc branch is created. +Currently, raising the proposal to deploy to testnet is a manual process via GovOps repo. + +## Creating a Release +After the Release Candidate has been fully tested, creating a final release for use on public networks is a straightforward process. Here are the steps to follow: + +### Steps + - Step 1. Open a Pull Request (PR): Begin by opening a PR from the release candidate branch (e.g., vx.x.x-rc) to the main branch. + - Step 2. Testing and Validation: Allow the automated tests, including E2E tests, linting, and upgrade path testing, to run. Ensure that these tests pass successfully. + - Step 3. Approval Process: Obtain the necessary approvals from relevant stakeholders or team members. + - Step 4. Merging PR: Once all requirements have been met and the PR has received the required approvals, merge the PR. The automation will then be triggered to proceed with the release. +By following these steps, you can efficiently create a release, ensuring that the code has been thoroughly tested and validated before deployment to public networks. ## Creating a Hotfix Release Creating a hotfix release is a straightforward process. Here are the steps to follow: From da6f9e38b4ae5384fcbb3dd25e8fe13f314993d8 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Sat, 20 Jan 2024 11:46:13 -0800 Subject: [PATCH 2/5] test(`e2e`): add chain header tests back and fix admin tests (#1577) * add header test back * fix admin tests * update changelogs --- changelog.md | 9 ++++++--- cmd/zetae2e/local/admin.go | 2 +- cmd/zetae2e/local/bitcoin.go | 2 +- cmd/zetae2e/local/ethereum.go | 2 +- cmd/zetae2e/local/local.go | 6 +++++- .../smoketest/smoketests/test_pause_zrc20.go | 12 ++++++------ 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/changelog.md b/changelog.md index 26932679a2..01b77c5681 100644 --- a/changelog.md +++ b/changelog.md @@ -2,9 +2,9 @@ ## Unreleased -### Chores +### Tests -* [1585](https://github.com/zeta-chain/node/pull/1585) - Updated release instructions +* [1577](https://github.com/zeta-chain/node/pull/1577) - add chain header tests in E2E tests and fix admin tests ### Features @@ -13,8 +13,11 @@ * [1535](https://github.com/zeta-chain/node/issues/1535) - Avoid voting on wrong ballots due to false blockNumber in EVM tx receipt * [1588](https://github.com/zeta-chain/node/pull/1588) - fix chain params comparison logic -## Version: v12.0.0 +### Chores + +* [1585](https://github.com/zeta-chain/node/pull/1585) - Updated release instructions +## Version: v12.0.0 ### Breaking Changes diff --git a/cmd/zetae2e/local/admin.go b/cmd/zetae2e/local/admin.go index 01e5d3ae8f..34900fbaf4 100644 --- a/cmd/zetae2e/local/admin.go +++ b/cmd/zetae2e/local/admin.go @@ -66,7 +66,7 @@ func adminTestRoutine( smoketests.TestUpdateBytecodeName, smoketests.TestDepositEtherLiquidityCapName, ); err != nil { - return fmt.Errorf("admim tests failed: %v", err) + return fmt.Errorf("admin tests failed: %v", err) } adminRunner.Logger.Print("🍾 admin tests completed in %s", time.Since(startTime).String()) diff --git a/cmd/zetae2e/local/bitcoin.go b/cmd/zetae2e/local/bitcoin.go index a27d619138..eaf700465e 100644 --- a/cmd/zetae2e/local/bitcoin.go +++ b/cmd/zetae2e/local/bitcoin.go @@ -59,7 +59,7 @@ func bitcoinTestRoutine( bitcoinRunner.WaitForMinedCCTX(txERC20Deposit) bitcoinRunner.SetupBitcoinAccount(initBitcoinNetwork) - bitcoinRunner.DepositBTC(false) + bitcoinRunner.DepositBTC(true) // run bitcoin test // Note: due to the extensive block generation in Bitcoin localnet, block header test is run first diff --git a/cmd/zetae2e/local/ethereum.go b/cmd/zetae2e/local/ethereum.go index 74a57a6470..90d6a35dfb 100644 --- a/cmd/zetae2e/local/ethereum.go +++ b/cmd/zetae2e/local/ethereum.go @@ -47,7 +47,7 @@ func ethereumTestRoutine( startTime := time.Now() // depositing the necessary tokens on ZetaChain - txEtherDeposit := ethereumRunner.DepositEther(false) + txEtherDeposit := ethereumRunner.DepositEther(true) ethereumRunner.WaitForMinedCCTX(txEtherDeposit) // run ethereum test diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index f1a723f26e..b31c6869d4 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -135,7 +135,11 @@ func localE2ETest(cmd *cobra.Command, _ []string) { } testStartTime := time.Now() - logger.Print("starting tests") + logger.Print("starting E2E tests") + + if testAdmin { + logger.Print("⚠️ admin tests enabled") + } // start timer go func() { diff --git a/contrib/localnet/orchestrator/smoketest/smoketests/test_pause_zrc20.go b/contrib/localnet/orchestrator/smoketest/smoketests/test_pause_zrc20.go index 5b6a9700b1..f3579990f2 100644 --- a/contrib/localnet/orchestrator/smoketest/smoketests/test_pause_zrc20.go +++ b/contrib/localnet/orchestrator/smoketest/smoketests/test_pause_zrc20.go @@ -28,7 +28,7 @@ func TestPauseZRC20(sm *runner.SmokeTestRunner) { if receipt.Status == 0 { panic("Vault approval should succeed") } - tx, err = sm.BTCZRC20.Approve(sm.ZevmAuth, vaultAddr, big.NewInt(1e18)) + tx, err = sm.USDTZRC20.Approve(sm.ZevmAuth, vaultAddr, big.NewInt(1e18)) if err != nil { panic(err) } @@ -93,23 +93,23 @@ func TestPauseZRC20(sm *runner.SmokeTestRunner) { } sm.Logger.Info("Operations all failed") - // Check we can still interact with BTC ZRC20 + // Check we can still interact with USDT ZRC20 sm.Logger.Info("Check other ZRC20 can still be operated") - tx, err = sm.BTCZRC20.Transfer(sm.ZevmAuth, sample.EthAddress(), big.NewInt(1e3)) + tx, err = sm.USDTZRC20.Transfer(sm.ZevmAuth, sample.EthAddress(), big.NewInt(1e3)) if err != nil { panic(err) } receipt = utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, tx, sm.Logger, sm.ReceiptTimeout) if receipt.Status == 0 { - panic("BTC transfer should succeed") + panic("USDT transfer should succeed") } - tx, err = vaultContract.Deposit(sm.ZevmAuth, sm.BTCZRC20Addr, big.NewInt(1e3)) + tx, err = vaultContract.Deposit(sm.ZevmAuth, sm.USDTZRC20Addr, big.NewInt(1e3)) if err != nil { panic(err) } receipt = utils.MustWaitForTxReceipt(sm.Ctx, sm.ZevmClient, tx, sm.Logger, sm.ReceiptTimeout) if receipt.Status == 0 { - panic("BTC vault deposit should succeed") + panic("USDT vault deposit should succeed") } // Check deposit revert when paused From e06711b63e7cc71e5999e4ba6674e7f27147478b Mon Sep 17 00:00:00 2001 From: Grant Zukel <80433392+gzukel@users.noreply.github.com> Date: Sat, 20 Jan 2024 22:49:04 -0700 Subject: [PATCH 3/5] ci: fix the cleanup step in the rc-release and publish-release pipelines (#1580) * fix: fix the cleanup step in the rc-release and publish-release pipelines * fix: fix the cleanup step in the rc-release and publish-release pipelines * Update rc-release.yml Co-authored-by: Lucas Bertrand --------- Co-authored-by: Charlie <31941002+CharlieMc0@users.noreply.github.com> Co-authored-by: Lucas Bertrand --- .github/workflows/publish-release.yml | 2 +- .github/workflows/rc-release.yml | 2 +- changelog.md | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 951f7a2888..fa01e0d4e4 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -133,4 +133,4 @@ jobs: - name: Clean Up Workspace if: always() shell: bash - run: rm -rf * \ No newline at end of file + run: sudo rm -rf * || echo "failed to cleanup workspace please investigate" \ No newline at end of file diff --git a/.github/workflows/rc-release.yml b/.github/workflows/rc-release.yml index fcd8faff9c..2e4fbfd194 100644 --- a/.github/workflows/rc-release.yml +++ b/.github/workflows/rc-release.yml @@ -85,4 +85,4 @@ jobs: - name: Clean Up Workspace if: always() shell: bash - run: rm -rf * \ No newline at end of file + run: sudo rm -rf * || echo "failed to clean workspace please investigate" \ No newline at end of file diff --git a/changelog.md b/changelog.md index 01b77c5681..0fd90f83af 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,10 @@ * [1535](https://github.com/zeta-chain/node/issues/1535) - Avoid voting on wrong ballots due to false blockNumber in EVM tx receipt * [1588](https://github.com/zeta-chain/node/pull/1588) - fix chain params comparison logic +### CI + +* [1580](https://github.com/zeta-chain/node/pull/1580) - Fix release pipelines cleanup step. + ### Chores * [1585](https://github.com/zeta-chain/node/pull/1585) - Updated release instructions From d1abe7b8dced067e218b95ff4ee478b9fe8f5785 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sun, 21 Jan 2024 12:18:54 -0500 Subject: [PATCH 4/5] fix: get tss address cli (#1589) * add btc chain id to get tss address cli * add btc chain id to get tss address historical cli * use maximum args instead of exact args * add changelog * generate docs * lint issue --------- Co-authored-by: Lucas Bertrand --- changelog.md | 1 + ...ery_observer_get-historical-tss-address.md | 2 +- ...etacored_query_observer_get-tss-address.md | 2 +- .../client/cli/query_get_tss_address.go | 23 +++++++++++++++---- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 0fd90f83af..832f006123 100644 --- a/changelog.md +++ b/changelog.md @@ -80,6 +80,7 @@ Getting the correct TSS address for Bitcoin now requires proviidng the Bitcoin c * [1546](https://github.com/zeta-chain/node/pull/1546) - fix reset of pending nonces on genesis import * [1555](https://github.com/zeta-chain/node/pull/1555) - Reduce websocket message limit to 10MB * [1567](https://github.com/zeta-chain/node/pull/1567) - add bitcoin chain id to fetch the tss address rpc endpoint +* [1589](https://github.com/zeta-chain/node/pull/1589) - add bitcoin chain id to `get tss address` and `get tss address historical` cli query ### Refactoring diff --git a/docs/cli/zetacored/zetacored_query_observer_get-historical-tss-address.md b/docs/cli/zetacored/zetacored_query_observer_get-historical-tss-address.md index 83de26b9dd..d56798a084 100644 --- a/docs/cli/zetacored/zetacored_query_observer_get-historical-tss-address.md +++ b/docs/cli/zetacored/zetacored_query_observer_get-historical-tss-address.md @@ -3,7 +3,7 @@ Query tss address by finalized zeta height (for historical tss addresses) ``` -zetacored query observer get-historical-tss-address [finalizedZetaHeight] [flags] +zetacored query observer get-historical-tss-address [finalizedZetaHeight] [bitcoinChainId] [flags] ``` ### Options diff --git a/docs/cli/zetacored/zetacored_query_observer_get-tss-address.md b/docs/cli/zetacored/zetacored_query_observer_get-tss-address.md index cb763f8510..5c5e68bd14 100644 --- a/docs/cli/zetacored/zetacored_query_observer_get-tss-address.md +++ b/docs/cli/zetacored/zetacored_query_observer_get-tss-address.md @@ -3,7 +3,7 @@ Query current tss address ``` -zetacored query observer get-tss-address [flags] +zetacored query observer get-tss-address [bitcoinChainId]] [flags] ``` ### Options diff --git a/x/observer/client/cli/query_get_tss_address.go b/x/observer/client/cli/query_get_tss_address.go index 8bfac0e10f..d37fb95f0c 100644 --- a/x/observer/client/cli/query_get_tss_address.go +++ b/x/observer/client/cli/query_get_tss_address.go @@ -11,9 +11,9 @@ import ( func CmdGetTssAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "get-tss-address", + Use: "get-tss-address [bitcoinChainId]]", Short: "Query current tss address", - Args: cobra.NoArgs, + Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) @@ -21,8 +21,14 @@ func CmdGetTssAddress() *cobra.Command { return err } queryClient := types.NewQueryClient(clientCtx) - params := &types.QueryGetTssAddressRequest{} + if len(args) == 1 { + bitcoinChainID, err := strconv.ParseInt(args[0], 10, 64) + if err != nil { + return err + } + params.BitcoinChainId = bitcoinChainID + } res, err := queryClient.GetTssAddress(cmd.Context(), params) if err != nil { @@ -40,9 +46,9 @@ func CmdGetTssAddress() *cobra.Command { func CmdGetTssAddressByFinalizedZetaHeight() *cobra.Command { cmd := &cobra.Command{ - Use: "get-historical-tss-address [finalizedZetaHeight]", + Use: "get-historical-tss-address [finalizedZetaHeight] [bitcoinChainId]", Short: "Query tss address by finalized zeta height (for historical tss addresses)", - Args: cobra.ExactArgs(1), + Args: cobra.MaximumNArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) @@ -58,6 +64,13 @@ func CmdGetTssAddressByFinalizedZetaHeight() *cobra.Command { params := &types.QueryGetTssAddressByFinalizedHeightRequest{ FinalizedZetaHeight: finalizedZetaHeight, } + if len(args) == 2 { + bitcoinChainID, err := strconv.ParseInt(args[1], 10, 64) + if err != nil { + return err + } + params.BitcoinChainId = bitcoinChainID + } res, err := queryClient.GetTssAddressByFinalizedHeight(cmd.Context(), params) if err != nil { From dfc2314e0253293622e1da9cee8b6340b7f9b445 Mon Sep 17 00:00:00 2001 From: brewmaster012 <88689859+brewmaster012@users.noreply.github.com> Date: Mon, 22 Jan 2024 10:03:03 -0800 Subject: [PATCH 5/5] fix: exempt system txs from min gas check and fee deduction (#1605) * exempt system txs from min gas check and fee deduction in antehandlers. System txs are 7 zetaclient txs from observers. * update changelog * sort imports * simplify conditional branches in ante.go * add back fee deductor; allow system tx so set 1% min gas price * update changelog * update broadcast func to adjust gas price * refactor per review * factor out the reduction rate in to common variable * factor out the system tx determinator * separate out MsgCreateValidator * refactor per review comments * clean up * add unit tests * add one unit test * fix unit tests by using higher gas limits for inbound and outbound voters --------- Co-authored-by: Tanmay --- app/ante/ante.go | 94 +++++--- app/ante/ante_test.go | 216 +++++++++++++++++- app/ante/fees.go | 11 +- app/ante/handler_options.go | 34 ++- app/app.go | 3 +- changelog.md | 1 + .../client/integrationtests/cli_helpers.go | 16 +- .../integrationtests/inbound_voter_test.go | 7 +- .../cli/tx_deploy_fungible_coin_zrc_4.go | 2 - .../cli/tx_update_zrc20_liquidity_cap.go | 3 - zetaclient/broadcast.go | 6 +- 11 files changed, 344 insertions(+), 49 deletions(-) diff --git a/app/ante/ante.go b/app/ante/ante.go index 7d9586edfb..e1077339b4 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -19,19 +19,18 @@ import ( "fmt" "runtime/debug" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ethante "github.com/evmos/ethermint/app/ante" - cctxtypes "github.com/zeta-chain/zetacore/x/crosschain/types" - - tmlog "github.com/tendermint/tendermint/libs/log" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/authz" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + tmlog "github.com/tendermint/tendermint/libs/log" + cctxtypes "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) -func ValidateHandlerOptions(options ethante.HandlerOptions) error { +func ValidateHandlerOptions(options HandlerOptions) error { if options.AccountKeeper == nil { return errorsmod.Wrap(errortypes.ErrLogic, "account keeper is required for AnteHandler") } @@ -47,6 +46,9 @@ func ValidateHandlerOptions(options ethante.HandlerOptions) error { if options.EvmKeeper == nil { return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler") } + if options.ObserverKeeper == nil { + return errorsmod.Wrap(errortypes.ErrLogic, "observer keeper is required for AnteHandler") + } return nil } @@ -54,7 +56,7 @@ func ValidateHandlerOptions(options ethante.HandlerOptions) error { // Ethereum or SDK transaction to an internal ante handler for performing // transaction-level processing (e.g. fee payment, signature verification) before // being passed onto it's respective handler. -func NewAnteHandler(options ethante.HandlerOptions) (sdk.AnteHandler, error) { +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { if err := ValidateHandlerOptions(options); err != nil { return nil, err } @@ -94,28 +96,26 @@ func NewAnteHandler(options ethante.HandlerOptions) (sdk.AnteHandler, error) { // handle as totally normal Cosmos SDK tx switch tx.(type) { case sdk.Tx: - found := false - for _, msg := range tx.GetMsgs() { - switch msg.(type) { - // treat these three msg types differently because they might call EVM which results in massive gas consumption - // For these two msg types, we don't check gas limit by using a different ante handler - case *cctxtypes.MsgGasPriceVoter, *cctxtypes.MsgVoteOnObservedInboundTx: - found = true - break - case *stakingtypes.MsgCreateValidator: - if ctx.BlockHeight() == 0 { - found = true - break - } - } + // default: handle as normal Cosmos SDK tx + anteHandler = newCosmosAnteHandler(options) + + // if tx is a system tx, and singer is authorized, use system tx handler + + isAuthorized := func(creator string) bool { + return options.ObserverKeeper.IsAuthorized(ctx, creator) } - if len(tx.GetMsgs()) == 1 && found { - // this differs newCosmosAnteHandler only in that it doesn't check gas limit - // by using an Infinite Gas Meter. - anteHandler = newCosmosAnteHandlerNoGasLimit(options) - } else { - anteHandler = newCosmosAnteHandler(options) + if IsSystemTx(tx, isAuthorized) { + anteHandler = newCosmosAnteHandlerForSystemTx(options) } + + // if tx is MsgCreatorValidator, use the newCosmosAnteHandlerForSystemTx handler to + // exempt gas fee requirement in genesis because it's not possible to pay gas fee in genesis + if len(tx.GetMsgs()) == 1 { + if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 { + anteHandler = newCosmosAnteHandlerForSystemTx(options) + } + } + default: return ctx, errorsmod.Wrapf(errortypes.ErrUnknownRequest, "invalid transaction type: %T", tx) } @@ -145,3 +145,41 @@ func Recover(logger tmlog.Logger, err *error) { } } } + +// IsSystemTx determines whether tx is a system tx that's signed by an authorized signer +// system tx are special types of txs (see in the switch below), or such txs wrapped inside a MsgExec +// the parameter isAuthorizedSigner is a caller specified function that determines whether the signer of +// the tx is authorized. +func IsSystemTx(tx sdk.Tx, isAuthorizedSigner func(string) bool) bool { + // the following determines whether the tx is a system tx which will uses different handler + // System txs are always single Msg txs, optionally wrapped by one level of MsgExec + if len(tx.GetMsgs()) != 1 { // this is not a system tx + return false + } + msg := tx.GetMsgs()[0] + + // if wrapped inside a MsgExec, unwrap it and reveal the innerMsg. + var innerMsg sdk.Msg + innerMsg = msg + if mm, ok := msg.(*authz.MsgExec); ok { // authz tx; look inside it + msgs, err := mm.GetMessages() + if err == nil && len(msgs) == 1 { + innerMsg = msgs[0] + } + } + switch innerMsg.(type) { + case *cctxtypes.MsgGasPriceVoter, + *cctxtypes.MsgVoteOnObservedInboundTx, + *cctxtypes.MsgVoteOnObservedOutboundTx, + *cctxtypes.MsgAddToOutTxTracker, + *cctxtypes.MsgCreateTSSVoter, + *observertypes.MsgAddBlockHeader, + *observertypes.MsgAddBlameVote: + signers := innerMsg.GetSigners() + if len(signers) == 1 { + return isAuthorizedSigner(signers[0].String()) + } + } + + return false +} diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 53a7d95c85..146e50c6ae 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -1,6 +1,19 @@ package ante_test -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/app" + "github.com/zeta-chain/zetacore/app/ante" + "github.com/zeta-chain/zetacore/testutil/sample" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) var _ sdk.AnteHandler = (&MockAnteHandler{}).AnteHandle @@ -16,3 +29,204 @@ func (mah *MockAnteHandler) AnteHandle(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.C mah.CalledCtx = ctx return ctx, nil } + +func TestIsSystemTx(t *testing.T) { + // system tx types: + // *cctxtypes.MsgGasPriceVoter, + // *cctxtypes.MsgVoteOnObservedInboundTx, + // *cctxtypes.MsgVoteOnObservedOutboundTx, + // *cctxtypes.MsgAddToOutTxTracker, + // *cctxtypes.MsgCreateTSSVoter, + // *observertypes.MsgAddBlockHeader, + // *observertypes.MsgAddBlameVote: + buildTxFromMsg := func(msg sdk.Msg) sdk.Tx { + txBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() + txBuilder.SetMsgs(msg) + return txBuilder.GetTx() + } + buildAuthzTxFromMsg := func(msg sdk.Msg) sdk.Tx { + txBuilder := app.MakeEncodingConfig().TxConfig.NewTxBuilder() + msgExec := authz.NewMsgExec(sample.Bech32AccAddress(), []sdk.Msg{msg}) + txBuilder.SetMsgs(&msgExec) + return txBuilder.GetTx() + } + isAuthorized := func(_ string) bool { + return true + } + isAuthorizedFalse := func(_ string) bool { + return false + } + + tests := []struct { + name string + tx sdk.Tx + isAuthorized func(string) bool + wantIs bool + }{ + { + "MsgCreateTSSVoter", + buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{ + Creator: sample.AccAddress(), + TssPubkey: "pubkey1234", + }), + isAuthorizedFalse, + false, + }, + { + "MsgCreateTSSVoter", + buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{ + Creator: sample.AccAddress(), + TssPubkey: "pubkey1234", + }), + isAuthorized, + true, + }, + { + "MsgExec{MsgCreateTSSVoter}", + buildAuthzTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{ + Creator: sample.AccAddress(), + TssPubkey: "pubkey1234", + }), + isAuthorized, + + true, + }, + { + "MsgSend", + buildTxFromMsg(&banktypes.MsgSend{}), + isAuthorized, + + false, + }, + { + "MsgExec{MsgSend}", + buildAuthzTxFromMsg(&banktypes.MsgSend{}), + isAuthorized, + + false, + }, + { + "MsgCreateValidator", + buildTxFromMsg(&stakingtypes.MsgCreateValidator{}), + isAuthorized, + + false, + }, + + { + "MsgVoteOnObservedInboundTx", + buildTxFromMsg(&crosschaintypes.MsgVoteOnObservedInboundTx{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgVoteOnObservedInboundTx}", + buildAuthzTxFromMsg(&crosschaintypes.MsgVoteOnObservedInboundTx{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + + { + "MsgVoteOnObservedOutboundTx", + buildTxFromMsg(&crosschaintypes.MsgVoteOnObservedOutboundTx{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgVoteOnObservedOutboundTx}", + buildAuthzTxFromMsg(&crosschaintypes.MsgVoteOnObservedOutboundTx{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgAddToOutTxTracker", + buildTxFromMsg(&crosschaintypes.MsgAddToOutTxTracker{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgAddToOutTxTracker}", + buildAuthzTxFromMsg(&crosschaintypes.MsgAddToOutTxTracker{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgCreateTSSVoter", + buildTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgCreateTSSVoter}", + buildAuthzTxFromMsg(&crosschaintypes.MsgCreateTSSVoter{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgAddBlockHeader", + buildTxFromMsg(&observertypes.MsgAddBlockHeader{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgAddBlockHeader}", + buildAuthzTxFromMsg(&observertypes.MsgAddBlockHeader{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgAddBlameVote", + buildTxFromMsg(&observertypes.MsgAddBlameVote{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + { + "MsgExec{MsgAddBlameVote}", + buildAuthzTxFromMsg(&observertypes.MsgAddBlameVote{ + Creator: sample.AccAddress(), + }), + isAuthorized, + + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + is := ante.IsSystemTx(tt.tx, tt.isAuthorized) + require.Equal(t, tt.wantIs, is) + }) + } +} diff --git a/app/ante/fees.go b/app/ante/fees.go index adb0fef13d..912ed8e0e2 100644 --- a/app/ante/fees.go +++ b/app/ante/fees.go @@ -29,6 +29,10 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" ) +var ( + GasPriceReductionRate = "0.01" // 1% of regular tx gas price for system txs +) + // MinGasPriceDecorator will check if the transaction's fee is at least as large // as the MinGasPrices param. If fee is too low, decorator returns error and tx // is rejected. This applies for both CheckTx and DeliverTx @@ -92,13 +96,16 @@ func (mpd MinGasPriceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate return next(ctx, tx, simulate) } - // Short-circuit genesis txs gentx + // Short-circuit genesis txs gentx at block 0 (there is no way to pay fee in genesis file) if len(tx.GetMsgs()) == 1 { - if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok { + if _, ok := tx.GetMsgs()[0].(*stakingtypes.MsgCreateValidator); ok && ctx.BlockHeight() == 0 { return next(ctx, tx, simulate) } } + reductionRate := sdk.MustNewDecFromStr(GasPriceReductionRate) + minGasPrice = minGasPrice.Mul(reductionRate) // discounts min gas price for system tx + evmParams := mpd.evmKeeper.GetParams(ctx) evmDenom := evmParams.GetEvmDenom() minGasPrices := sdk.DecCoins{ diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 5fe40847e9..e46f7b728e 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -19,16 +19,39 @@ package ante import ( "fmt" + observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ibcante "github.com/cosmos/ibc-go/v6/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper" ethante "github.com/evmos/ethermint/app/ante" ethermint "github.com/evmos/ethermint/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" ) -func NewLegacyCosmosAnteHandlerEip712(options ethante.HandlerOptions) sdk.AnteHandler { +type HandlerOptions struct { + AccountKeeper evmtypes.AccountKeeper + BankKeeper evmtypes.BankKeeper + IBCKeeper *ibckeeper.Keeper + FeeMarketKeeper FeeMarketKeeper + EvmKeeper EVMKeeper + FeegrantKeeper ante.FeegrantKeeper + SignModeHandler authsigning.SignModeHandler + SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error + MaxTxGasWanted uint64 + ExtensionOptionChecker ante.ExtensionOptionChecker + TxFeeChecker ante.TxFeeChecker + DisabledAuthzMsgs []string + ObserverKeeper *observerkeeper.Keeper +} + +func NewLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs NewAuthzLimiterDecorator(options.DisabledAuthzMsgs...), @@ -52,7 +75,7 @@ func NewLegacyCosmosAnteHandlerEip712(options ethante.HandlerOptions) sdk.AnteHa ) } -func newEthAnteHandler(options ethante.HandlerOptions) sdk.AnteHandler { +func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first ethante.NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices @@ -68,7 +91,7 @@ func newEthAnteHandler(options ethante.HandlerOptions) sdk.AnteHandler { ) } -func newCosmosAnteHandler(options ethante.HandlerOptions) sdk.AnteHandler { +func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs NewAuthzLimiterDecorator(options.DisabledAuthzMsgs...), @@ -92,15 +115,16 @@ func newCosmosAnteHandler(options ethante.HandlerOptions) sdk.AnteHandler { } // this applies to special cosmos tx that calls EVM, in which case the EVM overrides the gas limit -func newCosmosAnteHandlerNoGasLimit(options ethante.HandlerOptions) sdk.AnteHandler { +func newCosmosAnteHandlerForSystemTx(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs NewAuthzLimiterDecorator(options.DisabledAuthzMsgs...), NewVestingAccountDecorator(), - NewSetUpContextDecorator(), + ante.NewSetUpContextDecorator(), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), + // system txs pay less gas fee NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), diff --git a/app/app.go b/app/app.go index d78ef88643..a87abb240b 100644 --- a/app/app.go +++ b/app/app.go @@ -575,7 +575,7 @@ func New( app.SetBeginBlocker(app.BeginBlocker) maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)) - options := evmante.HandlerOptions{ + options := ante.HandlerOptions{ AccountKeeper: app.AccountKeeper, BankKeeper: app.BankKeeper, EvmKeeper: app.EvmKeeper, @@ -589,6 +589,7 @@ func New( sdk.MsgTypeURL(&vestingtypes.MsgCreatePermanentLockedAccount{}), sdk.MsgTypeURL(&vestingtypes.MsgCreatePeriodicVestingAccount{}), }, + ObserverKeeper: app.ZetaObserverKeeper, } anteHandler, err := ante.NewAnteHandler(options) diff --git a/changelog.md b/changelog.md index 832f006123..5f1d3abbce 100644 --- a/changelog.md +++ b/changelog.md @@ -12,6 +12,7 @@ * [1535](https://github.com/zeta-chain/node/issues/1535) - Avoid voting on wrong ballots due to false blockNumber in EVM tx receipt * [1588](https://github.com/zeta-chain/node/pull/1588) - fix chain params comparison logic +* [1650](https://github.com/zeta-chain/node/pull/1605) - exempt (discounted) *system txs* from min gas price check and gas fee deduction ### CI diff --git a/x/crosschain/client/integrationtests/cli_helpers.go b/x/crosschain/client/integrationtests/cli_helpers.go index 626706a627..3195782031 100644 --- a/x/crosschain/client/integrationtests/cli_helpers.go +++ b/x/crosschain/client/integrationtests/cli_helpers.go @@ -165,7 +165,9 @@ func BuildSignedGasPriceVote(t testing.TB, val *network.Validator, denom string, fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagGas, "400000"), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.5"), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fmt.Sprintf("%s%s", "10", denom)), } args := append(inboundVoterArgs, txArgs...) out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) @@ -188,7 +190,9 @@ func BuildSignedTssVote(t testing.TB, val *network.Validator, denom string, acco fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagGas, "400000"), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.5"), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fmt.Sprintf("%s%s", "10", denom)), } args := append(inboundVoterArgs, txArgs...) out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) @@ -229,7 +233,9 @@ func BuildSignedOutboundVote( fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagGas, "400000"), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.5"), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fmt.Sprintf("%s%s", "10", denom)), } args := append(outboundVoterArgs, txArgs...) out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) @@ -262,7 +268,9 @@ func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", flags.FlagGas, "4000000"), + fmt.Sprintf("--%s=%s", flags.FlagGasAdjustment, "1.5"), + fmt.Sprintf("--%s=%s", flags.FlagGasPrices, fmt.Sprintf("%s%s", "10", denom)), } args := append(inboundVoterArgs, txArgs...) out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go index 424a7e68eb..b838250745 100644 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ b/x/crosschain/client/integrationtests/inbound_voter_test.go @@ -241,10 +241,13 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { s.Require().NoError(s.network.WaitForNBlocks(2)) out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdListPendingNonces(), []string{"--output", "json"}) s.Require().NoError(err) - fmt.Println(out.String()) + //fmt.Println(out.String()) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdGetSupportedChains(), []string{"--output", "json"}) s.Require().NoError(err) - fmt.Println(out.String()) + //fmt.Println(out.String()) + out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdListGasPrice(), []string{"--output", "json"}) + s.Require().NoError(err) + //fmt.Println(out.String()) // Vote the inbound tx for _, val := range s.network.Validators { diff --git a/x/fungible/client/cli/tx_deploy_fungible_coin_zrc_4.go b/x/fungible/client/cli/tx_deploy_fungible_coin_zrc_4.go index adc638e69f..2be8037801 100644 --- a/x/fungible/client/cli/tx_deploy_fungible_coin_zrc_4.go +++ b/x/fungible/client/cli/tx_deploy_fungible_coin_zrc_4.go @@ -1,7 +1,6 @@ package cli import ( - "fmt" "strconv" "github.com/zeta-chain/zetacore/common" @@ -43,7 +42,6 @@ func CmdDeployFungibleCoinZRC4() *cobra.Command { if err != nil { return err } - fmt.Printf("CLI address: %s\n", clientCtx.GetFromAddress().String()) msg := types.NewMsgDeployFungibleCoinZRC20( clientCtx.GetFromAddress().String(), argERC20, diff --git a/x/fungible/client/cli/tx_update_zrc20_liquidity_cap.go b/x/fungible/client/cli/tx_update_zrc20_liquidity_cap.go index 4944e12d81..4c84c38527 100644 --- a/x/fungible/client/cli/tx_update_zrc20_liquidity_cap.go +++ b/x/fungible/client/cli/tx_update_zrc20_liquidity_cap.go @@ -1,8 +1,6 @@ package cli import ( - "fmt" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -23,7 +21,6 @@ func CmdUpdateZRC20LiquidityCap() *cobra.Command { if err != nil { return err } - fmt.Printf("CLI address: %s\n", clientCtx.GetFromAddress().String()) msg := types.NewMsgUpdateZRC20LiquidityCap( clientCtx.GetFromAddress().String(), args[0], diff --git a/zetaclient/broadcast.go b/zetaclient/broadcast.go index f015f2df85..8c1a86e70d 100644 --- a/zetaclient/broadcast.go +++ b/zetaclient/broadcast.go @@ -14,6 +14,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" flag "github.com/spf13/pflag" rpchttp "github.com/tendermint/tendermint/rpc/client/http" + "github.com/zeta-chain/zetacore/app/ante" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/zeta-chain/zetacore/common/cosmos" "github.com/zeta-chain/zetacore/zetaclient/hsm" @@ -41,6 +42,9 @@ func (b *ZetaCoreBridge) Broadcast(gaslimit uint64, authzWrappedMsg sdktypes.Msg if baseGasPrice == 0 { baseGasPrice = DefaultBaseGasPrice // shoudn't happen, but just in case } + reductionRate := sdktypes.MustNewDecFromStr(ante.GasPriceReductionRate) + // multiply gas price by the system tx reduction rate + adjustedBaseGasPrice := sdktypes.NewDec(baseGasPrice).Mul(reductionRate) if blockHeight > b.blockHeight { b.blockHeight = blockHeight @@ -72,7 +76,7 @@ func (b *ZetaCoreBridge) Broadcast(gaslimit uint64, authzWrappedMsg sdktypes.Msg builder.SetGasLimit(gaslimit) // #nosec G701 always in range fee := sdktypes.NewCoins(sdktypes.NewCoin(config.BaseDenom, - cosmos.NewInt(int64(gaslimit)).Mul(cosmos.NewInt(baseGasPrice)))) + cosmos.NewInt(int64(gaslimit)).Mul(adjustedBaseGasPrice.Ceil().RoundInt()))) builder.SetFeeAmount(fee) //fmt.Printf("signing from name: %s\n", ctx.GetFromName()) err = b.SignTx(factory, ctx.GetFromName(), builder, true, ctx.TxConfig)