From d1f14307c914cfca414192f212b1b560f1cdf291 Mon Sep 17 00:00:00 2001 From: kevinssgh Date: Wed, 6 Mar 2024 13:23:56 -0500 Subject: [PATCH] added test cases and converted SetTransactionData into constructor --- zetaclient/evm/evm_signer.go | 22 +++++----- zetaclient/evm/evm_signer_test.go | 41 +++++++++--------- zetaclient/evm/outbound_transaction_data.go | 26 +++++------ .../evm/outbound_transaction_data_test.go | 43 +++++++++++++++---- .../cctx/cctx_56_68270_invalidChainID.json | 43 +++++++++++++++++++ 5 files changed, 123 insertions(+), 52 deletions(-) create mode 100644 zetaclient/testdata/cctx/cctx_56_68270_invalidChainID.json diff --git a/zetaclient/evm/evm_signer.go b/zetaclient/evm/evm_signer.go index f0dd269061..c42e04b206 100644 --- a/zetaclient/evm/evm_signer.go +++ b/zetaclient/evm/evm_signer.go @@ -307,9 +307,7 @@ func (signer *Signer) TryProcessOutTx( } // Setup Transaction input - txData := OutBoundTransactionData{} - txData.height = height - skipTx, err := txData.SetTransactionData(cctx, evmClient, signer.client, logger) + txData, skipTx, err := NewOutBoundTransactionData(cctx, evmClient, signer.client, logger, height) if err != nil { logger.Err(err).Msg("error setting up transaction input fields") return @@ -355,7 +353,7 @@ func (signer *Signer) TryProcessOutTx( // params field is used to pass input parameters for command requests, currently it is used to pass the ERC20 // contract address when a whitelist command is requested params := msg[1] - tx, err = signer.SignCommandTx(&txData, cmd, params) + tx, err = signer.SignCommandTx(txData, cmd, params) if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) return @@ -364,13 +362,13 @@ func (signer *Signer) TryProcessOutTx( switch cctx.GetCurrentOutTxParam().CoinType { case common.CoinType_Gas: logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignWithdrawTx(&txData) + tx, err = signer.SignWithdrawTx(txData) case common.CoinType_ERC20: logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignERC20WithdrawTx(&txData) + tx, err = signer.SignERC20WithdrawTx(txData) case common.CoinType_Zeta: logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignOutboundTx(&txData) + tx, err = signer.SignOutboundTx(txData) } if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) @@ -380,10 +378,10 @@ func (signer *Signer) TryProcessOutTx( switch cctx.GetCurrentOutTxParam().CoinType { case common.CoinType_Gas: logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignWithdrawTx(&txData) + tx, err = signer.SignWithdrawTx(txData) case common.CoinType_ERC20: logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignERC20WithdrawTx(&txData) + tx, err = signer.SignERC20WithdrawTx(txData) } if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) @@ -394,14 +392,14 @@ func (signer *Signer) TryProcessOutTx( txData.srcChainID = big.NewInt(cctx.OutboundTxParams[0].ReceiverChainId) txData.toChainID = big.NewInt(cctx.GetCurrentOutTxParam().ReceiverChainId) - tx, err = signer.SignRevertTx(&txData) + tx, err = signer.SignRevertTx(txData) if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) return } } else if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound { logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasPrice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, txData.gasPrice) - tx, err = signer.SignOutboundTx(&txData) + tx, err = signer.SignOutboundTx(txData) if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) return @@ -411,7 +409,7 @@ func (signer *Signer) TryProcessOutTx( logger.Info().Msgf("Key-sign success: %d => %s, nonce %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) // Broadcast Signed Tx - signer.BroadcastOutTx(tx, cctx, logger, myID, zetaBridge, &txData) + signer.BroadcastOutTx(tx, cctx, logger, myID, zetaBridge, txData) } // BroadcastOutTx signed transaction through evm rpc client diff --git a/zetaclient/evm/evm_signer_test.go b/zetaclient/evm/evm_signer_test.go index 63b850eb98..76365ef6ec 100644 --- a/zetaclient/evm/evm_signer_test.go +++ b/zetaclient/evm/evm_signer_test.go @@ -70,6 +70,12 @@ func getCCTX() (*types.CrossChainTx, error) { return &cctx, err } +func getInvalidCCTX() (*types.CrossChainTx, error) { + var cctx crosschaintypes.CrossChainTx + err := testutils.LoadObjectFromJSONFile(&cctx, path.Join("../", testutils.TestDataPathCctx, "cctx_56_68270_invalidChainID.json")) + return &cctx, err +} + func TestSigner_TryProcessOutTx(t *testing.T) { evmSigner, err := getNewEvmSigner() require.NoError(t, err) @@ -92,18 +98,18 @@ func TestSigner_SignOutboundTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} + cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) t.Run("SignOutboundTx - should successfully sign", func(t *testing.T) { // Call SignOutboundTx - tx, err := evmSigner.SignOutboundTx(&txData) + tx, err := evmSigner.SignOutboundTx(txData) require.NoError(t, err) // Verify Signature @@ -123,18 +129,17 @@ func TestSigner_SignRevertTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) t.Run("SignRevertTx - should successfully sign", func(t *testing.T) { // Call SignRevertTx - tx, err := evmSigner.SignRevertTx(&txData) + tx, err := evmSigner.SignRevertTx(txData) require.NoError(t, err) // Verify Signature @@ -154,18 +159,17 @@ func TestSigner_SignWithdrawTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) t.Run("SignWithdrawTx - should successfully sign", func(t *testing.T) { // Call SignWithdrawTx - tx, err := evmSigner.SignWithdrawTx(&txData) + tx, err := evmSigner.SignWithdrawTx(txData) require.NoError(t, err) // Verify Signature @@ -185,12 +189,11 @@ func TestSigner_SignCommandTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) @@ -198,7 +201,7 @@ func TestSigner_SignCommandTx(t *testing.T) { cmd := corecommon.CmdWhitelistERC20 params := ConnectorAddress.Hex() // Call SignCommandTx - tx, err := evmSigner.SignCommandTx(&txData, cmd, params) + tx, err := evmSigner.SignCommandTx(txData, cmd, params) require.NoError(t, err) // Verify Signature @@ -214,7 +217,7 @@ func TestSigner_SignCommandTx(t *testing.T) { t.Run("SignCommandTx CmdMigrateTssFunds", func(t *testing.T) { cmd := corecommon.CmdMigrateTssFunds // Call SignCommandTx - tx, err := evmSigner.SignCommandTx(&txData, cmd, "") + tx, err := evmSigner.SignCommandTx(txData, cmd, "") require.NoError(t, err) // Verify Signature @@ -234,18 +237,17 @@ func TestSigner_SignERC20WithdrawTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) t.Run("SignERC20WithdrawTx - should successfully sign", func(t *testing.T) { // Call SignERC20WithdrawTx - tx, err := evmSigner.SignERC20WithdrawTx(&txData) + tx, err := evmSigner.SignERC20WithdrawTx(txData) require.NoError(t, err) // Verify Signature @@ -265,21 +267,20 @@ func TestSigner_BroadcastOutTx(t *testing.T) { require.NoError(t, err) // Setup txData struct - txData := OutBoundTransactionData{} cctx, err := getCCTX() require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) + txData, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) require.False(t, skip) require.NoError(t, err) t.Run("BroadcastOutTx - should successfully broadcast", func(t *testing.T) { // Call SignERC20WithdrawTx - tx, err := evmSigner.SignERC20WithdrawTx(&txData) + tx, err := evmSigner.SignERC20WithdrawTx(txData) require.NoError(t, err) - evmSigner.BroadcastOutTx(tx, cctx, zerolog.Logger{}, sdktypes.AccAddress{}, stub.NewZetaCoreBridge(), &txData) + evmSigner.BroadcastOutTx(tx, cctx, zerolog.Logger{}, sdktypes.AccAddress{}, stub.NewZetaCoreBridge(), txData) //Check if cctx was signed and broadcasted list := evmSigner.GetReportedTxList() diff --git a/zetaclient/evm/outbound_transaction_data.go b/zetaclient/evm/outbound_transaction_data.go index 411a22100c..0b6ed97612 100644 --- a/zetaclient/evm/outbound_transaction_data.go +++ b/zetaclient/evm/outbound_transaction_data.go @@ -100,59 +100,61 @@ func (txData *OutBoundTransactionData) SetupGas( return nil } -// SetTransactionData populates transaction input fields parsed from the cctx and other parameters +// NewOutBoundTransactionData populates transaction input fields parsed from the cctx and other parameters // returns // bool (skipTx) - if the transaction doesn't qualify to be processed the function will return true, meaning that this // // cctx will be skipped and false otherwise. // // error -func (txData *OutBoundTransactionData) SetTransactionData( +func NewOutBoundTransactionData( cctx *types.CrossChainTx, evmClient *ChainClient, evmRPC interfaces.EVMRPCClient, logger zerolog.Logger, -) (bool, error) { - + height uint64, +) (*OutBoundTransactionData, bool, error) { + txData := OutBoundTransactionData{} txData.outboundParams = cctx.GetCurrentOutTxParam() txData.amount = cctx.GetCurrentOutTxParam().Amount.BigInt() txData.nonce = cctx.GetCurrentOutTxParam().OutboundTxTssNonce txData.sender = ethcommon.HexToAddress(cctx.InboundTxParams.Sender) txData.srcChainID = big.NewInt(cctx.InboundTxParams.SenderChainId) txData.asset = ethcommon.HexToAddress(cctx.InboundTxParams.Asset) + txData.height = height skipTx := txData.SetChainAndSender(cctx, logger) if skipTx { - return true, nil + return nil, true, nil } toChain := common.GetChainFromChainID(txData.toChainID.Int64()) if toChain == nil { - return true, fmt.Errorf("unknown chain: %d", txData.toChainID.Int64()) + return nil, true, fmt.Errorf("unknown chain: %d", txData.toChainID.Int64()) } // Get nonce, Early return if the cctx is already processed nonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce included, confirmed, err := evmClient.IsSendOutTxProcessed(cctx, logger) if err != nil { - return true, errors.New("IsSendOutTxProcessed failed") + return nil, true, errors.New("IsSendOutTxProcessed failed") } if included || confirmed { logger.Info().Msgf("CCTX already processed; exit signer") - return true, nil + return nil, true, nil } // Set up gas limit and gas price err = txData.SetupGas(cctx, logger, evmRPC, toChain) if err != nil { - return true, err + return nil, true, err } // Get sendHash logger.Info().Msgf("chain %s minting %d to %s, nonce %d, finalized zeta bn %d", toChain, cctx.InboundTxParams.Amount, txData.to.Hex(), nonce, cctx.InboundTxParams.InboundTxFinalizedZetaHeight) sendHash, err := hex.DecodeString(cctx.Index[2:]) // remove the leading 0x if err != nil || len(sendHash) != 32 { - return true, fmt.Errorf("decode CCTX %s error", cctx.Index) + return nil, true, fmt.Errorf("decode CCTX %s error", cctx.Index) } copy(txData.sendHash[:32], sendHash[:32]) @@ -163,7 +165,7 @@ func (txData *OutBoundTransactionData) SetTransactionData( logger.Info().Msgf("replace pending outTx %s nonce %d using gas price %d", pendingTx.Hash().Hex(), nonce, txData.gasPrice) } else { logger.Info().Msgf("please wait for pending outTx %s nonce %d to be included", pendingTx.Hash().Hex(), nonce) - return true, nil + return nil, true, nil } } @@ -175,5 +177,5 @@ func (txData *OutBoundTransactionData) SetTransactionData( } } - return false, nil + return &txData, false, nil } diff --git a/zetaclient/evm/outbound_transaction_data_test.go b/zetaclient/evm/outbound_transaction_data_test.go index 92f0f961a1..cc5de0489b 100644 --- a/zetaclient/evm/outbound_transaction_data_test.go +++ b/zetaclient/evm/outbound_transaction_data_test.go @@ -68,18 +68,45 @@ func TestSigner_SetupGas(t *testing.T) { }) } -func TestSigner_SetTransactionData(t *testing.T) { +func TestSigner_NewOutBoundTransactionData(t *testing.T) { // Setup evm signer evmSigner, err := getNewEvmSigner() require.NoError(t, err) - // Setup txData struct - txData := OutBoundTransactionData{} - cctx, err := getCCTX() - require.NoError(t, err) mockChainClient, err := getNewEvmChainClient() require.NoError(t, err) - skip, err := txData.SetTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}) - require.False(t, skip) - require.NoError(t, err) + + t.Run("NewOutBoundTransactionData success", func(t *testing.T) { + cctx, err := getCCTX() + require.NoError(t, err) + _, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) + require.False(t, skip) + require.NoError(t, err) + }) + + t.Run("NewOutBoundTransactionData skip", func(t *testing.T) { + cctx, err := getCCTX() + require.NoError(t, err) + cctx.CctxStatus.Status = types.CctxStatus_Aborted + _, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) + require.NoError(t, err) + require.True(t, skip) + }) + + t.Run("NewOutBoundTransactionData unknown chain", func(t *testing.T) { + cctx, err := getInvalidCCTX() + require.NoError(t, err) + _, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) + require.ErrorContains(t, err, "unknown chain") + require.True(t, skip) + }) + + t.Run("NewOutBoundTransactionData setup gas error", func(t *testing.T) { + cctx, err := getCCTX() + require.NoError(t, err) + cctx.GetCurrentOutTxParam().OutboundTxGasPrice = "invalidGasPrice" + _, skip, err := NewOutBoundTransactionData(cctx, mockChainClient, evmSigner.EvmClient(), zerolog.Logger{}, 123) + require.True(t, skip) + require.ErrorContains(t, err, "cannot convert gas price") + }) } diff --git a/zetaclient/testdata/cctx/cctx_56_68270_invalidChainID.json b/zetaclient/testdata/cctx/cctx_56_68270_invalidChainID.json new file mode 100644 index 0000000000..2e4cc4d97a --- /dev/null +++ b/zetaclient/testdata/cctx/cctx_56_68270_invalidChainID.json @@ -0,0 +1,43 @@ +{ + "creator": "", + "index": "0x541b570182950809f9b9077861a0fc7038af9a14ce8af4e151a83adfa308c7a9", + "zeta_fees": "0", + "relayed_message": "", + "cctx_status": { + "status": 1, + "status_message": "", + "lastUpdate_timestamp": 1709145057 + }, + "inbound_tx_params": { + "sender": "0xd91b507F2A3e2D4A32d0C86Ac19FEAD2D461008D", + "sender_chain_id": 7000, + "tx_origin": "0xb0C04e07A301927672A8A7a874DB6930576C90B8", + "coin_type": 1, + "asset": "", + "amount": "657177295293237048", + "inbound_tx_observed_hash": "0x093f4ca4c1884df0fd9dd59b75979342ded29d3c9b6861644287a2e1417b9a39", + "inbound_tx_observed_external_height": 1960153, + "inbound_tx_ballot_index": "0x541b570182950809f9b9077861a0fc7038af9a14ce8af4e151a83adfa308c7a9", + "inbound_tx_finalized_zeta_height": 0, + "tx_finalization_status": 0 + }, + "outbound_tx_params": [ + { + "receiver": "0xb0C04e07A301927672A8A7a874DB6930576C90B8", + "receiver_chainId": 13378337, + "coin_type": 1, + "amount": "657177295293237048", + "outbound_tx_tss_nonce": 68270, + "outbound_tx_gas_limit": 21000, + "outbound_tx_gas_price": "6000000000", + "outbound_tx_hash": "", + "outbound_tx_ballot_index": "", + "outbound_tx_observed_external_height": 0, + "outbound_tx_gas_used": 0, + "outbound_tx_effective_gas_price": "0", + "outbound_tx_effective_gas_limit": 0, + "tss_pubkey": "zetapub1addwnpepqtadxdyt037h86z60nl98t6zk56mw5zpnm79tsmvspln3hgt5phdc79kvfc", + "tx_finalization_status": 0 + } + ] +}