From eaacc09b276ffd0856b10d48123e34c89cc9bdb3 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 22 Nov 2024 04:50:26 -0500 Subject: [PATCH 1/6] test: fix upgrade tests (#3196) * stop e2e test from erroring out if uniswap pair already exists * print error for pair exists revert * match pending revert for v21 dtc dust amount withdraw * remove dust withdraw from v21 previous version tests * remove dust withdraw from v21 previous version tests * add comment for v23 * adjust code format * make generate * revert skip btc dust * remove flag name * newline * lint --------- Co-authored-by: lumtis --- cmd/zetae2e/local/local.go | 6 +++++- contrib/localnet/orchestrator/start-zetae2e.sh | 3 ++- .../test_bitcoin_deposit_and_call_revert_with_dust.go | 3 +++ e2e/e2etests/test_crosschain_swap.go | 2 +- e2e/e2etests/test_v2_deposit_and_call_swap.go | 7 +++++-- e2e/e2etests/test_zrc20_swap.go | 2 +- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index a752c0e388..fa190a07a7 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -121,6 +121,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger := runner.NewLogger(verbose, color.FgWhite, "setup") testStartTime := time.Now() + logger.Print("starting E2E tests") if testAdmin { @@ -323,7 +324,6 @@ func localE2ETest(cmd *cobra.Command, _ []string) { e2etests.TestBitcoinDepositName, e2etests.TestBitcoinDepositAndCallName, e2etests.TestBitcoinDepositAndCallRevertName, - e2etests.TestBitcoinDepositAndCallRevertWithDustName, e2etests.TestBitcoinStdMemoDepositName, e2etests.TestBitcoinStdMemoDepositAndCallName, e2etests.TestBitcoinStdMemoDepositAndCallRevertName, @@ -331,6 +331,9 @@ func localE2ETest(cmd *cobra.Command, _ []string) { e2etests.TestBitcoinStdMemoInscribedDepositAndCallName, e2etests.TestCrosschainSwapName, } + bitcoinDepositTestsAdvanced := []string{ + e2etests.TestBitcoinDepositAndCallRevertWithDustName, + } bitcoinWithdrawTests := []string{ e2etests.TestBitcoinWithdrawSegWitName, e2etests.TestBitcoinWithdrawInvalidAddressName, @@ -375,6 +378,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { erc20Tests = append(erc20Tests, erc20AdvancedTests...) zetaTests = append(zetaTests, zetaAdvancedTests...) zevmMPTests = append(zevmMPTests, zevmMPAdvancedTests...) + bitcoinDepositTests = append(bitcoinDepositTests, bitcoinDepositTestsAdvanced...) bitcoinWithdrawTests = append(bitcoinWithdrawTests, bitcoinWithdrawTestsAdvanced...) ethereumTests = append(ethereumTests, ethereumAdvancedTests...) } diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index 5d8c9c5586..c9c3d26c55 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -222,7 +222,8 @@ if [ "$LOCALNET_MODE" == "upgrade" ]; then echo "running E2E command to setup the networks and populate the state..." # Use light flag to ensure tests can complete before the upgrade height - zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light --skip-precompiles ${COMMON_ARGS} + # skip-bitcoin-dust-withdraw flag can be removed after v23 is released + zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light --skip-precompiles ${COMMON_ARGS} if [ $? -ne 0 ]; then echo "first e2e failed" exit 1 diff --git a/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go b/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go index cc5f5451dc..9e3606759b 100644 --- a/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go +++ b/e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go @@ -47,7 +47,10 @@ func TestBitcoinDepositAndCallRevertWithDust(r *runner.E2ERunner, args []string) // ASSERT // Now we want to make sure the cctx is aborted with expected error message + + // cctx status would be pending revert if using v21 or before cctx := utils.WaitCctxAbortedByInboundHash(r.Ctx, r, txHash.String(), r.CctxClient) + require.True(r, cctx.GetCurrentOutboundParam().Amount.Uint64() < constant.BTCWithdrawalDustAmount) require.True(r, strings.Contains(cctx.CctxStatus.ErrorMessage, crosschaintypes.ErrInvalidWithdrawalAmount.Error())) } diff --git a/e2e/e2etests/test_crosschain_swap.go b/e2e/e2etests/test_crosschain_swap.go index 813f2d76ed..b8ec437972 100644 --- a/e2e/e2etests/test_crosschain_swap.go +++ b/e2e/e2etests/test_crosschain_swap.go @@ -25,7 +25,7 @@ func TestCrosschainSwap(r *runner.E2ERunner, _ []string) { // if the tx fails due to already initialized, it will be ignored _, err := r.UniswapV2Factory.CreatePair(r.ZEVMAuth, r.ERC20ZRC20Addr, r.BTCZRC20Addr) if err != nil { - r.Logger.Print("ℹ️ create pair error") + r.Logger.Print("ℹ️ create pair error %s", err.Error()) } txERC20ZRC20Approve, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) diff --git a/e2e/e2etests/test_v2_deposit_and_call_swap.go b/e2e/e2etests/test_v2_deposit_and_call_swap.go index ed71ed3c53..fb0aafed4b 100644 --- a/e2e/e2etests/test_v2_deposit_and_call_swap.go +++ b/e2e/e2etests/test_v2_deposit_and_call_swap.go @@ -20,8 +20,11 @@ import ( func TestV2DepositAndCallSwap(r *runner.E2ERunner, _ []string) { // create tokens pair (erc20 and eth) tx, err := r.UniswapV2Factory.CreatePair(r.ZEVMAuth, r.ERC20ZRC20Addr, r.ETHZRC20Addr) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + if err != nil { + r.Logger.Print("ℹ️ create pair error %s", err.Error()) + } else { + utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + } // approve router to spend tokens being swapped tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, big.NewInt(1e18)) diff --git a/e2e/e2etests/test_zrc20_swap.go b/e2e/e2etests/test_zrc20_swap.go index 72819aabf8..dcf1a312c2 100644 --- a/e2e/e2etests/test_zrc20_swap.go +++ b/e2e/e2etests/test_zrc20_swap.go @@ -19,7 +19,7 @@ func TestZRC20Swap(r *runner.E2ERunner, _ []string) { // if the tx fails due to already initialized, it will be ignored tx, err := r.UniswapV2Factory.CreatePair(r.ZEVMAuth, r.ERC20ZRC20Addr, r.ETHZRC20Addr) if err != nil { - r.Logger.Print("ℹ️ create pair error") + r.Logger.Print("ℹ️ create pair error %s", err.Error()) } else { utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) } From 64edb401f22a80ef11baa01185d4f31bf782cfd1 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Fri, 22 Nov 2024 04:11:47 -0600 Subject: [PATCH 2/6] fix: fix Bitcoin incorrect 'origin' in zContext caused by revertAddress option (#3192) * fix incorrect zContext origin caused by the replacement of sender address on BTC inbound revert * add changelog entry * fix unit test failure * check btc sender address in the CCTX struct --- changelog.md | 1 + ...d_deposit_and_call_revert_other_address.go | 4 ++ testutil/sample/crosschain.go | 16 +++++++ x/crosschain/types/cctx.go | 14 +++++- x/crosschain/types/cctx_test.go | 35 ++++++++++++++ x/crosschain/types/revert_options.go | 14 ++++++ x/crosschain/types/revert_options_test.go | 46 ++++++++++++++++++- zetaclient/chains/bitcoin/observer/event.go | 12 ++--- .../chains/bitcoin/observer/event_test.go | 6 ++- 9 files changed, 138 insertions(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index 6992b9a706..4e145b2114 100644 --- a/changelog.md +++ b/changelog.md @@ -35,6 +35,7 @@ * [3155](https://github.com/zeta-chain/node/pull/3155) - fix potential panic in the Bitcoin inscription parsing * [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation if transaction does not involve TSS address * [3179](https://github.com/zeta-chain/node/pull/3179) - support inbound trackers for v2 cctx +* [3192](https://github.com/zeta-chain/node/pull/3192) - fix incorrect zContext origin caused by the replacement of 'sender' with 'revertAddress' ## v21.0.0 diff --git a/e2e/e2etests/test_bitcoin_std_deposit_and_call_revert_other_address.go b/e2e/e2etests/test_bitcoin_std_deposit_and_call_revert_other_address.go index 8ecb3b0d5f..19e9893b95 100644 --- a/e2e/e2etests/test_bitcoin_std_deposit_and_call_revert_other_address.go +++ b/e2e/e2etests/test_bitcoin_std_deposit_and_call_revert_other_address.go @@ -45,6 +45,10 @@ func TestBitcoinStdMemoDepositAndCallRevertOtherAddress(r *runner.E2ERunner, arg // Now we want to make sure revert TX is completed. cctx := utils.WaitCctxRevertedByInboundHash(r.Ctx, r, txHash.String(), r.CctxClient) + // Make sure inbound sender and revert address are correct + assert.Equal(r, cctx.InboundParams.Sender, r.BTCDeployerAddress.EncodeAddress()) + assert.Equal(r, cctx.GetCurrentOutboundParam().Receiver, revertAddress) + // Check revert tx receiver address and amount receiver, value := r.QueryOutboundReceiverAndAmount(cctx.OutboundParams[1].Hash) assert.Equal(r, revertAddress, receiver) diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 25733e1fef..4ac29ec697 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -217,6 +217,22 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { } } +func CrossChainTxV2(t *testing.T, index string) *types.CrossChainTx { + r := newRandFromStringSeed(t, index) + + return &types.CrossChainTx{ + Creator: AccAddress(), + Index: GetCctxIndexFromString(index), + ZetaFees: math.NewUint(uint64(r.Int63())), + RelayedMessage: StringRandom(r, 32), + CctxStatus: Status(t, index), + InboundParams: InboundParams(r), + OutboundParams: []*types.OutboundParams{OutboundParams(r), OutboundParams(r)}, + ProtocolContractVersion: types.ProtocolContractVersion_V2, + RevertOptions: types.NewEmptyRevertOptions(), + } +} + // CustomCctxsInBlockRange create 1 cctx per block in block range [lowBlock, highBlock] (inclusive) func CustomCctxsInBlockRange( t *testing.T, diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 2b84b5f26c..b2354a79e1 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -10,6 +10,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/zeta-chain/node/pkg/chains" observertypes "github.com/zeta-chain/node/x/observer/types" ) @@ -114,10 +115,21 @@ func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) error { return fmt.Errorf("cannot revert before trying to process an outbound tx") } + // in protocol contract V1, developers can specify a revert address for Bitcoin chains + // TODO: remove this V1 logic after switching Bitcoin to V2 architecture + // https://github.com/zeta-chain/node/issues/2711 + revertReceiver := m.InboundParams.Sender + if m.ProtocolContractVersion == ProtocolContractVersion_V1 && + chains.IsBitcoinChain(m.InboundParams.SenderChainId, []chains.Chain{}) { + revertAddress, valid := m.RevertOptions.GetBTCRevertAddress(m.InboundParams.SenderChainId) + if valid { + revertReceiver = revertAddress + } + } + // in protocol contract V2, developers can specify a specific address to receive the revert // if not specified, the sender address is used // note: this option is current only support for EVM type chains - revertReceiver := m.InboundParams.Sender if m.ProtocolContractVersion == ProtocolContractVersion_V2 { revertAddress, valid := m.RevertOptions.GetEVMRevertAddress() if valid { diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index f49768f8a0..1369e2dee0 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -4,8 +4,10 @@ import ( "math/rand" "testing" + "github.com/btcsuite/btcd/chaincfg" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) @@ -134,6 +136,39 @@ func Test_SetRevertOutboundValues(t *testing.T) { require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundParams[0].TxFinalizationStatus) }) + t.Run("successfully set BTC revert address V1", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.InboundParams.SenderChainId = chains.BitcoinTestnet.ChainId + cctx.OutboundParams = cctx.OutboundParams[:1] + cctx.RevertOptions.RevertAddress = sample.BtcAddressP2WPKH(t, &chaincfg.TestNet3Params) + + err := cctx.AddRevertOutbound(100) + require.NoError(t, err) + require.Len(t, cctx.OutboundParams, 2) + require.Equal(t, cctx.GetCurrentOutboundParam().Receiver, cctx.RevertOptions.RevertAddress) + require.Equal(t, cctx.GetCurrentOutboundParam().ReceiverChainId, cctx.InboundParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutboundParam().Amount, cctx.OutboundParams[0].Amount) + require.Equal(t, cctx.GetCurrentOutboundParam().CallOptions.GasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().TssPubkey, cctx.OutboundParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundParams[0].TxFinalizationStatus) + }) + + t.Run("successfully set EVM revert address V2", func(t *testing.T) { + cctx := sample.CrossChainTxV2(t, "test") + cctx.OutboundParams = cctx.OutboundParams[:1] + cctx.RevertOptions.RevertAddress = sample.EthAddress().Hex() + + err := cctx.AddRevertOutbound(100) + require.NoError(t, err) + require.Len(t, cctx.OutboundParams, 2) + require.Equal(t, cctx.GetCurrentOutboundParam().Receiver, cctx.RevertOptions.RevertAddress) + require.Equal(t, cctx.GetCurrentOutboundParam().ReceiverChainId, cctx.InboundParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutboundParam().Amount, cctx.OutboundParams[0].Amount) + require.Equal(t, cctx.GetCurrentOutboundParam().CallOptions.GasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().TssPubkey, cctx.OutboundParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundParams[0].TxFinalizationStatus) + }) + t.Run("failed to set revert outbound values if revert outbound already exists", func(t *testing.T) { cctx := sample.CrossChainTx(t, "test") err := cctx.AddRevertOutbound(100) diff --git a/x/crosschain/types/revert_options.go b/x/crosschain/types/revert_options.go index 6cdb3040bf..4893b19ad3 100644 --- a/x/crosschain/types/revert_options.go +++ b/x/crosschain/types/revert_options.go @@ -6,6 +6,7 @@ import ( "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/crypto" ) @@ -75,6 +76,19 @@ func (r RevertOptions) GetEVMRevertAddress() (ethcommon.Address, bool) { return addr, !crypto.IsEmptyAddress(addr) } +// GetBTCRevertAddress validates and returns the BTC revert address +func (r RevertOptions) GetBTCRevertAddress(chainID int64) (string, bool) { + btcAddress, err := chains.DecodeBtcAddress(r.RevertAddress, chainID) + if err != nil { + return "", false + } + if !chains.IsBtcAddressSupported(btcAddress) { + return "", false + } + + return btcAddress.EncodeAddress(), true +} + // GetEVMAbortAddress returns the EVM abort address // if the abort address is not a valid address, it returns false func (r RevertOptions) GetEVMAbortAddress() (ethcommon.Address, bool) { diff --git a/x/crosschain/types/revert_options_test.go b/x/crosschain/types/revert_options_test.go index 46981855ea..c91927dd86 100644 --- a/x/crosschain/types/revert_options_test.go +++ b/x/crosschain/types/revert_options_test.go @@ -1,11 +1,14 @@ package types_test import ( + "testing" + + "github.com/btcsuite/btcd/chaincfg" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" - "testing" ) func TestRevertOptions_GetEVMRevertAddress(t *testing.T) { @@ -44,6 +47,47 @@ func TestRevertOptions_GetEVMRevertAddress(t *testing.T) { }) } +func TestRevertOptions_GetBTCRevertAddress(t *testing.T) { + t.Run("valid Bitcoin revert address", func(t *testing.T) { + addr := sample.BtcAddressP2WPKH(t, &chaincfg.TestNet3Params) + actualAddr, valid := types.RevertOptions{ + RevertAddress: addr, + }.GetBTCRevertAddress(chains.BitcoinTestnet.ChainId) + + require.True(t, valid) + require.Equal(t, addr, actualAddr) + }) + + t.Run("invalid Bitcoin revert address", func(t *testing.T) { + actualAddr, valid := types.RevertOptions{ + // it's a regnet address, not testnet + RevertAddress: "bcrt1qy9pqmk2pd9sv63g27jt8r657wy0d9uee4x2dt2", + }.GetBTCRevertAddress(chains.BitcoinTestnet.ChainId) + + require.False(t, valid) + require.Empty(t, actualAddr) + }) + + t.Run("empty revert address", func(t *testing.T) { + actualAddr, valid := types.RevertOptions{ + RevertAddress: "", + }.GetBTCRevertAddress(chains.BitcoinTestnet.ChainId) + + require.False(t, valid) + require.Empty(t, actualAddr) + }) + + t.Run("unsupported Bitcoin revert address", func(t *testing.T) { + actualAddr, valid := types.RevertOptions{ + // address not supported + RevertAddress: "035e4ae279bd416b5da724972c9061ec6298dac020d1e3ca3f06eae715135cdbec", + }.GetBTCRevertAddress(chains.BitcoinTestnet.ChainId) + + require.False(t, valid) + require.Empty(t, actualAddr) + }) +} + func TestRevertOptions_GetEVMAbortAddress(t *testing.T) { t.Run("valid abort address", func(t *testing.T) { addr := sample.EthAddress() diff --git a/zetaclient/chains/bitcoin/observer/event.go b/zetaclient/chains/bitcoin/observer/event.go index 69657d29f1..7cd581a1cc 100644 --- a/zetaclient/chains/bitcoin/observer/event.go +++ b/zetaclient/chains/bitcoin/observer/event.go @@ -221,11 +221,10 @@ func (ob *Observer) NewInboundVoteFromStdMemo( event *BTCInboundEvent, amountSats *big.Int, ) *crosschaintypes.MsgVoteInbound { - // replace 'sender' with 'revertAddress' if specified in the memo, so that - // zetacore will refund to the address specified by the user in the revert options. - sender := event.FromAddress - if event.MemoStd.RevertOptions.RevertAddress != "" { - sender = event.MemoStd.RevertOptions.RevertAddress + // inject the 'revertAddress' specified in the memo, so that + // zetacore will create a revert outbound that points to the custom revert address. + revertOptions := crosschaintypes.RevertOptions{ + RevertAddress: event.MemoStd.RevertOptions.RevertAddress, } // make a legacy message so that zetacore can process it as V1 @@ -234,7 +233,7 @@ func (ob *Observer) NewInboundVoteFromStdMemo( return crosschaintypes.NewMsgVoteInbound( ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), - sender, + event.FromAddress, ob.Chain().ChainId, event.FromAddress, event.ToAddress, @@ -249,5 +248,6 @@ func (ob *Observer) NewInboundVoteFromStdMemo( 0, crosschaintypes.ProtocolContractVersion_V1, false, // not relevant for v1 + crosschaintypes.WithRevertOptions(revertOptions), ) } diff --git a/zetaclient/chains/bitcoin/observer/event_test.go b/zetaclient/chains/bitcoin/observer/event_test.go index 5ed8e9b103..80566b55cd 100644 --- a/zetaclient/chains/bitcoin/observer/event_test.go +++ b/zetaclient/chains/bitcoin/observer/event_test.go @@ -423,7 +423,7 @@ func Test_NewInboundVoteFromStdMemo(t *testing.T) { // expected vote memoBytesExpected := append(event.MemoStd.Receiver.Bytes(), event.MemoStd.Payload...) expectedVote := crosschaintypes.MsgVoteInbound{ - Sender: revertOptions.RevertAddress, // should be overridden by revert address + Sender: event.FromAddress, SenderChainId: chain.ChainId, TxOrigin: event.FromAddress, Receiver: event.ToAddress, @@ -437,7 +437,9 @@ func Test_NewInboundVoteFromStdMemo(t *testing.T) { }, CoinType: coin.CoinType_Gas, ProtocolContractVersion: crosschaintypes.ProtocolContractVersion_V1, - RevertOptions: crosschaintypes.NewEmptyRevertOptions(), // ignored by V1 + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: revertOptions.RevertAddress, // should be overridden by revert address + }, } // create new inbound vote V1 with standard memo From 8998ccf0cfedc5287e51dd04489a675bbe069a8d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 22 Nov 2024 05:12:05 -0500 Subject: [PATCH 3/6] test: `e2e` add withdraw emissions (#3151) * add withdraw emissions to e2e * add changelog and minor refactors * Update e2e/runner/emissions.go Co-authored-by: Lucas Bertrand --------- Co-authored-by: Lucas Bertrand --- changelog.md | 1 + cmd/zetae2e/config/local.yml | 4 + cmd/zetae2e/config/localnet.yml | 4 + cmd/zetae2e/local/local.go | 9 +- .../localnet/orchestrator/start-zetae2e.sh | 3 + contrib/localnet/scripts/start-zetacored.sh | 58 ++++++++++++ e2e/config/config.go | 36 ++++---- e2e/runner/emissions.go | 89 +++++++++++++++++++ e2e/runner/runner.go | 3 + e2e/runner/setup_zeta.go | 7 -- e2e/txserver/zeta_tx_server.go | 23 +++++ e2e/utils/zetacore.go | 8 +- pkg/rpc/clients.go | 4 + 13 files changed, 223 insertions(+), 26 deletions(-) create mode 100644 e2e/runner/emissions.go diff --git a/changelog.md b/changelog.md index 4e145b2114..d237016e62 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ * [3105](https://github.com/zeta-chain/node/pull/3105) - split Bitcoin E2E tests into two runners for deposit and withdraw * [3154](https://github.com/zeta-chain/node/pull/3154) - configure Solana gateway program id for E2E tests * [3188](https://github.com/zeta-chain/node/pull/3188) - add e2e test for v2 deposit and call with swap +* [3151](https://github.com/zeta-chain/node/pull/3151) - add withdraw emissions to e2e tests ### Refactor diff --git a/cmd/zetae2e/config/local.yml b/cmd/zetae2e/config/local.yml index aed44fc155..15de10ceda 100644 --- a/cmd/zetae2e/config/local.yml +++ b/cmd/zetae2e/config/local.yml @@ -65,6 +65,10 @@ additional_accounts: bech32_address: "zeta1nry9yeg6njhjrp2ctppa8558vqxal9fxk69zxg" evm_address: "0x98c852651A9CAF2185585843d3D287600Ddf9526" private_key: "bf9456c679bb5a952a9a137fcfc920e0413efdb97c36de1e57455763084230cb" + user_emissions_withdraw: + bech32_address: "zeta1n9zhyn4unvaee3ey40k7x7f5nmj7zet6qr5kl7" + evm_address: "0x9945724EBc9B3B9cc724abedE379349EE5E1657a" + private_key: "9d524fe318c0eb5f80d8b246993a9f15f924db24d4b8b873839b13bc30040d03" policy_accounts: emergency_policy_account: bech32_address: "zeta16m2cnrdwtgweq4njc6t470vl325gw4kp6s7tap" diff --git a/cmd/zetae2e/config/localnet.yml b/cmd/zetae2e/config/localnet.yml index 15f1e332f6..6e1c2b392c 100644 --- a/cmd/zetae2e/config/localnet.yml +++ b/cmd/zetae2e/config/localnet.yml @@ -65,6 +65,10 @@ additional_accounts: bech32_address: "zeta1nry9yeg6njhjrp2ctppa8558vqxal9fxk69zxg" evm_address: "0x98c852651A9CAF2185585843d3D287600Ddf9526" private_key: "bf9456c679bb5a952a9a137fcfc920e0413efdb97c36de1e57455763084230cb" + user_emissions_withdraw: + bech32_address: "zeta1n9zhyn4unvaee3ey40k7x7f5nmj7zet6qr5kl7" + evm_address: "0x9945724EBc9B3B9cc724abedE379349EE5E1657a" + private_key: "9d524fe318c0eb5f80d8b246993a9f15f924db24d4b8b873839b13bc30040d03" policy_accounts: emergency_policy_account: bech32_address: "zeta16m2cnrdwtgweq4njc6t470vl325gw4kp6s7tap" diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index fa190a07a7..4c3a1f0717 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -161,11 +161,17 @@ func localE2ETest(cmd *cobra.Command, _ []string) { zetaTxServer, err := txserver.NewZetaTxServer( conf.RPCs.ZetaCoreRPC, - []string{utils.EmergencyPolicyName, utils.OperationalPolicyName, utils.AdminPolicyName}, + []string{ + utils.EmergencyPolicyName, + utils.OperationalPolicyName, + utils.AdminPolicyName, + utils.UserEmissionsWithdrawName, + }, []string{ conf.PolicyAccounts.EmergencyPolicyAccount.RawPrivateKey.String(), conf.PolicyAccounts.OperationalPolicyAccount.RawPrivateKey.String(), conf.PolicyAccounts.AdminPolicyAccount.RawPrivateKey.String(), + conf.AdditionalAccounts.UserEmissionsWithdraw.RawPrivateKey.String(), }, conf.ZetaChainID, ) @@ -492,6 +498,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger.Print("❌ e2e tests failed after %s", time.Since(testStartTime).String()) os.Exit(1) } + noError(deployerRunner.WithdrawEmissions()) // if all tests pass, cancel txs priority monitoring and check if tx priority is not correct in some blocks logger.Print("⏳ e2e tests passed, checking tx priority") diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index c9c3d26c55..99ab61d700 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -134,6 +134,9 @@ fund_eth_from_config '.additional_accounts.user_v2_ether_revert.evm_address' 100 # unlock v2 erc20 revert tests accounts fund_eth_from_config '.additional_accounts.user_v2_erc20_revert.evm_address' 10000 "V2 ERC20 revert tester" +# unlock emissions withdraw tests accounts +fund_eth_from_config '.additional_accounts.user_emissions_withdraw.evm_address' 10000 "emissions withdraw tester" + # unlock local solana relayer accounts if host solana > /dev/null; then solana_url=$(config_str '.rpcs.solana') diff --git a/contrib/localnet/scripts/start-zetacored.sh b/contrib/localnet/scripts/start-zetacored.sh index 38047a6b46..56e30358c1 100755 --- a/contrib/localnet/scripts/start-zetacored.sh +++ b/contrib/localnet/scripts/start-zetacored.sh @@ -67,6 +67,55 @@ add_v17_message_authorizations() { ' $json_file > temp.json && mv temp.json $json_file } + +add_emissions_withdraw_authorizations() { + + config_file="/root/config.yml" + json_file="/root/.zetacored/config/genesis.json" + + # Check if config file exists + if [[ ! -f "$config_file" ]]; then + echo "Error: Config file not found at $config_file" + return 1 + fi + # Address to add emissions withdraw authorizations + address=$(yq -r '.additional_accounts.user_emissions_withdraw.bech32_address' "$config_file") + + # Check if genesis file exists + if [[ ! -f "$json_file" ]]; then + echo "Error: Genesis file not found at $json_file" + return 1 + fi + + echo "Adding emissions withdraw authorizations for address: $address" + + + # Using jq to parse JSON, create new entries, and append them to the authorization array + if ! jq --arg address "$address" ' + # Store the nodeAccountList array + .app_state.observer.nodeAccountList as $list | + # Iterate over the stored list to construct new objects and append to the authorization array + .app_state.authz.authorization += [ + $list[] | + { + "granter": .operator, + "grantee": $address, + "authorization": { + "@type": "/cosmos.authz.v1beta1.GenericAuthorization", + "msg": "/zetachain.zetacore.emissions.MsgWithdrawEmission" + }, + "expiration": null + } + ] + ' "$json_file" > temp.json; then + echo "Error: Failed to update genesis file" + return 1 + fi + mv temp.json "$json_file" +} + + + # create keys CHAINID="athens_101-1" KEYRING="test" @@ -191,6 +240,12 @@ then zetacored collect-observer-info zetacored add-observer-list --keygen-block 25 + # Add emissions withdraw authorizations + if ! add_emissions_withdraw_authorizations; then + echo "Error: Failed to add emissions withdraw authorizations" + exit 1 + fi + # Check for the existence of "AddToOutTxTracker" string in the genesis file # If this message is found in the genesis, it means add-observer-list has been run with the v16 binary for upgrade tests # In this case, we need to add authorizations for the new v17 messages to the genesis file @@ -272,6 +327,9 @@ then # v2 erc20 revert tester address=$(yq -r '.additional_accounts.user_v2_erc20_revert.bech32_address' /root/config.yml) zetacored add-genesis-account "$address" 100000000000000000000000000azeta +# emissions withdraw tester + address=$(yq -r '.additional_accounts.user_emissions_withdraw.bech32_address' /root/config.yml) + zetacored add-genesis-account "$address" 100000000000000000000000000azeta # 3. Copy the genesis.json to all the nodes .And use it to create a gentx for every node zetacored gentx operator 1000000000000000000000azeta --chain-id=$CHAINID --keyring-backend=$KEYRING --gas-prices 20000000000azeta diff --git a/e2e/config/config.go b/e2e/config/config.go index 22382c1fa1..1ae7d4109a 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -61,21 +61,22 @@ type Account struct { // AdditionalAccounts are extra accounts required to run specific tests type AdditionalAccounts struct { - UserERC20 Account `yaml:"user_erc20"` - UserZetaTest Account `yaml:"user_zeta_test"` - UserZEVMMPTest Account `yaml:"user_zevm_mp_test"` - UserBitcoinDeposit Account `yaml:"user_bitcoin_deposit"` - UserBitcoinWithdraw Account `yaml:"user_bitcoin_withdraw"` - UserSolana Account `yaml:"user_solana"` - UserEther Account `yaml:"user_ether"` - UserMisc Account `yaml:"user_misc"` - UserAdmin Account `yaml:"user_admin"` - UserMigration Account `yaml:"user_migration"` // used for TSS migration, TODO: rename (https://github.com/zeta-chain/node/issues/2780) - UserPrecompile Account `yaml:"user_precompile"` - UserV2Ether Account `yaml:"user_v2_ether"` - UserV2ERC20 Account `yaml:"user_v2_erc20"` - UserV2EtherRevert Account `yaml:"user_v2_ether_revert"` - UserV2ERC20Revert Account `yaml:"user_v2_erc20_revert"` + UserERC20 Account `yaml:"user_erc20"` + UserZetaTest Account `yaml:"user_zeta_test"` + UserZEVMMPTest Account `yaml:"user_zevm_mp_test"` + UserBitcoinDeposit Account `yaml:"user_bitcoin_deposit"` + UserBitcoinWithdraw Account `yaml:"user_bitcoin_withdraw"` + UserSolana Account `yaml:"user_solana"` + UserEther Account `yaml:"user_ether"` + UserMisc Account `yaml:"user_misc"` + UserAdmin Account `yaml:"user_admin"` + UserMigration Account `yaml:"user_migration"` // used for TSS migration, TODO: rename (https://github.com/zeta-chain/node/issues/2780) + UserPrecompile Account `yaml:"user_precompile"` + UserV2Ether Account `yaml:"user_v2_ether"` + UserV2ERC20 Account `yaml:"user_v2_erc20"` + UserV2EtherRevert Account `yaml:"user_v2_ether_revert"` + UserV2ERC20Revert Account `yaml:"user_v2_erc20_revert"` + UserEmissionsWithdraw Account `yaml:"user_emissions_withdraw"` } type PolicyAccounts struct { @@ -248,6 +249,7 @@ func (a AdditionalAccounts) AsSlice() []Account { a.UserV2ERC20, a.UserV2EtherRevert, a.UserV2ERC20Revert, + a.UserEmissionsWithdraw, } } @@ -364,6 +366,10 @@ func (c *Config) GenerateKeys() error { if err != nil { return err } + c.AdditionalAccounts.UserEmissionsWithdraw, err = generateAccount() + if err != nil { + return err + } c.PolicyAccounts.EmergencyPolicyAccount, err = generateAccount() if err != nil { diff --git a/e2e/runner/emissions.go b/e2e/runner/emissions.go new file mode 100644 index 0000000000..c950cf854c --- /dev/null +++ b/e2e/runner/emissions.go @@ -0,0 +1,89 @@ +package runner + +import ( + "fmt" + + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/zeta-chain/node/cmd/zetacored/config" + "github.com/zeta-chain/node/e2e/txserver" + e2eutils "github.com/zeta-chain/node/e2e/utils" + emissionstypes "github.com/zeta-chain/node/x/emissions/types" + observertypes "github.com/zeta-chain/node/x/observer/types" +) + +// FundEmissionsPool funds the emissions pool on ZetaChain with the same value as used originally on mainnet (20M ZETA) +func (r *E2ERunner) FundEmissionsPool() error { + r.Logger.Print("⚙️ funding the emissions pool on ZetaChain with 20M ZETA (%s)", txserver.EmissionsPoolAddress) + + return r.ZetaTxServer.FundEmissionsPool(e2eutils.OperationalPolicyName, EmissionsPoolFunding) +} + +// WithdrawEmissions withdraws emissions from the emission pool on ZetaChain for all observers +// This functions uses the UserEmissionsWithdrawName to create the withdraw tx. +// UserEmissionsWithdraw can sign the authz transactions because the necessary permissions are granted in the genesis file +func (r *E2ERunner) WithdrawEmissions() error { + observerSet, err := r.ObserverClient.ObserverSet(r.Ctx, &observertypes.QueryObserverSet{}) + if err != nil { + return err + } + + for _, observer := range observerSet.Observers { + r.Logger.Print("🏃 Withdrawing emissions for observer %s", observer) + var ( + baseDenom = config.BaseDenom + queryObserverBalance = &banktypes.QueryBalanceRequest{ + Address: observer, + Denom: baseDenom, + } + ) + + balanceBefore, err := r.BankClient.Balance(r.Ctx, queryObserverBalance) + if err != nil { + return errors.Wrapf(err, "failed to get balance for observer before withdrawing emissions %s", observer) + } + + availableAmount, err := r.EmissionsClient.ShowAvailableEmissions( + r.Ctx, + &emissionstypes.QueryShowAvailableEmissionsRequest{ + Address: observer, + }, + ) + if err != nil { + return fmt.Errorf("failed to get available emissions for observer %s: %w", observer, err) + } + + availableCoin, err := sdk.ParseCoinNormalized(availableAmount.Amount) + if err != nil { + return fmt.Errorf("failed to parse coin amount: %w", err) + } + + if availableCoin.Amount.IsZero() { + r.Logger.Print("no emissions to withdraw for observer %s", observer) + continue + } + + if err := r.ZetaTxServer.WithdrawAllEmissions(availableCoin.Amount, e2eutils.UserEmissionsWithdrawName, observer); err != nil { + return err + } + + balanceAfter, err := r.BankClient.Balance(r.Ctx, queryObserverBalance) + if err != nil { + return errors.Wrapf(err, "failed to get balance for observer after withdrawing emissions %s", observer) + } + + changeInBalance := balanceAfter.Balance.Sub(*balanceBefore.Balance).Amount + if !changeInBalance.Equal(availableCoin.Amount) { + return fmt.Errorf( + "invalid balance change for observer %s, expected %s, got %s", + observer, + availableCoin.Amount, + changeInBalance, + ) + } + } + + return nil +} diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index f117758c28..9e75c6fcd7 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -45,6 +45,7 @@ import ( toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" + emissionstypes "github.com/zeta-chain/node/x/emissions/types" fungibletypes "github.com/zeta-chain/node/x/fungible/types" lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" observertypes "github.com/zeta-chain/node/x/observer/types" @@ -99,6 +100,7 @@ type E2ERunner struct { ObserverClient observertypes.QueryClient LightclientClient lightclienttypes.QueryClient DistributionClient distributiontypes.QueryClient + EmissionsClient emissionstypes.QueryClient // optional zeta (cosmos) client // typically only in test runners that need it @@ -210,6 +212,7 @@ func NewE2ERunner( ObserverClient: clients.Zetacore.Observer, LightclientClient: clients.Zetacore.Lightclient, DistributionClient: clients.Zetacore.Distribution, + EmissionsClient: clients.Zetacore.Emissions, EVMAuth: clients.EvmAuth, ZEVMAuth: clients.ZevmAuth, diff --git a/e2e/runner/setup_zeta.go b/e2e/runner/setup_zeta.go index 072957346c..56c803a376 100644 --- a/e2e/runner/setup_zeta.go +++ b/e2e/runner/setup_zeta.go @@ -276,10 +276,3 @@ func (r *E2ERunner) EnableHeaderVerification(chainIDList []int64) error { return r.ZetaTxServer.EnableHeaderVerification(e2eutils.AdminPolicyName, chainIDList) } - -// FundEmissionsPool funds the emissions pool on ZetaChain with the same value as used originally on mainnet (20M ZETA) -func (r *E2ERunner) FundEmissionsPool() error { - r.Logger.Print("⚙️ funding the emissions pool on ZetaChain with 20M ZETA (%s)", txserver.EmissionsPoolAddress) - - return r.ZetaTxServer.FundEmissionsPool(e2eutils.OperationalPolicyName, EmissionsPoolFunding) -} diff --git a/e2e/txserver/zeta_tx_server.go b/e2e/txserver/zeta_tx_server.go index 146dda4cf2..e83d6a0d71 100644 --- a/e2e/txserver/zeta_tx_server.go +++ b/e2e/txserver/zeta_tx_server.go @@ -10,6 +10,7 @@ import ( "strings" "time" + sdkmath "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" rpchttp "github.com/cometbft/cometbft/rpc/client/http" coretypes "github.com/cometbft/cometbft/rpc/core/types" @@ -585,6 +586,28 @@ func (zts ZetaTxServer) FundEmissionsPool(account string, amount *big.Int) error return err } +func (zts ZetaTxServer) WithdrawAllEmissions(withdrawAmount sdkmath.Int, account, observer string) error { + // retrieve account + acc, err := zts.clientCtx.Keyring.Key(account) + if err != nil { + return fmt.Errorf("failed to get withdrawer account: %w", err) + } + withdrawerAddress, err := acc.GetAddress() + if err != nil { + return fmt.Errorf("failed to get withdrawer account address: %w", err) + } + + msg := emissionstypes.MsgWithdrawEmission{ + Creator: observer, + Amount: withdrawAmount, + } + + authzMessage := authz.NewMsgExec(withdrawerAddress, []sdktypes.Msg{&msg}) + + _, err = zts.BroadcastTx(account, &authzMessage) + return err +} + // UpdateKeygen sets a new keygen height . The new height is the current height + 30 func (zts ZetaTxServer) UpdateKeygen(height int64) error { keygenHeight := height + 30 diff --git a/e2e/utils/zetacore.go b/e2e/utils/zetacore.go index 34e53e61b0..bf01d79ec8 100644 --- a/e2e/utils/zetacore.go +++ b/e2e/utils/zetacore.go @@ -16,9 +16,11 @@ import ( type CCTXClient = crosschaintypes.QueryClient const ( - EmergencyPolicyName = "emergency" - AdminPolicyName = "admin" - OperationalPolicyName = "operational" + EmergencyPolicyName = "emergency" + AdminPolicyName = "admin" + OperationalPolicyName = "operational" + UserEmissionsWithdrawName = "emissions_withdraw" + // The timeout was increased from 4 to 6 , which allows for a higher success in test runs // However this needs to be researched as to why the increase in timeout was needed. // https://github.com/zeta-chain/node/issues/2690 diff --git a/pkg/rpc/clients.go b/pkg/rpc/clients.go index 4d94b317e4..8ae9813b53 100644 --- a/pkg/rpc/clients.go +++ b/pkg/rpc/clients.go @@ -17,6 +17,7 @@ import ( etherminttypes "github.com/zeta-chain/node/rpc/types" authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" + emissionstypes "github.com/zeta-chain/node/x/emissions/types" fungibletypes "github.com/zeta-chain/node/x/fungible/types" lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" observertypes "github.com/zeta-chain/node/x/observer/types" @@ -51,6 +52,8 @@ type Clients struct { Observer observertypes.QueryClient // Lightclient is a github.com/zeta-chain/zetacore/x/lightclient/types QueryClient Lightclient lightclienttypes.QueryClient + // EmissionsClient is a github.com/zeta-chain/zetacore/x/emissions/types QueryClient + Emissions emissionstypes.QueryClient // Ethermint specific clients @@ -79,6 +82,7 @@ func newClients(ctx client.Context) (Clients, error) { Fungible: fungibletypes.NewQueryClient(ctx), Observer: observertypes.NewQueryClient(ctx), Lightclient: lightclienttypes.NewQueryClient(ctx), + Emissions: emissionstypes.NewQueryClient(ctx), // Ethermint specific clients Ethermint: etherminttypes.NewQueryClient(ctx), EthermintFeeMarket: feemarkettypes.NewQueryClient(ctx), From 162753f3d6399ff075a37aeff7896145e6438414 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 22 Nov 2024 13:23:51 +0100 Subject: [PATCH 4/6] docs: changelog for v23 (#3190) --- changelog.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index d237016e62..01b6f7bd66 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # CHANGELOG -## Unreleased +## v23.0.0 ### Features @@ -38,6 +38,47 @@ * [3179](https://github.com/zeta-chain/node/pull/3179) - support inbound trackers for v2 cctx * [3192](https://github.com/zeta-chain/node/pull/3192) - fix incorrect zContext origin caused by the replacement of 'sender' with 'revertAddress' +## v22.1.2 + +## Fixes + +- [3181](https://github.com/zeta-chain/node/pull/3181) - add lock around pingRTT to prevent crash + +## v22.1.1 + +## Fixes + +- [3171](https://github.com/zeta-chain/node/pull/3171) - infinite discovery address leak + +## v22.1.0 + +## Features + +- [3028](https://github.com/zeta-chain/node/pull/3028) - whitelist connection gater + +## Fixes + +- [3041](https://github.com/zeta-chain/node/pull/3041) - replace DHT with private peer discovery +- [3162](https://github.com/zeta-chain/node/pull/3162) - skip depositor fee calculation on irrelevant transactions + +## v22.0.2 + +## Fixes + +- [3144](https://github.com/zeta-chain/node/pull/3145) - out of gas on ZetaClient during `onRevert` + +## v22.0.1 + +## Fixes + +- [3140](https://github.com/zeta-chain/node/pull/3140) - allow BTC revert with dust amount + +## v22.0.0 + +## Refactor + +* [3073](https://github.com/zeta-chain/node/pull/3073) - improve ZETA deposit check with max supply check + ## v21.0.0 ### Features From e9e88dbc9d2b586bdd79b962958d441e072b3eda Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Fri, 22 Nov 2024 04:52:22 -0800 Subject: [PATCH 5/6] chore: use jsdelivr for swagger css/js (#3197) --- docs/openapi/openapi.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/openapi/openapi.html b/docs/openapi/openapi.html index 37fbfb2a16..20f878256f 100644 --- a/docs/openapi/openapi.html +++ b/docs/openapi/openapi.html @@ -5,18 +5,18 @@
- +