From 466b3b8bb0eca8af60ee63a110d74ec0ebe9d1c9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 5 Mar 2024 18:14:31 -0500 Subject: [PATCH 01/36] refactor inbound vote --- proto/crosschain/cross_chain_tx.proto | 1 + testutil/keeper/authority.go | 11 + x/crosschain/keeper/cctx.go | 57 ----- x/crosschain/keeper/cctx_utils.go | 196 ++++++++++++++++- x/crosschain/keeper/cctx_utils_test.go | 16 +- x/crosschain/keeper/evm_deposit.go | 33 ++- x/crosschain/keeper/evm_deposit_test.go | 198 +++++++++--------- x/crosschain/keeper/evm_hooks_test.go | 27 ++- .../keeper/msg_server_vote_inbound_tx.go | 121 +---------- .../keeper/msg_server_vote_outbound_tx.go | 2 +- x/crosschain/types/cross_chain_tx.pb.go | 174 +++++++++------ 11 files changed, 450 insertions(+), 386 deletions(-) diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 28aeab85db..47495d1a5a 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -92,4 +92,5 @@ message CrossChainTx { Status cctx_status = 8; InboundTxParams inbound_tx_params = 9; repeated OutboundTxParams outbound_tx_params = 10; + uint64 event_index = 11; } diff --git a/testutil/keeper/authority.go b/testutil/keeper/authority.go index 2c599e66a3..534f8b8dee 100644 --- a/testutil/keeper/authority.go +++ b/testutil/keeper/authority.go @@ -77,3 +77,14 @@ func AuthorityKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { func MockIsAuthorized(m *mock.Mock, address string, policyType types.PolicyType, isAuthorized bool) { m.On("IsAuthorized", mock.Anything, address, policyType).Return(isAuthorized).Once() } + +func SetAdminPolices(ctx sdk.Context, ak *keeper.Keeper) string { + admin := sample.AccAddress() + ak.SetPolicies(ctx, types.Policies{Items: []*types.Policy{ + { + Address: admin, + PolicyType: types.PolicyType_groupAdmin, + }, + }}) + return admin +} diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index d6fb9b117b..eff106d56f 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -3,7 +3,6 @@ package keeper import ( "fmt" - "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" @@ -98,59 +97,3 @@ func (k Keeper) RemoveCrossChainTx(ctx sdk.Context, index string) { store := prefix.NewStore(ctx.KVStore(k.storeKey), p) store.Delete(types.KeyPrefix(index)) } - -func (k Keeper) CreateNewCCTX( - ctx sdk.Context, - msg *types.MsgVoteOnObservedInboundTx, - index string, - tssPubkey string, - s types.CctxStatus, - senderChainID, - receiverChainID int64, -) types.CrossChainTx { - if msg.TxOrigin == "" { - msg.TxOrigin = msg.Sender - } - inboundParams := &types.InboundTxParams{ - Sender: msg.Sender, - SenderChainId: senderChainID, - TxOrigin: msg.TxOrigin, - Asset: msg.Asset, - Amount: msg.Amount, - CoinType: msg.CoinType, - InboundTxObservedHash: msg.InTxHash, - InboundTxObservedExternalHeight: msg.InBlockHeight, - InboundTxFinalizedZetaHeight: 0, - InboundTxBallotIndex: index, - } - - outBoundParams := &types.OutboundTxParams{ - Receiver: msg.Receiver, - ReceiverChainId: receiverChainID, - OutboundTxHash: "", - OutboundTxTssNonce: 0, - OutboundTxGasLimit: msg.GasLimit, - OutboundTxGasPrice: "", - OutboundTxBallotIndex: "", - OutboundTxObservedExternalHeight: 0, - CoinType: msg.CoinType, // FIXME: is this correct? - Amount: sdk.NewUint(0), - TssPubkey: tssPubkey, - } - status := &types.Status{ - Status: s, - StatusMessage: "", - LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), - IsAbortRefunded: false, - } - newCctx := types.CrossChainTx{ - Creator: msg.Creator, - Index: index, - ZetaFees: math.ZeroUint(), - RelayedMessage: msg.Message, - CctxStatus: status, - InboundTxParams: inboundParams, - OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, - } - return newCctx -} diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 8c2edd5013..e0ed1a7f71 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -15,6 +15,74 @@ import ( zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) +func (k Keeper) GetInbound(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx) types.CrossChainTx { + + // get the latest TSS to set the TSS public key in the CCTX + tssPub := "" + tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) + if tssFound { + tssPub = tss.TssPubkey + } + return k.CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) +} + +func (k Keeper) CreateNewCCTX( + ctx sdk.Context, + msg *types.MsgVoteOnObservedInboundTx, + index string, + tssPubkey string, + s types.CctxStatus, + senderChainID, + receiverChainID int64, +) types.CrossChainTx { + if msg.TxOrigin == "" { + msg.TxOrigin = msg.Sender + } + inboundParams := &types.InboundTxParams{ + Sender: msg.Sender, + SenderChainId: senderChainID, + TxOrigin: msg.TxOrigin, + Asset: msg.Asset, + Amount: msg.Amount, + CoinType: msg.CoinType, + InboundTxObservedHash: msg.InTxHash, + InboundTxObservedExternalHeight: msg.InBlockHeight, + InboundTxFinalizedZetaHeight: 0, + InboundTxBallotIndex: index, + } + + outBoundParams := &types.OutboundTxParams{ + Receiver: msg.Receiver, + ReceiverChainId: receiverChainID, + OutboundTxHash: "", + OutboundTxTssNonce: 0, + OutboundTxGasLimit: msg.GasLimit, + OutboundTxGasPrice: "", + OutboundTxBallotIndex: "", + OutboundTxObservedExternalHeight: 0, + CoinType: msg.CoinType, // FIXME: is this correct? + Amount: sdk.NewUint(0), + TssPubkey: tssPubkey, + } + status := &types.Status{ + Status: s, + StatusMessage: "", + LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), + IsAbortRefunded: false, + } + newCctx := types.CrossChainTx{ + Creator: msg.Creator, + Index: index, + ZetaFees: sdkmath.ZeroUint(), + RelayedMessage: msg.Message, + CctxStatus: status, + InboundTxParams: inboundParams, + OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, + EventIndex: msg.EventIndex, + } + return newCctx +} + // UpdateNonce sets the CCTX outbound nonce to the next nonce, and updates the nonce of blockchain state. // It also updates the PendingNonces that is used to track the unfulfilled outbound txs. func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error { @@ -54,7 +122,7 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C // GetRevertGasLimit returns the gas limit for the revert transaction in a CCTX // It returns 0 if there is no error but the gas limit can't be determined from the CCTX data -func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx types.CrossChainTx) (uint64, error) { +func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (uint64, error) { if cctx.InboundTxParams == nil { return 0, nil } @@ -105,3 +173,129 @@ func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { return sdkmath.ZeroUint() } + +// ProcessInbound processes the inbound CCTX. +// It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. +func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { + if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { + k.ProcessZEVMDeposit(ctx, cctx) + } else { + k.ProcessCrosschainMsgPassing(ctx, cctx) + } +} + +// ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain. +// If the deposit is successful, the CCTX status is changed to OutboundMined. +// If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. +// If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. +// If the creation of revert tx also fails it changes the status to Aborted. +// Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. +// We do not return an error from this function , as all changes need to be persisted to the state. +// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. +func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) + + if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + return + } else if err != nil && isContractReverted { // contract call reverted; should refund + revertMessage := err.Error() + chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) + if chain == nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") + return + } + + gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + if err != nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "can't get revert tx gas limit"+err.Error()) + return + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit + } + + // create new OutboundTxParams for the revert + revertTxParams := &types.OutboundTxParams{ + Receiver: cctx.InboundTxParams.Sender, + ReceiverChainId: cctx.InboundTxParams.SenderChainId, + Amount: cctx.InboundTxParams.Amount, + CoinType: cctx.InboundTxParams.CoinType, + OutboundTxGasLimit: gasLimit, + } + cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) + + // we create a new cached context, and we don't commit the previous one with EVM deposit + tmpCtx, commit := ctx.CacheContext() + err = func() error { + err := k.PayGasAndUpdateCctx( + tmpCtx, + chain.ChainId, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + return k.UpdateNonce(tmpCtx, chain.ChainId, cctx) + }() + if err != nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) + return + } + commit() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) + return + } + // successful HandleEVMDeposit; + commit() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "Remote omnichain contract call completed") + return +} + +// ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain. +// If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. +// If the crosschain message passing returns an error, the CCTX status is changed to Aborted. +// We do not return an error from this function , as all changes need to be persisted to the state. +// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. +func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId + err := func() error { + err := k.PayGasAndUpdateCctx( + tmpCtx, + outboundReceiverChainID, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + return k.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx) + }() + if err != nil { + // do not commit anything here as the CCTX should be aborted + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + return + } + commit() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingOutbound, "") + return +} + +func (k Keeper) SaveInbound(ctx sdk.Context, cctx *types.CrossChainTx) { + EmitEventInboundFinalized(ctx, cctx) + k.AddFinalizedInbound(ctx, + cctx.GetInboundTxParams().InboundTxObservedHash, + cctx.GetInboundTxParams().SenderChainId, + cctx.EventIndex) + // #nosec G701 always positive + cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) + cctx.InboundTxParams.TxFinalizationStatus = types.TxFinalizationStatus_Executed + k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) + k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) +} diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 319ef35a54..36297d5e31 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -18,7 +18,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if no inbound tx params", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{}) + gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{}) require.NoError(t, err) require.Equal(t, uint64(0), gasLimit) }) @@ -26,7 +26,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if coin type is not gas or erc20", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Zeta, }}) @@ -45,7 +45,7 @@ func TestGetRevertGasLimit(t *testing.T) { _, err := zk.FungibleKeeper.UpdateZRC20GasLimit(ctx, gas, big.NewInt(42)) require.NoError(t, err) - gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Gas, SenderChainId: chainID, @@ -75,7 +75,7 @@ func TestGetRevertGasLimit(t *testing.T) { _, err := zk.FungibleKeeper.UpdateZRC20GasLimit(ctx, zrc20Addr, big.NewInt(42)) require.NoError(t, err) - gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: chainID, @@ -88,7 +88,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should fail if no gas coin found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Gas, SenderChainId: 999999, @@ -109,7 +109,7 @@ func TestGetRevertGasLimit(t *testing.T) { }) // no contract deployed therefore will fail - _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Gas, SenderChainId: chainID, @@ -120,7 +120,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should fail if no asset found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: 999999, @@ -143,7 +143,7 @@ func TestGetRevertGasLimit(t *testing.T) { }) // no contract deployed therefore will fail - _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_ERC20, SenderChainId: chainID, diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index c3392e005e..8fbd16ae35 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -18,14 +18,13 @@ import ( // HandleEVMDeposit handles a deposit from an inbound tx // returns (isContractReverted, err) // (true, non-nil) means CallEVM() reverted -func (k Keeper) HandleEVMDeposit( - ctx sdk.Context, - cctx *types.CrossChainTx, - msg types.MsgVoteOnObservedInboundTx, - senderChainID int64, -) (bool, error) { - to := ethcommon.HexToAddress(msg.Receiver) +func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (bool, error) { + to := ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver) var ethTxHash ethcommon.Hash + inboundAmount := cctx.GetInboundTxParams().Amount.BigInt() + inboundSender := cctx.GetInboundTxParams().Sender + inboundSenderChainID := cctx.GetInboundTxParams().SenderChainId + inboundCoinType := cctx.GetInboundTxParams().CoinType if len(ctx.TxBytes()) > 0 { // add event for tendermint transaction hash format hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) @@ -35,15 +34,15 @@ func (k Keeper) HandleEVMDeposit( cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = uint64(ctx.BlockHeight()) } - if msg.CoinType == common.CoinType_Zeta { + if inboundCoinType == common.CoinType_Zeta { // if coin type is Zeta, this is a deposit ZETA to zEVM cctx. - err := k.fungibleKeeper.DepositCoinZeta(ctx, to, msg.Amount.BigInt()) + err := k.fungibleKeeper.DepositCoinZeta(ctx, to, inboundAmount) if err != nil { return false, err } } else { // cointype is Gas or ERC20; then it could be a ZRC20 deposit/depositAndCall cctx. - parsedAddress, data, err := common.ParseAddressAndData(msg.Message) + parsedAddress, data, err := common.ParseAddressAndData(cctx.RelayedMessage) if err != nil { return false, errors.Wrap(types.ErrUnableToParseAddress, err.Error()) } @@ -51,7 +50,7 @@ func (k Keeper) HandleEVMDeposit( to = parsedAddress } - from, err := common.DecodeAddressFromChainID(senderChainID, msg.Sender) + from, err := common.DecodeAddressFromChainID(inboundSenderChainID, inboundSender) if err != nil { return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %s", err.Error()) } @@ -60,11 +59,11 @@ func (k Keeper) HandleEVMDeposit( ctx, from, to, - msg.Amount.BigInt(), - senderChainID, + inboundAmount, + inboundSenderChainID, data, - msg.CoinType, - msg.Asset, + inboundCoinType, + cctx.InboundTxParams.Asset, ) if fungibletypes.IsContractReverted(evmTxResponse, err) || errShouldRevertCctx(err) { return true, err @@ -78,9 +77,9 @@ func (k Keeper) HandleEVMDeposit( logs := evmtypes.LogsToEthereum(evmTxResponse.Logs) if len(logs) > 0 { ctx = ctx.WithValue("inCctxIndex", cctx.Index) - txOrigin := msg.TxOrigin + txOrigin := cctx.InboundTxParams.TxOrigin if txOrigin == "" { - txOrigin = msg.Sender + txOrigin = inboundSender } err = k.ProcessLogs(ctx, logs, to, txOrigin) diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index dd6528e639..406ba600de 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -31,15 +31,14 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { fungibleMock.On("DepositCoinZeta", ctx, receiver, amount).Return(nil) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_Zeta, - }, - 0, + cctx, ) require.NoError(t, err) require.False(t, reverted) @@ -60,15 +59,15 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { fungibleMock.On("DepositCoinZeta", ctx, receiver, amount).Return(errDeposit) // call HandleEVMDeposit + + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_Zeta, - }, - 0, + cctx, ) require.ErrorIs(t, err, errDeposit) require.False(t, reverted) @@ -101,18 +100,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.NoError(t, err) require.False(t, reverted) @@ -146,18 +144,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{}, false, errDeposit) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, errDeposit) require.False(t, reverted) @@ -191,18 +188,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, errDeposit) require.True(t, reverted) @@ -235,18 +231,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrForeignCoinCapReached) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, fungibletypes.ErrForeignCoinCapReached) require.True(t, reverted) @@ -279,18 +274,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrPausedZRC20) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, fungibletypes.ErrPausedZRC20) require.True(t, reverted) @@ -321,18 +315,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrCallNonContract) // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, fungibletypes.ErrCallNonContract) require.True(t, reverted) @@ -345,18 +338,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { }) senderChain := getValidEthChainID(t) + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() + cctx.GetInboundTxParams().Amount = math.NewUint(42) + cctx.GetInboundTxParams().CoinType = common.CoinType_Gas + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "not_hex" + cctx.GetInboundTxParams().Asset = "" _, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: sample.EthAddress().String(), - Amount: math.NewUint(42), - CoinType: common.CoinType_Gas, - Message: "not_hex", - Asset: "", - }, - senderChain, + cctx, ) require.ErrorIs(t, err, types.ErrUnableToParseAddress) }) @@ -386,18 +378,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = receiver.Hex()[2:] + "DEADBEEF" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: sample.EthAddress().String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: receiver.Hex()[2:] + "DEADBEEF", - Asset: "", - }, - senderChain, + cctx, ) require.NoError(t, err) require.False(t, reverted) @@ -429,18 +420,17 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) + cctx := sample.CrossChainTx(t, "foo") + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetInboundTxParams().SenderChainId = senderChain + cctx.RelayedMessage = "DEADBEEF" + cctx.GetInboundTxParams().Asset = "" reverted, err := k.HandleEVMDeposit( ctx, - sample.CrossChainTx(t, "foo"), - types.MsgVoteOnObservedInboundTx{ - Sender: sample.EthAddress().String(), - Receiver: receiver.String(), - Amount: math.NewUintFromBigInt(amount), - CoinType: common.CoinType_ERC20, - Message: "DEADBEEF", - Asset: "", - }, - senderChain, + cctx, ) require.NoError(t, err) require.False(t, reverted) diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index d58a4d314d..583e28a364 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -23,9 +23,7 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) -func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosschainkeeper.Keeper, zk keepertest.ZetaKeepers, sdkk keepertest.SDKKeepers, chain common.Chain) { - admin := sample.AccAddress() - setAdminPolicies(ctx, zk, admin) +func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosschainkeeper.Keeper, zk keepertest.ZetaKeepers, sdkk keepertest.SDKKeepers, chain common.Chain, admin string) { assetAddress := sample.EthAddress().String() gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chain.ChainId, "ethereum", "ETH") @@ -42,7 +40,7 @@ func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosscha fungibleMsgServer := fungiblekeeper.NewMsgServerImpl(*zk.FungibleKeeper) _, err := fungibleMsgServer.UpdateZRC20WithdrawFee( sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(withdrawFee), sdkmath.Uint{}), + fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(uint64(withdrawFee)), sdkmath.Uint{}), ) require.NoError(t, err) k.SetGasPrice(ctx, crosschaintypes.GasPrice{ @@ -433,14 +431,16 @@ func TestKeeper_ParseZetaSentEvent(t *testing.T) { func TestKeeper_ProcessZetaSentEvent(t *testing.T) { t.Run("successfully process ZetaSentEvent", func(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) - k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) chain := common.EthChain() chainID := chain.ChainId setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) + amount, ok := sdkmath.NewIntFromString("20000000000000000000000") require.True(t, ok) err := sdkk.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sdk.NewCoins(sdk.NewCoin(config.BaseDenom, amount))) @@ -470,7 +470,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { chainID := chain.ChainId setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) event, err := crosschainkeeper.ParseZetaSentEvent(*sample.GetValidZetaSentDestinationExternal(t).Logs[4], sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address) require.NoError(t, err) @@ -488,7 +489,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { chain := common.EthChain() SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) amount, ok := sdkmath.NewIntFromString("20000000000000000000000") require.True(t, ok) @@ -512,7 +514,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { chainID := chain.ChainId setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) amount, ok := sdkmath.NewIntFromString("20000000000000000000000") require.True(t, ok) @@ -561,7 +564,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) zk.ObserverKeeper.SetChainNonces(ctx, observertypes.ChainNonces{ Index: chain.ChainName.String(), @@ -618,7 +622,8 @@ func TestKeeper_ProcessLogs(t *testing.T) { chainID := chain.ChainId setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain) + admin := keepertest.SetAdminPolices(ctx, zk.AuthorityKeeper) + SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) amount, ok := sdkmath.NewIntFromString("20000000000000000000000") require.True(t, ok) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index db287e6b82..c515d541f0 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -6,7 +6,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -85,127 +84,13 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg } } commit() - // If the ballot is not finalized return nil here to add vote to commit state if !finalized { return &types.MsgVoteOnObservedInboundTxResponse{}, nil } - // get the latest TSS to set the TSS public key in the CCTX - tssPub := "" - tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) - if tssFound { - tssPub = tss.TssPubkey - } - - // create the CCTX - cctx := k.CreateNewCCTX( - ctx, - msg, - index, - tssPub, - types.CctxStatus_PendingInbound, - msg.SenderChainId, - msg.ReceiverChain, - ) - - defer func() { - EmitEventInboundFinalized(ctx, &cctx) - k.AddFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) - // #nosec G701 always positive - cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) - cctx.InboundTxParams.TxFinalizationStatus = types.TxFinalizationStatus_Executed - k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) - k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) - }() - - // FinalizeInbound updates CCTX Prices and Nonce - // Aborts is any of the updates fail - if common.IsZetaChain(msg.ReceiverChain) { - tmpCtx, commit := ctx.CacheContext() - isContractReverted, err := k.HandleEVMDeposit(tmpCtx, &cctx, *msg, msg.SenderChainId) - - if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } else if err != nil && isContractReverted { // contract call reverted; should refund - revertMessage := err.Error() - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) - if chain == nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) - if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "can't get revert tx gas limit"+err.Error()) - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = msg.GasLimit - } - - // create new OutboundTxParams for the revert - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - CoinType: cctx.InboundTxParams.CoinType, - OutboundTxGasLimit: gasLimit, - } - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) - - // we create a new cached context, and we don't commit the previous one with EVM deposit - tmpCtx, commit := ctx.CacheContext() - err = func() error { - err := k.PayGasAndUpdateCctx( - tmpCtx, - chain.ChainId, - &cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - return k.UpdateNonce(tmpCtx, chain.ChainId, &cctx) - }() - if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - // successful HandleEVMDeposit; - commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "Remote omnichain contract call completed") - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - - // Receiver is not ZetaChain: Cross Chain SWAP - tmpCtx, commit = ctx.CacheContext() - err = func() error { - err := k.PayGasAndUpdateCctx( - tmpCtx, - msg.ReceiverChain, - &cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - return k.UpdateNonce(tmpCtx, msg.ReceiverChain, &cctx) - }() - if err != nil { - // do not commit anything here as the CCTX should be aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) - return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } - commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingOutbound, "") + inboundCctx := k.GetInbound(ctx, msg) + k.ProcessInbound(ctx, &inboundCctx) + k.SaveInbound(ctx, &inboundCctx) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 5c36a2abf9..870d1e08c5 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -149,7 +149,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms switch oldStatus { case types.CctxStatus_PendingOutbound: - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + gasLimit, err := k.GetRevertGasLimit(ctx, &cctx) if err != nil { return errors.New("can't get revert tx gas limit" + err.Error()) } diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 94f34e6e46..dd539f0f25 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -466,6 +466,7 @@ type CrossChainTx struct { CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` InboundTxParams *InboundTxParams `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` OutboundTxParams []*OutboundTxParams `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` + EventIndex uint64 `protobuf:"varint,11,opt,name=event_index,json=eventIndex,proto3" json:"event_index,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -543,6 +544,13 @@ func (m *CrossChainTx) GetOutboundTxParams() []*OutboundTxParams { return nil } +func (m *CrossChainTx) GetEventIndex() uint64 { + if m != nil { + return m.EventIndex + } + return 0 +} + func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) @@ -556,77 +564,78 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1120 bytes of a gzipped FileDescriptorProto + // 1135 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, - 0x12, 0x25, 0x80, 0x25, 0xd8, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0xb5, 0x13, 0x23, 0x89, 0x6d, 0x6c, - 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0xd2, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, - 0x10, 0x3d, 0xf4, 0x11, 0x7a, 0xe8, 0xa3, 0xe4, 0x50, 0xa0, 0x39, 0x16, 0x3d, 0x18, 0x85, 0x7d, - 0xee, 0xa5, 0x4f, 0x50, 0xf0, 0x67, 0x57, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, - 0x9b, 0x21, 0xe7, 0x1b, 0x72, 0xa1, 0xe6, 0x47, 0x8c, 0x73, 0xbf, 0x87, 0x69, 0xd8, 0x56, 0xa6, - 0xa7, 0x6c, 0x4f, 0x8c, 0x5b, 0xc3, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, 0x4b, - 0x59, 0x2c, 0x22, 0xad, 0x09, 0x66, 0x79, 0xd1, 0x67, 0x83, 0x01, 0x0b, 0xdb, 0xfa, 0xa3, 0x31, - 0xcb, 0x95, 0x2e, 0xeb, 0x32, 0x65, 0xb6, 0xa5, 0xa5, 0xbd, 0x8d, 0xdf, 0x73, 0x50, 0xde, 0x09, - 0x3b, 0x6c, 0x14, 0x06, 0x07, 0xe3, 0x7d, 0x1c, 0xe1, 0x01, 0x47, 0xf7, 0x20, 0xcf, 0x49, 0x18, - 0x90, 0xc8, 0xb1, 0xea, 0x56, 0xb3, 0xe8, 0x9a, 0x11, 0x7a, 0x04, 0x65, 0x6d, 0x99, 0x74, 0x68, - 0xe0, 0xdc, 0xa9, 0x5b, 0xcd, 0xac, 0x3b, 0xa7, 0xdd, 0x9b, 0xd2, 0xbb, 0x13, 0xa0, 0xfb, 0x50, - 0x14, 0x63, 0x8f, 0x45, 0xb4, 0x4b, 0x43, 0x27, 0xab, 0x28, 0x0a, 0x62, 0xbc, 0xa7, 0xc6, 0x68, - 0x05, 0x8a, 0x3e, 0x93, 0x7b, 0x39, 0x1d, 0x12, 0x27, 0x57, 0xb7, 0x9a, 0xf3, 0x6b, 0x76, 0xcb, - 0x24, 0xba, 0xc9, 0x68, 0x78, 0x70, 0x3a, 0x24, 0x6e, 0xc1, 0x37, 0x16, 0xaa, 0xc0, 0x5d, 0xcc, - 0x39, 0x11, 0xce, 0x5d, 0xc5, 0xa3, 0x07, 0xe8, 0x05, 0xe4, 0xf1, 0x80, 0x8d, 0x42, 0xe1, 0xe4, - 0xa5, 0x7b, 0xa3, 0xfd, 0xfe, 0xac, 0x96, 0xf9, 0xf5, 0xac, 0xf6, 0xb8, 0x4b, 0x45, 0x6f, 0xd4, - 0x91, 0x7c, 0x6d, 0x9f, 0xf1, 0x01, 0xe3, 0xe6, 0xb3, 0xc2, 0x83, 0xb7, 0x6d, 0x19, 0x92, 0xb7, - 0x0e, 0x69, 0x28, 0x5c, 0x03, 0x47, 0xcf, 0xc1, 0xa1, 0x7a, 0xf7, 0x9e, 0x4c, 0xb9, 0xc3, 0x49, - 0x74, 0x42, 0x02, 0xaf, 0x87, 0x79, 0xcf, 0x99, 0x51, 0x11, 0x97, 0x68, 0x7c, 0x3a, 0x7b, 0x66, - 0xf6, 0x25, 0xe6, 0x3d, 0xf4, 0x1a, 0x3e, 0xb9, 0x0a, 0x48, 0xc6, 0x82, 0x44, 0x21, 0xee, 0x7b, - 0x3d, 0x42, 0xbb, 0x3d, 0xe1, 0x14, 0xea, 0x56, 0x33, 0xe7, 0xd6, 0xfe, 0xc2, 0xb1, 0x65, 0xd6, - 0xbd, 0x54, 0xcb, 0xd0, 0x67, 0xf0, 0x51, 0x8a, 0xad, 0x83, 0xfb, 0x7d, 0x26, 0x3c, 0x1a, 0x06, - 0x64, 0xec, 0x14, 0x55, 0x16, 0x95, 0x84, 0x61, 0x43, 0x4d, 0xee, 0xc8, 0x39, 0xb4, 0x0d, 0xf5, - 0x14, 0xec, 0x98, 0x86, 0xb8, 0x4f, 0xdf, 0x91, 0xc0, 0x93, 0x9a, 0x88, 0x33, 0x00, 0x95, 0xc1, - 0xc7, 0x09, 0x7e, 0x3b, 0x5e, 0x75, 0x44, 0x04, 0x36, 0xe1, 0x29, 0xdc, 0x9b, 0xe0, 0xb1, 0xa0, - 0x2c, 0xf4, 0xb8, 0xc0, 0x62, 0xc4, 0x9d, 0x92, 0x2a, 0xd0, 0xb3, 0xd6, 0x8d, 0x7a, 0x6b, 0x25, - 0xac, 0x0a, 0xfb, 0xa5, 0x82, 0xba, 0x15, 0x71, 0x85, 0xb7, 0xf1, 0x0d, 0xcc, 0xcb, 0xc0, 0xeb, - 0xbe, 0x2f, 0xcf, 0x9f, 0x86, 0x5d, 0xe4, 0xc1, 0x22, 0xee, 0xb0, 0x48, 0xc4, 0x79, 0x9b, 0xc2, - 0x5a, 0xff, 0xae, 0xb0, 0x0b, 0x86, 0x4b, 0x05, 0x51, 0x4c, 0x8d, 0xef, 0x67, 0xc0, 0xde, 0x1b, - 0x89, 0xcb, 0x1a, 0x5f, 0x86, 0x42, 0x44, 0x7c, 0x42, 0x4f, 0x12, 0x95, 0x27, 0x63, 0xf4, 0x04, - 0xec, 0xd8, 0xd6, 0x4a, 0xdf, 0x89, 0x85, 0x5e, 0x8e, 0xfd, 0xb1, 0xd4, 0x2f, 0xa9, 0x39, 0x7b, - 0xab, 0x9a, 0x27, 0xba, 0xcd, 0xfd, 0x37, 0xdd, 0xae, 0xc2, 0x12, 0x33, 0x5b, 0x92, 0xa5, 0x17, - 0x9c, 0x7b, 0x21, 0x0b, 0x7d, 0xa2, 0xda, 0x24, 0xe7, 0x22, 0x96, 0xec, 0xf7, 0x80, 0xf3, 0x5d, - 0x39, 0x33, 0x0d, 0xe9, 0x62, 0xee, 0xf5, 0xe9, 0x80, 0xea, 0x16, 0xba, 0x04, 0x79, 0x81, 0xf9, - 0x6b, 0x39, 0x73, 0x15, 0x64, 0x18, 0x51, 0x9f, 0x98, 0xd6, 0xb8, 0x0c, 0xd9, 0x97, 0x33, 0xa8, - 0x09, 0x76, 0x1a, 0xa2, 0x1a, 0xa9, 0xa0, 0x56, 0xcf, 0x4f, 0x56, 0xab, 0x0e, 0x7a, 0x0e, 0x4e, - 0x7a, 0xe5, 0x15, 0xa2, 0x5f, 0x9a, 0x20, 0xd2, 0xaa, 0xdf, 0x85, 0x4f, 0xd3, 0xc0, 0x6b, 0x7b, - 0x4f, 0x2b, 0xbf, 0x3e, 0x21, 0xb9, 0xa6, 0xf9, 0xda, 0x50, 0x99, 0xde, 0xe5, 0x88, 0x93, 0xc0, - 0xa9, 0x28, 0xfc, 0xc2, 0xa5, 0x4d, 0x1e, 0x72, 0x12, 0x20, 0x01, 0xb5, 0x34, 0x80, 0x1c, 0x1f, - 0x13, 0x5f, 0xd0, 0x13, 0x92, 0x3a, 0xa0, 0x25, 0x55, 0xde, 0x96, 0x29, 0xef, 0xa3, 0xbf, 0x51, - 0xde, 0x9d, 0x50, 0xb8, 0xf7, 0x27, 0xb1, 0xb6, 0x62, 0xd2, 0xe4, 0x64, 0xbf, 0xb8, 0x29, 0xaa, - 0xae, 0xe4, 0x3d, 0x95, 0xf1, 0x35, 0x2c, 0xba, 0xa4, 0x0f, 0x00, 0xa4, 0x58, 0x86, 0xa3, 0xce, - 0x5b, 0x72, 0xaa, 0xda, 0xbb, 0xe8, 0x16, 0x05, 0xe7, 0xfb, 0xca, 0x71, 0xc3, 0x4d, 0x30, 0xfb, - 0x7f, 0xdf, 0x04, 0x3f, 0x5b, 0x90, 0xd7, 0x26, 0x5a, 0x87, 0xbc, 0x89, 0x62, 0xa9, 0x28, 0x4f, - 0x6e, 0x89, 0xb2, 0xe9, 0x8b, 0xb1, 0xe1, 0x36, 0x40, 0xf4, 0x10, 0xe6, 0xb5, 0xe5, 0x0d, 0x08, - 0xe7, 0xb8, 0x4b, 0x54, 0xc7, 0x16, 0xdd, 0x39, 0xed, 0x7d, 0xa3, 0x9d, 0x68, 0x15, 0x2a, 0x7d, - 0xcc, 0xc5, 0xe1, 0x30, 0xc0, 0x82, 0x78, 0x82, 0x0e, 0x08, 0x17, 0x78, 0x30, 0x54, 0xad, 0x9b, - 0x75, 0x17, 0x27, 0x73, 0x07, 0xf1, 0x14, 0x6a, 0x42, 0x99, 0xf2, 0x75, 0x79, 0xab, 0xb8, 0xe4, - 0x78, 0x14, 0x06, 0x24, 0x50, 0xcd, 0x5b, 0x70, 0xa7, 0xdd, 0x8d, 0x9f, 0xb2, 0x30, 0xbb, 0x29, - 0xb3, 0x54, 0xb7, 0xc3, 0xc1, 0x18, 0x39, 0x30, 0xe3, 0x47, 0x04, 0x0b, 0x16, 0xdf, 0x31, 0xf1, - 0x50, 0x3e, 0x6b, 0x5a, 0xe9, 0x3a, 0x4b, 0x3d, 0x40, 0x5f, 0x43, 0x51, 0x5d, 0x81, 0xc7, 0x84, - 0x70, 0xfd, 0xe0, 0x6d, 0x6c, 0xfe, 0xc3, 0x1b, 0xe2, 0x8f, 0xb3, 0x9a, 0x7d, 0x8a, 0x07, 0xfd, - 0xcf, 0x1b, 0x09, 0x53, 0xc3, 0x2d, 0x48, 0x7b, 0x9b, 0x10, 0x8e, 0x1e, 0x43, 0x39, 0x22, 0x7d, - 0x7c, 0x4a, 0x82, 0xe4, 0x9c, 0xf2, 0xba, 0x3b, 0x8d, 0x3b, 0x3e, 0xa8, 0x6d, 0x28, 0xf9, 0xbe, - 0x18, 0xc7, 0xd5, 0x97, 0x2d, 0x5c, 0x5a, 0x7b, 0x78, 0x4b, 0x5d, 0x4c, 0x4d, 0xc0, 0x4f, 0xea, - 0x83, 0x8e, 0x60, 0x21, 0xf5, 0x44, 0x0d, 0xd5, 0xe5, 0xab, 0xda, 0xbb, 0xb4, 0xd6, 0xba, 0x85, - 0x6d, 0xea, 0xb7, 0xc4, 0x2d, 0xd3, 0xa9, 0xff, 0x94, 0xaf, 0x00, 0xa5, 0x3b, 0xc2, 0x90, 0x43, - 0x3d, 0xdb, 0x2c, 0xad, 0xb5, 0x6f, 0x21, 0x9f, 0x7e, 0x10, 0x5c, 0x9b, 0x4d, 0x79, 0x9e, 0x7e, - 0x0b, 0x30, 0x11, 0x1a, 0x42, 0x30, 0xbf, 0x4f, 0xc2, 0x80, 0x86, 0x5d, 0x93, 0x97, 0x9d, 0x41, - 0x8b, 0x50, 0x36, 0xbe, 0x98, 0xce, 0xb6, 0xd0, 0x02, 0xcc, 0xc5, 0xa3, 0x37, 0x34, 0x24, 0x81, - 0x9d, 0x95, 0x2e, 0xb3, 0xce, 0x25, 0x27, 0x24, 0x12, 0x76, 0x0e, 0xcd, 0x42, 0x41, 0xdb, 0x24, - 0xb0, 0xef, 0xa2, 0x12, 0xcc, 0xac, 0xeb, 0x77, 0xcb, 0xce, 0x2f, 0xe7, 0x7e, 0xfc, 0xa1, 0x6a, - 0x3d, 0x7d, 0x05, 0x95, 0xab, 0x9a, 0x09, 0xd9, 0x30, 0xbb, 0xcb, 0x44, 0xf2, 0x8a, 0xdb, 0x19, - 0x34, 0x07, 0xc5, 0xc9, 0xd0, 0x92, 0xcc, 0x5b, 0x63, 0xe2, 0x8f, 0x24, 0xd9, 0x1d, 0x4d, 0xb6, - 0xf1, 0xea, 0xfd, 0x79, 0xd5, 0xfa, 0x70, 0x5e, 0xb5, 0x7e, 0x3b, 0xaf, 0x5a, 0xdf, 0x5d, 0x54, - 0x33, 0x1f, 0x2e, 0xaa, 0x99, 0x5f, 0x2e, 0xaa, 0x99, 0xa3, 0xd5, 0x94, 0xae, 0xe4, 0x39, 0xad, - 0xe8, 0xbf, 0xce, 0xf8, 0xc8, 0xda, 0xe3, 0x76, 0xea, 0x5f, 0x54, 0xc9, 0xac, 0x93, 0x57, 0x7f, - 0x8e, 0xcf, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x13, 0xc7, 0x24, 0x8d, 0xa6, 0x0a, 0x00, 0x00, + 0x12, 0x25, 0x40, 0x24, 0xc4, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0x8d, 0x13, 0x23, 0x3f, 0x36, 0xb6, + 0xf6, 0xc5, 0x40, 0xb1, 0xa5, 0x76, 0xc7, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, + 0x10, 0x3d, 0xf4, 0x11, 0x7a, 0xe8, 0xa3, 0xe4, 0xd6, 0x1c, 0x8b, 0x1e, 0x8c, 0xc2, 0x3e, 0xe7, + 0xd2, 0x27, 0x28, 0x48, 0xee, 0x4a, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, 0x9b, + 0x21, 0xe7, 0x1b, 0x72, 0xa1, 0xe6, 0x47, 0x5c, 0x08, 0xbf, 0x47, 0x59, 0xd8, 0xd6, 0xa6, 0xa7, + 0x6d, 0x4f, 0x8e, 0x5b, 0xc3, 0x88, 0x4b, 0x4e, 0xee, 0xbc, 0x43, 0x49, 0xb5, 0xaf, 0xa5, 0x2d, + 0x1e, 0x61, 0x6b, 0x8a, 0x59, 0x5d, 0xf6, 0xf9, 0x60, 0xc0, 0xc3, 0xb6, 0xf9, 0x18, 0xcc, 0x6a, + 0xa5, 0xcb, 0xbb, 0x5c, 0x9b, 0x6d, 0x65, 0x19, 0x6f, 0xe3, 0x63, 0x0e, 0xca, 0xdb, 0x61, 0x87, + 0x8f, 0xc2, 0x60, 0x6f, 0xbc, 0x4b, 0x23, 0x3a, 0x10, 0xe4, 0x16, 0xe4, 0x05, 0x86, 0x01, 0x46, + 0x8e, 0x55, 0xb7, 0x9a, 0x45, 0x37, 0x1e, 0x91, 0x7b, 0x50, 0x36, 0x56, 0x9c, 0x0e, 0x0b, 0x9c, + 0x1b, 0x75, 0xab, 0x99, 0x75, 0x17, 0x8c, 0x7b, 0x53, 0x79, 0xb7, 0x03, 0x72, 0x1b, 0x8a, 0x72, + 0xec, 0xf1, 0x88, 0x75, 0x59, 0xe8, 0x64, 0x35, 0x45, 0x41, 0x8e, 0x77, 0xf4, 0x98, 0x3c, 0x82, + 0xa2, 0xcf, 0xd5, 0x5e, 0x8e, 0x87, 0xe8, 0xe4, 0xea, 0x56, 0x73, 0x71, 0xcd, 0x6e, 0xc5, 0x89, + 0x6e, 0x72, 0x16, 0xee, 0x1d, 0x0f, 0xd1, 0x2d, 0xf8, 0xb1, 0x45, 0x2a, 0x70, 0x93, 0x0a, 0x81, + 0xd2, 0xb9, 0xa9, 0x79, 0xcc, 0x80, 0x3c, 0x87, 0x3c, 0x1d, 0xf0, 0x51, 0x28, 0x9d, 0xbc, 0x72, + 0x6f, 0xb4, 0xdf, 0x9f, 0xd4, 0x32, 0xbf, 0x9d, 0xd4, 0xee, 0x77, 0x99, 0xec, 0x8d, 0x3a, 0x8a, + 0xaf, 0xed, 0x73, 0x31, 0xe0, 0x22, 0xfe, 0x3c, 0x12, 0xc1, 0xdb, 0xb6, 0x0a, 0x29, 0x5a, 0xfb, + 0x2c, 0x94, 0x6e, 0x0c, 0x27, 0x4f, 0xc1, 0x61, 0x66, 0xf7, 0x9e, 0x4a, 0xb9, 0x23, 0x30, 0x3a, + 0xc2, 0xc0, 0xeb, 0x51, 0xd1, 0x73, 0xe6, 0x74, 0xc4, 0x15, 0x96, 0x9c, 0xce, 0x4e, 0x3c, 0xfb, + 0x82, 0x8a, 0x1e, 0x79, 0x05, 0x9f, 0x5d, 0x04, 0xc4, 0xb1, 0xc4, 0x28, 0xa4, 0x7d, 0xaf, 0x87, + 0xac, 0xdb, 0x93, 0x4e, 0xa1, 0x6e, 0x35, 0x73, 0x6e, 0xed, 0x2f, 0x1c, 0xcf, 0xe2, 0x75, 0x2f, + 0xf4, 0x32, 0xf2, 0x05, 0x7c, 0x92, 0x62, 0xeb, 0xd0, 0x7e, 0x9f, 0x4b, 0x8f, 0x85, 0x01, 0x8e, + 0x9d, 0xa2, 0xce, 0xa2, 0x32, 0x61, 0xd8, 0xd0, 0x93, 0xdb, 0x6a, 0x8e, 0x6c, 0x41, 0x3d, 0x05, + 0x3b, 0x64, 0x21, 0xed, 0xb3, 0x77, 0x18, 0x78, 0x4a, 0x13, 0x49, 0x06, 0xa0, 0x33, 0xf8, 0x74, + 0x82, 0xdf, 0x4a, 0x56, 0x1d, 0xa0, 0xa4, 0x71, 0x78, 0x06, 0xb7, 0xa6, 0x78, 0x2a, 0x19, 0x0f, + 0x3d, 0x21, 0xa9, 0x1c, 0x09, 0xa7, 0xa4, 0x0b, 0xf4, 0xa4, 0x75, 0xa5, 0xde, 0x5a, 0x13, 0x56, + 0x8d, 0xfd, 0x5a, 0x43, 0xdd, 0x8a, 0xbc, 0xc0, 0xdb, 0xf8, 0x0e, 0x16, 0x55, 0xe0, 0x75, 0xdf, + 0x57, 0xe7, 0xcf, 0xc2, 0x2e, 0xf1, 0x60, 0x99, 0x76, 0x78, 0x24, 0x93, 0xbc, 0xe3, 0xc2, 0x5a, + 0xff, 0xae, 0xb0, 0x4b, 0x31, 0x97, 0x0e, 0xa2, 0x99, 0x1a, 0x3f, 0xce, 0x81, 0xbd, 0x33, 0x92, + 0xe7, 0x35, 0xbe, 0x0a, 0x85, 0x08, 0x7d, 0x64, 0x47, 0x13, 0x95, 0x4f, 0xc6, 0xe4, 0x01, 0xd8, + 0x89, 0x6d, 0x94, 0xbe, 0x9d, 0x08, 0xbd, 0x9c, 0xf8, 0x13, 0xa9, 0x9f, 0x53, 0x73, 0xf6, 0x5a, + 0x35, 0x4f, 0x75, 0x9b, 0xfb, 0x6f, 0xba, 0x7d, 0x0c, 0x2b, 0x3c, 0xde, 0x92, 0x2a, 0xbd, 0x14, + 0xc2, 0x0b, 0x79, 0xe8, 0xa3, 0x6e, 0x93, 0x9c, 0x4b, 0xf8, 0x64, 0xbf, 0x7b, 0x42, 0xbc, 0x51, + 0x33, 0xb3, 0x90, 0x2e, 0x15, 0x5e, 0x9f, 0x0d, 0x98, 0x69, 0xa1, 0x73, 0x90, 0xe7, 0x54, 0xbc, + 0x52, 0x33, 0x17, 0x41, 0x86, 0x11, 0xf3, 0x31, 0x6e, 0x8d, 0xf3, 0x90, 0x5d, 0x35, 0x43, 0x9a, + 0x60, 0xa7, 0x21, 0xba, 0x91, 0x0a, 0x7a, 0xf5, 0xe2, 0x74, 0xb5, 0xee, 0xa0, 0xa7, 0xe0, 0xa4, + 0x57, 0x5e, 0x20, 0xfa, 0x95, 0x29, 0x22, 0xad, 0xfa, 0x37, 0xf0, 0x79, 0x1a, 0x78, 0x69, 0xef, + 0x19, 0xe5, 0xd7, 0xa7, 0x24, 0x97, 0x34, 0x5f, 0x1b, 0x2a, 0xb3, 0xbb, 0x1c, 0x09, 0x0c, 0x9c, + 0x8a, 0xc6, 0x2f, 0x9d, 0xdb, 0xe4, 0xbe, 0xc0, 0x80, 0x48, 0xa8, 0xa5, 0x01, 0x78, 0x78, 0x88, + 0xbe, 0x64, 0x47, 0x98, 0x3a, 0xa0, 0x15, 0x5d, 0xde, 0x56, 0x5c, 0xde, 0x7b, 0x7f, 0xa3, 0xbc, + 0xdb, 0xa1, 0x74, 0x6f, 0x4f, 0x63, 0x3d, 0x4b, 0x48, 0x27, 0x27, 0xfb, 0xd5, 0x55, 0x51, 0x4d, + 0x25, 0x6f, 0xe9, 0x8c, 0x2f, 0x61, 0x31, 0x25, 0xbd, 0x03, 0xa0, 0xc4, 0x32, 0x1c, 0x75, 0xde, + 0xe2, 0xb1, 0x6e, 0xef, 0xa2, 0x5b, 0x94, 0x42, 0xec, 0x6a, 0xc7, 0x15, 0x37, 0xc1, 0xfc, 0xff, + 0x7d, 0x13, 0xfc, 0x62, 0x41, 0xde, 0x98, 0x64, 0x1d, 0xf2, 0x71, 0x14, 0x4b, 0x47, 0x79, 0x70, + 0x4d, 0x94, 0x4d, 0x5f, 0x8e, 0x63, 0xee, 0x18, 0x48, 0xee, 0xc2, 0xa2, 0xb1, 0xbc, 0x01, 0x0a, + 0x41, 0xbb, 0xa8, 0x3b, 0xb6, 0xe8, 0x2e, 0x18, 0xef, 0x6b, 0xe3, 0x24, 0x8f, 0xa1, 0xd2, 0xa7, + 0x42, 0xee, 0x0f, 0x03, 0x2a, 0xd1, 0x93, 0x6c, 0x80, 0x42, 0xd2, 0xc1, 0x50, 0xb7, 0x6e, 0xd6, + 0x5d, 0x9e, 0xce, 0xed, 0x25, 0x53, 0xa4, 0x09, 0x65, 0x26, 0xd6, 0xd5, 0xad, 0xe2, 0xe2, 0xe1, + 0x28, 0x0c, 0x30, 0xd0, 0xcd, 0x5b, 0x70, 0x67, 0xdd, 0x8d, 0x8f, 0x59, 0x98, 0xdf, 0x54, 0x59, + 0xea, 0xdb, 0x61, 0x6f, 0x4c, 0x1c, 0x98, 0xf3, 0x23, 0xa4, 0x92, 0x27, 0x77, 0x4c, 0x32, 0x54, + 0xcf, 0x9a, 0x51, 0xba, 0xc9, 0xd2, 0x0c, 0xc8, 0xb7, 0x50, 0xd4, 0x57, 0xe0, 0x21, 0xa2, 0x30, + 0x0f, 0xde, 0xc6, 0xe6, 0x3f, 0xbc, 0x21, 0xfe, 0x38, 0xa9, 0xd9, 0xc7, 0x74, 0xd0, 0xff, 0xb2, + 0x31, 0x61, 0x6a, 0xb8, 0x05, 0x65, 0x6f, 0x21, 0x0a, 0x72, 0x1f, 0xca, 0x11, 0xf6, 0xe9, 0x31, + 0x06, 0x93, 0x73, 0xca, 0x9b, 0xee, 0x8c, 0xdd, 0xc9, 0x41, 0x6d, 0x41, 0xc9, 0xf7, 0xe5, 0x38, + 0xa9, 0xbe, 0x6a, 0xe1, 0xd2, 0xda, 0xdd, 0x6b, 0xea, 0x12, 0xd7, 0x04, 0xfc, 0x49, 0x7d, 0xc8, + 0x01, 0x2c, 0xa5, 0x9e, 0xa8, 0xa1, 0xbe, 0x7c, 0x75, 0x7b, 0x97, 0xd6, 0x5a, 0xd7, 0xb0, 0xcd, + 0xfc, 0x96, 0xb8, 0x65, 0x36, 0xf3, 0x9f, 0xf2, 0x0d, 0x90, 0x74, 0x47, 0xc4, 0xe4, 0x50, 0xcf, + 0x36, 0x4b, 0x6b, 0xed, 0x6b, 0xc8, 0x67, 0x1f, 0x04, 0xd7, 0xe6, 0xb3, 0x4f, 0x44, 0x0d, 0x4a, + 0x78, 0x84, 0x61, 0x72, 0x27, 0x95, 0x74, 0x73, 0x81, 0x76, 0xe9, 0x8b, 0xe8, 0xe1, 0xf7, 0x00, + 0x53, 0x25, 0x12, 0x02, 0x8b, 0xbb, 0x18, 0x06, 0x2c, 0xec, 0xc6, 0x89, 0xdb, 0x19, 0xb2, 0x0c, + 0xe5, 0xd8, 0x97, 0xc4, 0xb3, 0x2d, 0xb2, 0x04, 0x0b, 0xc9, 0xe8, 0x35, 0x0b, 0x31, 0xb0, 0xb3, + 0xca, 0x15, 0xaf, 0x73, 0xf1, 0x08, 0x23, 0x69, 0xe7, 0xc8, 0x3c, 0x14, 0x8c, 0x8d, 0x81, 0x7d, + 0x93, 0x94, 0x60, 0x6e, 0xdd, 0x3c, 0x6c, 0x76, 0x7e, 0x35, 0xf7, 0xf3, 0x4f, 0x55, 0xeb, 0xe1, + 0x4b, 0xa8, 0x5c, 0xd4, 0x6d, 0xc4, 0x86, 0xf9, 0x37, 0x5c, 0x4e, 0x9e, 0x79, 0x3b, 0x43, 0x16, + 0xa0, 0x38, 0x1d, 0x5a, 0x8a, 0xf9, 0xd9, 0x18, 0xfd, 0x91, 0x22, 0xbb, 0x61, 0xc8, 0x36, 0x5e, + 0xbe, 0x3f, 0xad, 0x5a, 0x1f, 0x4e, 0xab, 0xd6, 0xef, 0xa7, 0x55, 0xeb, 0x87, 0xb3, 0x6a, 0xe6, + 0xc3, 0x59, 0x35, 0xf3, 0xeb, 0x59, 0x35, 0x73, 0xf0, 0x38, 0x25, 0x3c, 0x75, 0x90, 0x8f, 0xcc, + 0x6f, 0x69, 0x72, 0xa6, 0xed, 0x71, 0x3b, 0xf5, 0xb3, 0xaa, 0x75, 0xd8, 0xc9, 0xeb, 0x5f, 0xcb, + 0x27, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x87, 0xc1, 0xc0, 0x30, 0xc7, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -949,6 +958,11 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.EventIndex != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.EventIndex)) + i-- + dAtA[i] = 0x58 + } if len(m.OutboundTxParams) > 0 { for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { { @@ -1202,6 +1216,9 @@ func (m *CrossChainTx) Size() (n int) { n += 1 + l + sovCrossChainTx(uint64(l)) } } + if m.EventIndex != 0 { + n += 1 + sovCrossChainTx(uint64(m.EventIndex)) + } return n } @@ -2469,6 +2486,25 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EventIndex", wireType) + } + m.EventIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EventIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) From 46366f806b5799ab19d5d12f6387f43dd30ea22d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 6 Mar 2024 01:03:41 -0500 Subject: [PATCH 02/36] add unit tests for ProcessZEVMDeposit --- x/crosschain/keeper/cctx_utils.go | 4 +- x/crosschain/keeper/cctx_utils_test.go | 256 +++++++++++++++++++++++++ x/crosschain/keeper/gas_payment.go | 9 +- 3 files changed, 262 insertions(+), 7 deletions(-) diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index e0ed1a7f71..996bec2f03 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -209,7 +209,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { gasLimit, err := k.GetRevertGasLimit(ctx, cctx) if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "can't get revert tx gas limit"+err.Error()) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("can't get revert tx gas limit,%s", err.Error())) return } if gasLimit == 0 { @@ -243,7 +243,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return k.UpdateNonce(tmpCtx, chain.ChainId, cctx) }() if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) return } commit() diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 36297d5e31..4dc63d2183 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -1,10 +1,13 @@ package keeper_test import ( + "fmt" "math/big" "testing" sdkmath "cosmossdk.io/math" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -12,6 +15,7 @@ import ( crosschainkeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func TestGetRevertGasLimit(t *testing.T) { @@ -191,3 +195,255 @@ func TestGetAbortedAmount(t *testing.T) { require.Equal(t, sdkmath.ZeroUint(), a) }) } + +func TestKeeper_ProcessZEVMDeposit(t *testing.T) { + t.Run("process zevm deposit successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + // expect DepositCoinZeta to be called + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(nil) + + // call HandleEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit returns err without reverting", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup expected calls + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(fmt.Errorf("deposit error"), false) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at GetSupportedChainFromChainID", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChainId := getValidEthChainID(t) + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + fungibleMock.On( + "ZRC20DepositAndCallContract", + mock.Anything, + mock.Anything, + receiver, + amount, + senderChainId, + mock.Anything, + common.CoinType_ERC20, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChainId). + Return(nil) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = senderChainId + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = "" + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "invalid sender chain", cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + fungibleMock.On( + "ZRC20DepositAndCallContract", + mock.Anything, + mock.Anything, + receiver, + amount, + senderChain.ChainId, + mock.Anything, + common.CoinType_ERC20, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{}, false) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = asset + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("can't get revert tx gas limit,%s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + fungibleMock.On( + "ZRC20DepositAndCallContract", + mock.Anything, + mock.Anything, + receiver, + amount, + senderChain.ChainId, + mock.Anything, + common.CoinType_ERC20, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, true) + fungibleMock.On("QueryGasLimit", mock.Anything, mock.Anything). + Return(big.NewInt(100), nil) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain).Once() + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = asset + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + fungibleMock.On( + "ZRC20DepositAndCallContract", + mock.Anything, + mock.Anything, + receiver, + amount, + senderChain.ChainId, + mock.Anything, + common.CoinType_ERC20, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, true) + fungibleMock.On("QueryGasLimit", mock.Anything, mock.Anything). + Return(big.NewInt(100), nil) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain).Once() + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = asset + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) + }) + +} diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index e42c6df643..7f46d51e9a 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -14,7 +14,7 @@ import ( "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" - zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) // PayGasAndUpdateCctx updates the outbound tx with the new amount after paying the gas fee @@ -94,7 +94,7 @@ func (k Keeper) PayGasNativeAndUpdateCctx( return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in native gas with %s", cctx.InboundTxParams.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { - return zetaObserverTypes.ErrSupportedChains + return observertypes.ErrSupportedChains } // get gas params @@ -142,7 +142,7 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { - return zetaObserverTypes.ErrSupportedChains + return observertypes.ErrSupportedChains } // get gas params @@ -151,7 +151,6 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( return cosmoserrors.Wrap(types.ErrCannotFindGasParams, err.Error()) } outTxGasFee := gasLimit.Mul(gasPrice).Add(protocolFlatFee) - // get address of the zrc20 fc, found := k.fungibleKeeper.GetForeignCoinFromAsset(ctx, cctx.InboundTxParams.Asset, chainID) if !found { @@ -269,7 +268,7 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { - return zetaObserverTypes.ErrSupportedChains + return observertypes.ErrSupportedChains } gasZRC20, err := k.fungibleKeeper.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) From 398ee79506ed18aa108161f4d565f1e51fb52c2b Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 6 Mar 2024 15:11:01 -0500 Subject: [PATCH 03/36] creating mocking functions for test refactor --- testutil/keeper/crosschain.go | 82 +++++++++ x/crosschain/keeper/cctx_utils.go | 9 +- x/crosschain/keeper/cctx_utils_test.go | 231 ++++++++++++------------- x/crosschain/keeper/gas_payment.go | 1 - 4 files changed, 200 insertions(+), 123 deletions(-) diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index 715383ee92..8ef4d44cc5 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -1,16 +1,24 @@ package keeper import ( + "math/big" "testing" "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" tmdb "github.com/tendermint/tm-db" + "github.com/zeta-chain/zetacore/common" crosschainmocks "github.com/zeta-chain/zetacore/testutil/keeper/mocks/crosschain" + "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) type CrosschainMockOptions struct { @@ -183,3 +191,77 @@ func GetCrosschainFungibleMock(t testing.TB, keeper *keeper.Keeper) *crosschainm require.True(t, ok) return cfk } + +func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeeper, senderChain *common.Chain) { + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain).Once() + +} +func MockGetRevertGasLimitForERC20(m *crosschainmocks.CrosschainFungibleKeeper, asset string, senderChain common.Chain) { + m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, true) + m.On("QueryGasLimit", mock.Anything, mock.Anything). + Return(big.NewInt(100), nil) + +} +func MockPayGasAndUpdateCCTX(m *crosschainmocks.CrosschainFungibleKeeper, m2 *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, k keeper.Keeper, senderChain common.Chain) { + m2.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(&senderChain).Twice() + m.On("QuerySystemContractGasCoinZRC20", mock.Anything, mock.Anything). + Return(ethcommon.Address{}, nil) + m.On("QueryGasLimit", mock.Anything, mock.Anything). + Return(big.NewInt(100), nil) + m.On("QueryProtocolFlatFee", mock.Anything, mock.Anything). + Return(big.NewInt(1), nil) + k.SetGasPrice(ctx, types.GasPrice{ + ChainId: senderChain.ChainId, + MedianIndex: 0, + Prices: []uint64{1}, + }) + + m.On("QueryUniswapV2RouterGetZRC4ToZRC4AmountsIn", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(big.NewInt(0), nil) + m.On("DepositZRC20", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(&evmtypes.MsgEthereumTxResponse{}, nil) + m.On("GetUniswapV2Router02Address", mock.Anything). + Return(ethcommon.Address{}, nil) + m.On("CallZRC20Approve", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil) + m.On("CallUniswapV2RouterSwapExactTokensForTokens", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(1000)}, nil) + m.On("CallZRC20Burn", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + Return(nil) + +} + +func MockUpdateNonce(m *crosschainmocks.CrosschainObserverKeeper, senderChain common.Chain) (nonce uint64) { + nonce = uint64(1) + tss := sample.Tss() + m.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(senderChain) + m.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{Nonce: nonce}, true) + m.On("GetTSS", mock.Anything). + Return(tss, true) + m.On("GetPendingNonces", mock.Anything, tss.TssPubkey, mock.Anything). + Return(observertypes.PendingNonces{NonceHigh: int64(nonce)}, true) + m.On("SetChainNonces", mock.Anything, mock.Anything) + m.On("SetPendingNonces", mock.Anything, mock.Anything) + return +} + +func MockRevertForHandleEVMDeposit(m *crosschainmocks.CrosschainFungibleKeeper, receiver ethcommon.Address, amount *big.Int, senderChainId int64, errDeposit error) { + m.On( + "ZRC20DepositAndCallContract", + mock.Anything, + mock.Anything, + receiver, + amount, + senderChainId, + mock.Anything, + common.CoinType_ERC20, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) +} diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 996bec2f03..a307e76be3 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -201,8 +201,8 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return } else if err != nil && isContractReverted { // contract call reverted; should refund revertMessage := err.Error() - chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) - if chain == nil { + senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) + if senderChain == nil { cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") return } @@ -232,7 +232,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { err = func() error { err := k.PayGasAndUpdateCctx( tmpCtx, - chain.ChainId, + senderChain.ChainId, cctx, cctx.InboundTxParams.Amount, false, @@ -240,7 +240,8 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { if err != nil { return err } - return k.UpdateNonce(tmpCtx, chain.ChainId, cctx) + // Update nonce using senderchain id as this is a revert tx and would go back to the original sender + return k.UpdateNonce(tmpCtx, senderChain.ChainId, cctx) }() if err != nil { cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 4dc63d2183..24801572c0 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -6,7 +6,7 @@ import ( "testing" sdkmath "cosmossdk.io/math" - evmtypes "github.com/evmos/ethermint/x/evm/types" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" @@ -202,6 +202,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { UseFungibleMock: true, }) + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) @@ -210,7 +211,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). Return(nil) - // call HandleEVMDeposit + // call ProcessZEVMDeposit cctx := sample.CrossChainTx(t, "test") cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} cctx.GetCurrentOutTxParam().Receiver = receiver.String() @@ -226,11 +227,12 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - // Setup expected calls + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) + // mock unsuccessful HandleEVMDeposit which does not revert fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). Return(fmt.Errorf("deposit error"), false) @@ -252,39 +254,24 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { UseObserverMock: true, }) + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChainId := getValidEthChainID(t) - // Setup expected calls + senderChain := getValidEthChain(t) errDeposit := fmt.Errorf("deposit failed") - fungibleMock.On( - "ZRC20DepositAndCallContract", - mock.Anything, - mock.Anything, - receiver, - amount, - senderChainId, - mock.Anything, - common.CoinType_ERC20, - mock.Anything, - ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChainId). + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // mock unsuccessful GetSupportedChainFromChainID + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). Return(nil) // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = senderChainId - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 - cctx.RelayedMessage = "" - cctx.GetInboundTxParams().Asset = "" - cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, "invalid sender chain", cctx.CctxStatus.StatusMessage) @@ -296,43 +283,27 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { UseObserverMock: true, }) + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain(t) asset := "" + errDeposit := fmt.Errorf("deposit failed") // Setup expected calls - errDeposit := fmt.Errorf("deposit failed") - fungibleMock.On( - "ZRC20DepositAndCallContract", - mock.Anything, - mock.Anything, - receiver, - amount, - senderChain.ChainId, - mock.Anything, - common.CoinType_ERC20, - mock.Anything, - ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock unsuccessful GetRevertGasLimit for ERC20 fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). Return(fungibletypes.ForeignCoins{}, false) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain) - // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 - cctx.RelayedMessage = "" - cctx.GetInboundTxParams().Asset = asset - cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, fmt.Sprintf("can't get revert tx gas limit,%s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) @@ -344,6 +315,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { UseObserverMock: true, }) + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) @@ -352,98 +324,121 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { // Setup expected calls errDeposit := fmt.Errorf("deposit failed") - fungibleMock.On( - "ZRC20DepositAndCallContract", - mock.Anything, - mock.Anything, - receiver, - amount, - senderChain.ChainId, - mock.Anything, - common.CoinType_ERC20, - mock.Anything, - ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, true) - fungibleMock.On("QueryGasLimit", mock.Anything, mock.Anything). - Return(big.NewInt(100), nil) + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain).Once() + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock unsuccessful PayGasInERC20AndUpdateCctx observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). Return(nil).Once() // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 - cctx.RelayedMessage = "" - cctx.GetInboundTxParams().Asset = asset - cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) }) - t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at UpdateNonce", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ UseFungibleMock: true, UseObserverMock: true, }) + // Setup mock data fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) senderChain := getValidEthChain(t) asset := "" + errDeposit := fmt.Errorf("deposit failed") // Setup expected calls - errDeposit := fmt.Errorf("deposit failed") - fungibleMock.On( - "ZRC20DepositAndCallContract", - mock.Anything, - mock.Anything, - receiver, - amount, - senderChain.ChainId, - mock.Anything, - common.CoinType_ERC20, - mock.Anything, - ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, true) - fungibleMock.On("QueryGasLimit", mock.Anything, mock.Anything). - Return(big.NewInt(100), nil) + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(senderChain).Once() - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain) + + // Mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 - cctx.RelayedMessage = "" - cctx.GetInboundTxParams().Asset = asset - cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain) + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) + require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) }) +} + +func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { + t.Run("process crosschain msg passing successfully", func(t *testing.T) { + + }) +} +func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.Chain, asset string, amount *big.Int) *types.CrossChainTx { + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.RelayedMessage = "" + cctx.GetInboundTxParams().Asset = asset + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + return cctx } diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index 7f46d51e9a..a085e9cc7d 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -144,7 +144,6 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { return observertypes.ErrSupportedChains } - // get gas params gasZRC20, gasLimit, gasPrice, protocolFlatFee, err := k.ChainGasParams(ctx, chainID) if err != nil { From 595fd368f1caf0cea111245e6303dd7a069b8a95 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 6 Mar 2024 15:41:51 -0500 Subject: [PATCH 04/36] add tests for Process message passing --- testutil/keeper/crosschain.go | 26 +++++---- x/crosschain/keeper/cctx_utils.go | 1 + x/crosschain/keeper/cctx_utils_test.go | 77 +++++++++++++++++++++++++- 3 files changed, 91 insertions(+), 13 deletions(-) diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index 8ef4d44cc5..bc262a2c52 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -201,20 +201,24 @@ func MockGetRevertGasLimitForERC20(m *crosschainmocks.CrosschainFungibleKeeper, m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().String(), - }, true) + }, true).Once() m.On("QueryGasLimit", mock.Anything, mock.Anything). - Return(big.NewInt(100), nil) + Return(big.NewInt(100), nil).Once() } -func MockPayGasAndUpdateCCTX(m *crosschainmocks.CrosschainFungibleKeeper, m2 *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, k keeper.Keeper, senderChain common.Chain) { +func MockPayGasAndUpdateCCTX(m *crosschainmocks.CrosschainFungibleKeeper, m2 *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, k keeper.Keeper, senderChain common.Chain, asset string) { m2.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). Return(&senderChain).Twice() + m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, true).Once() m.On("QuerySystemContractGasCoinZRC20", mock.Anything, mock.Anything). - Return(ethcommon.Address{}, nil) + Return(ethcommon.Address{}, nil).Once() m.On("QueryGasLimit", mock.Anything, mock.Anything). - Return(big.NewInt(100), nil) + Return(big.NewInt(100), nil).Once() m.On("QueryProtocolFlatFee", mock.Anything, mock.Anything). - Return(big.NewInt(1), nil) + Return(big.NewInt(1), nil).Once() k.SetGasPrice(ctx, types.GasPrice{ ChainId: senderChain.ChainId, MedianIndex: 0, @@ -222,17 +226,17 @@ func MockPayGasAndUpdateCCTX(m *crosschainmocks.CrosschainFungibleKeeper, m2 *cr }) m.On("QueryUniswapV2RouterGetZRC4ToZRC4AmountsIn", mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(big.NewInt(0), nil) + Return(big.NewInt(0), nil).Once() m.On("DepositZRC20", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(&evmtypes.MsgEthereumTxResponse{}, nil) m.On("GetUniswapV2Router02Address", mock.Anything). - Return(ethcommon.Address{}, nil) + Return(ethcommon.Address{}, nil).Once() m.On("CallZRC20Approve", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil) + Return(nil).Once() m.On("CallUniswapV2RouterSwapExactTokensForTokens", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(1000)}, nil) + Return([]*big.Int{big.NewInt(0), big.NewInt(1), big.NewInt(1000)}, nil).Once() m.On("CallZRC20Burn", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). - Return(nil) + Return(nil).Once() } diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index a307e76be3..32568af5a0 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -264,6 +264,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { // Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { tmpCtx, commit := ctx.CacheContext() + // Todo : Check receiver vs sender chain id outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId err := func() error { err := k.PayGasAndUpdateCctx( diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 24801572c0..42bea61fe9 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -371,7 +371,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) // Mock unsuccessful UpdateNonce observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). @@ -410,7 +410,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) // mock successful UpdateNonce updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) @@ -425,7 +425,79 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { t.Run("process crosschain msg passing successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + }) + + t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock unsuccessful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). + Return(nil).Once() + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") }) } @@ -436,6 +508,7 @@ func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.C cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetCurrentOutTxParam().ReceiverChainId = senderChain.ChainId cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.RelayedMessage = "" cctx.GetInboundTxParams().Asset = asset From 842fcb1028b027979435295857214ae5d1e53f68 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 6 Mar 2024 18:02:58 -0500 Subject: [PATCH 05/36] move cointype to cctx struct and refactor tests to accomodate the change --- e2e/runner/logger.go | 4 +- proto/crosschain/cross_chain_tx.proto | 3 +- testutil/sample/crosschain.go | 3 +- .../types/message_update_policies_test.go | 2 - x/authority/types/policies_test.go | 1 - .../client/integrationtests/cli_test.go | 5 +- x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_test.go | 5 +- x/crosschain/keeper/cctx_utils.go | 13 +- x/crosschain/keeper/cctx_utils_test.go | 24 +- x/crosschain/keeper/evm_deposit.go | 2 +- x/crosschain/keeper/evm_deposit_test.go | 22 +- x/crosschain/keeper/evm_hooks.go | 6 +- x/crosschain/keeper/gas_payment.go | 16 +- x/crosschain/keeper/gas_payment_test.go | 72 ++--- .../keeper/msg_server_migrate_tss_funds.go | 3 +- .../keeper/msg_server_refund_aborted_tx.go | 2 +- .../msg_server_refund_aborted_tx_test.go | 26 +- .../keeper/msg_server_vote_outbound_tx.go | 1 - .../keeper/msg_server_whitelist_erc20.go | 10 +- x/crosschain/keeper/refund.go | 4 +- x/crosschain/keeper/refund_test.go | 36 ++- x/crosschain/migrations/v4/migrate.go | 2 +- x/crosschain/migrations/v4/migrate_test.go | 4 +- x/crosschain/migrations/v5/migrate.go | 2 +- x/crosschain/migrations/v5/migrate_test.go | 35 ++- x/crosschain/types/cross_chain_tx.pb.go | 247 ++++++++---------- x/emissions/client/tests/cli_test.go | 13 - .../client/tests/observer_rewards_test.go | 104 -------- x/emissions/client/tests/suite.go | 113 -------- .../msg_server_remove_chain_params_test.go | 5 +- x/observer/keeper/nonce_to_cctx_test.go | 6 +- x/observer/keeper/nonces_test.go | 6 +- x/observer/keeper/observer_set_test.go | 14 +- x/observer/keeper/pending_nonces_test.go | 6 +- x/observer/keeper/tss_funds_migrator_test.go | 4 +- x/observer/keeper/tss_test.go | 24 +- x/observer/keeper/utils_test.go | 6 +- zetaclient/bitcoin/bitcoin_signer.go | 2 +- zetaclient/evm/evm_client.go | 2 +- zetaclient/evm/evm_signer.go | 16 +- .../supplychecker/zeta_supply_checker.go | 2 +- 42 files changed, 287 insertions(+), 588 deletions(-) delete mode 100644 x/emissions/client/tests/cli_test.go delete mode 100644 x/emissions/client/tests/observer_rewards_test.go delete mode 100644 x/emissions/client/tests/suite.go diff --git a/e2e/runner/logger.go b/e2e/runner/logger.go index 3a9ed4827c..91180d5eac 100644 --- a/e2e/runner/logger.go +++ b/e2e/runner/logger.go @@ -122,7 +122,7 @@ func (l *Logger) CCTX(cctx crosschaintypes.CrossChainTx, name string) { l.Info(" TxHeight: %d", cctx.InboundTxParams.InboundTxObservedExternalHeight) l.Info(" BallotIndex: %s", cctx.InboundTxParams.InboundTxBallotIndex) l.Info(" Amount: %s", cctx.InboundTxParams.Amount.String()) - l.Info(" CoinType: %s", cctx.InboundTxParams.CoinType.String()) + l.Info(" CoinType: %s", cctx.InboundTxParams.String()) l.Info(" SenderChainID: %d", cctx.InboundTxParams.SenderChainId) l.Info(" Origin: %s", cctx.InboundTxParams.TxOrigin) if cctx.InboundTxParams.Sender != "" { @@ -151,7 +151,7 @@ func (l *Logger) CCTX(cctx crosschaintypes.CrossChainTx, name string) { l.Info(" EffectiveGasPrice: %s", outTxParam.OutboundTxEffectiveGasPrice.String()) l.Info(" EffectiveGasLimit: %d", outTxParam.OutboundTxEffectiveGasLimit) l.Info(" Amount: %s", outTxParam.Amount.String()) - l.Info(" CoinType: %s", outTxParam.CoinType.String()) + l.Info(" CoinType: %s", outTxParam.String()) l.Info(" Receiver: %s", outTxParam.Receiver) l.Info(" ReceiverChainID: %d", outTxParam.ReceiverChainId) } diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 47495d1a5a..9853e66621 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -26,7 +26,6 @@ message InboundTxParams { string sender = 1; // this address is the immediate contract/EOA that calls the Connector.send() int64 sender_chain_id = 2; string tx_origin = 3; // this address is the EOA that signs the inbound tx - common.CoinType coin_type = 4; string asset = 5; // for ERC20 coin type, the asset is an address of the ERC20 contract string amount = 6 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", @@ -50,7 +49,6 @@ message ZetaAccounting { message OutboundTxParams { string receiver = 1; int64 receiver_chainId = 2; - common.CoinType coin_type = 3; string amount = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", (gogoproto.nullable) = false @@ -93,4 +91,5 @@ message CrossChainTx { InboundTxParams inbound_tx_params = 9; repeated OutboundTxParams outbound_tx_params = 10; uint64 event_index = 11; + common.CoinType coin_type = 12; } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 2e8c98fda6..be45fcbb43 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -42,7 +42,6 @@ func InboundTxParams(r *rand.Rand) *types.InboundTxParams { Sender: EthAddress().String(), SenderChainId: r.Int63(), TxOrigin: EthAddress().String(), - CoinType: common.CoinType(r.Intn(100)), Asset: StringRandom(r, 32), Amount: math.NewUint(uint64(r.Int63())), InboundTxObservedHash: StringRandom(r, 32), @@ -56,7 +55,6 @@ func OutboundTxParams(r *rand.Rand) *types.OutboundTxParams { return &types.OutboundTxParams{ Receiver: EthAddress().String(), ReceiverChainId: r.Int63(), - CoinType: common.CoinType(r.Intn(100)), Amount: math.NewUint(uint64(r.Int63())), OutboundTxTssNonce: r.Uint64(), OutboundTxGasLimit: r.Uint64(), @@ -89,6 +87,7 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { return &types.CrossChainTx{ Creator: AccAddress(), Index: GetCctxIndexFromString(index), + CoinType: common.CoinType(r.Intn(100)), ZetaFees: math.NewUint(uint64(r.Int63())), RelayedMessage: StringRandom(r, 32), CctxStatus: Status(t, index), diff --git a/x/authority/types/message_update_policies_test.go b/x/authority/types/message_update_policies_test.go index 011d1e5d2c..0b03f3acb2 100644 --- a/x/authority/types/message_update_policies_test.go +++ b/x/authority/types/message_update_policies_test.go @@ -10,8 +10,6 @@ import ( ) func TestMsgUpdatePolicies_ValidateBasic(t *testing.T) { - setConfig() - tests := []struct { name string msg *types.MsgUpdatePolicies diff --git a/x/authority/types/policies_test.go b/x/authority/types/policies_test.go index 8d609d377c..11d2f3f1a5 100644 --- a/x/authority/types/policies_test.go +++ b/x/authority/types/policies_test.go @@ -19,7 +19,6 @@ func setConfig() { func TestPolicies_Validate(t *testing.T) { setConfig() - // use table driven tests to test the validation of policies tests := []struct { name string diff --git a/x/crosschain/client/integrationtests/cli_test.go b/x/crosschain/client/integrationtests/cli_test.go index de594398ce..46db24fbae 100644 --- a/x/crosschain/client/integrationtests/cli_test.go +++ b/x/crosschain/client/integrationtests/cli_test.go @@ -3,11 +3,10 @@ package integrationtests import ( "testing" - "github.com/stretchr/testify/suite" "github.com/zeta-chain/zetacore/testutil/network" ) func TestIntegrationTestSuite(t *testing.T) { - cfg := network.DefaultConfig() - suite.Run(t, NewIntegrationTestSuite(cfg)) + _ = network.DefaultConfig() + //suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index eff106d56f..7411d787fd 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -47,7 +47,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ Tss: tss.TssPubkey, }) } - if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.CoinType == common.CoinType_Zeta { k.AddZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) } } diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index 6732ed6795..bf98fc1d30 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -8,6 +8,7 @@ import ( "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/types/query" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/keeper" @@ -15,7 +16,6 @@ import ( "google.golang.org/grpc/status" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -48,7 +48,6 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha SenderChainId: int64(i), TxOrigin: fmt.Sprintf("%d", i), Asset: fmt.Sprintf("%d", i), - CoinType: common.CoinType_Zeta, InboundTxObservedHash: fmt.Sprintf("%d", i), InboundTxObservedExternalHeight: uint64(i), InboundTxFinalizedZetaHeight: uint64(i), @@ -62,7 +61,6 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha OutboundTxGasPrice: fmt.Sprintf("%d", i), OutboundTxBallotIndex: fmt.Sprintf("%d", i), OutboundTxObservedExternalHeight: uint64(i), - CoinType: 0, }} items[i].CctxStatus = &types.Status{ Status: types.CctxStatus_PendingInbound, @@ -73,6 +71,7 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha items[i].ZetaFees = math.OneUint() items[i].Index = fmt.Sprintf("%d", i) + items[i].CoinType = common.CoinType_Zeta keeper.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, items[i]) } return items diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 32568af5a0..4afe6546a0 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -23,10 +23,10 @@ func (k Keeper) GetInbound(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundT if tssFound { tssPub = tss.TssPubkey } - return k.CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) + return CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) } -func (k Keeper) CreateNewCCTX( +func CreateNewCCTX( ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx, index string, @@ -44,7 +44,6 @@ func (k Keeper) CreateNewCCTX( TxOrigin: msg.TxOrigin, Asset: msg.Asset, Amount: msg.Amount, - CoinType: msg.CoinType, InboundTxObservedHash: msg.InTxHash, InboundTxObservedExternalHeight: msg.InBlockHeight, InboundTxFinalizedZetaHeight: 0, @@ -60,7 +59,6 @@ func (k Keeper) CreateNewCCTX( OutboundTxGasPrice: "", OutboundTxBallotIndex: "", OutboundTxObservedExternalHeight: 0, - CoinType: msg.CoinType, // FIXME: is this correct? Amount: sdk.NewUint(0), TssPubkey: tssPubkey, } @@ -79,6 +77,7 @@ func (k Keeper) CreateNewCCTX( InboundTxParams: inboundParams, OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, EventIndex: msg.EventIndex, + CoinType: msg.CoinType, } return newCctx } @@ -127,7 +126,7 @@ func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (ui return 0, nil } - if cctx.InboundTxParams.CoinType == common.CoinType_Gas { + if cctx.CoinType == common.CoinType_Gas { // get the gas limit of the gas token fc, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, cctx.InboundTxParams.SenderChainId) if !found { @@ -138,7 +137,7 @@ func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (ui return 0, errors.Wrap(fungibletypes.ErrContractCall, err.Error()) } return gasLimit.Uint64(), nil - } else if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { + } else if cctx.CoinType == common.CoinType_ERC20 { // get the gas limit of the associated asset fc, found := k.fungibleKeeper.GetForeignCoinFromAsset(ctx, cctx.InboundTxParams.Asset, cctx.InboundTxParams.SenderChainId) if !found { @@ -222,7 +221,6 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { Receiver: cctx.InboundTxParams.Sender, ReceiverChainId: cctx.InboundTxParams.SenderChainId, Amount: cctx.InboundTxParams.Amount, - CoinType: cctx.InboundTxParams.CoinType, OutboundTxGasLimit: gasLimit, } cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) @@ -264,7 +262,6 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { // Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { tmpCtx, commit := ctx.CacheContext() - // Todo : Check receiver vs sender chain id outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId err := func() error { err := k.PayGasAndUpdateCctx( diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 42bea61fe9..ddf7285b15 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -31,9 +31,7 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - }}) + CoinType: common.CoinType_Zeta}) require.NoError(t, err) require.Equal(t, uint64(0), gasLimit) }) @@ -50,8 +48,8 @@ func TestGetRevertGasLimit(t *testing.T) { require.NoError(t, err) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, }}) require.NoError(t, err) @@ -80,8 +78,8 @@ func TestGetRevertGasLimit(t *testing.T) { require.NoError(t, err) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: chainID, Asset: asset, }}) @@ -93,8 +91,8 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: 999999, }}) require.ErrorIs(t, err, types.ErrForeignCoinNotFound) @@ -114,8 +112,8 @@ func TestGetRevertGasLimit(t *testing.T) { // no contract deployed therefore will fail _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, }}) require.ErrorIs(t, err, fungibletypes.ErrContractCall) @@ -125,8 +123,8 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: 999999, }}) require.ErrorIs(t, err, types.ErrForeignCoinNotFound) @@ -148,8 +146,8 @@ func TestGetRevertGasLimit(t *testing.T) { // no contract deployed therefore will fail _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: chainID, Asset: asset, }}) @@ -216,7 +214,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) @@ -241,7 +239,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) @@ -506,10 +504,10 @@ func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.C cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId cctx.GetCurrentOutTxParam().ReceiverChainId = senderChain.ChainId - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.RelayedMessage = "" cctx.GetInboundTxParams().Asset = asset cctx.GetInboundTxParams().Sender = sample.EthAddress().String() diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index 8fbd16ae35..b65974d419 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -24,7 +24,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo inboundAmount := cctx.GetInboundTxParams().Amount.BigInt() inboundSender := cctx.GetInboundTxParams().Sender inboundSenderChainID := cctx.GetInboundTxParams().SenderChainId - inboundCoinType := cctx.GetInboundTxParams().CoinType + inboundCoinType := cctx.CoinType if len(ctx.TxBytes()) > 0 { // add event for tendermint transaction hash format hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index 406ba600de..26bc2d1039 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -34,7 +34,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, @@ -63,7 +63,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, @@ -103,7 +103,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -147,7 +147,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -191,7 +191,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -234,7 +234,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -277,7 +277,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -318,7 +318,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -341,7 +341,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() cctx.GetInboundTxParams().Amount = math.NewUint(42) - cctx.GetInboundTxParams().CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "not_hex" @@ -381,7 +381,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = receiver.Hex()[2:] + "DEADBEEF" @@ -423,7 +423,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "DEADBEEF" diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 9428865463..d4b916d215 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -170,7 +170,7 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W ) sendHash := msg.Digest() - cctx := k.CreateNewCCTX( + cctx := CreateNewCCTX( ctx, msg, sendHash, @@ -205,7 +205,7 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC fungibletypes.ModuleName, sdk.NewCoins(sdk.NewCoin(config.BaseDenom, sdk.NewIntFromBigInt(event.ZetaValueAndGas))), ); err != nil { - fmt.Printf("burn coins failed: %s\n", err.Error()) + ctx.Logger().Error(fmt.Sprintf("ProcessZetaSentEvent: failed to burn coins from fungible: %s", err.Error())) return fmt.Errorf("ProcessZetaSentEvent: failed to burn coins from fungible: %s", err.Error()) } @@ -249,7 +249,7 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC sendHash := msg.Digest() // Create the CCTX - cctx := k.CreateNewCCTX( + cctx := CreateNewCCTX( ctx, msg, sendHash, diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index a085e9cc7d..a7d99dea3d 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -28,7 +28,7 @@ func (k Keeper) PayGasAndUpdateCctx( noEthereumTxEvent bool, ) error { // Dispatch to the correct function based on the coin type - switch cctx.InboundTxParams.CoinType { + switch cctx.CoinType { case common.CoinType_Zeta: return k.PayGasInZetaAndUpdateCctx(ctx, chainID, cctx, inputAmount, noEthereumTxEvent) case common.CoinType_Gas: @@ -37,7 +37,7 @@ func (k Keeper) PayGasAndUpdateCctx( return k.PayGasInERC20AndUpdateCctx(ctx, chainID, cctx, inputAmount, noEthereumTxEvent) default: // can't pay gas with coin type - return fmt.Errorf("can't pay gas with coin type %s", cctx.InboundTxParams.CoinType.String()) + return fmt.Errorf("can't pay gas with coin type %s", cctx.CoinType.String()) } } @@ -90,8 +90,8 @@ func (k Keeper) PayGasNativeAndUpdateCctx( inputAmount math.Uint, ) error { // preliminary checks - if cctx.InboundTxParams.CoinType != common.CoinType_Gas { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in native gas with %s", cctx.InboundTxParams.CoinType.String()) + if cctx.CoinType != common.CoinType_Gas { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in native gas with %s", cctx.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { return observertypes.ErrSupportedChains @@ -137,8 +137,8 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( noEthereumTxEvent bool, ) error { // preliminary checks - if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in erc20 with %s", cctx.InboundTxParams.CoinType.String()) + if cctx.CoinType != common.CoinType_ERC20 { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in erc20 with %s", cctx.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { @@ -262,8 +262,8 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( noEthereumTxEvent bool, ) error { // preliminary checks - if cctx.InboundTxParams.CoinType != common.CoinType_Zeta { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in zeta with %s", cctx.InboundTxParams.CoinType.String()) + if cctx.CoinType != common.CoinType_Zeta { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in zeta with %s", cctx.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { diff --git a/x/crosschain/keeper/gas_payment_test.go b/x/crosschain/keeper/gas_payment_test.go index 8ed31d8a46..e51c75566c 100644 --- a/x/crosschain/keeper/gas_payment_test.go +++ b/x/crosschain/keeper/gas_payment_test.go @@ -46,9 +46,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, - }, + CoinType: zetacommon.CoinType_Gas, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, @@ -72,9 +70,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, - }, + CoinType: zetacommon.CoinType_Zeta, } err := k.PayGasNativeAndUpdateCctx(ctx, chainID, &cctx, math.NewUint(inputAmount)) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -83,9 +79,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, - }, + CoinType: zetacommon.CoinType_Gas, } err := k.PayGasNativeAndUpdateCctx(ctx, 999999, &cctx, math.NewUint(inputAmount)) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -103,9 +97,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, - }, + CoinType: zetacommon.CoinType_Gas, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, @@ -140,8 +132,10 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { }) cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, + SenderChainId: chainID, + Sender: sample.EthAddress().String(), }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -201,9 +195,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - Asset: assetAddress, + Asset: assetAddress, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -233,9 +227,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, - }, + CoinType: zetacommon.CoinType_Zeta, } err := k.PayGasInERC20AndUpdateCctx(ctx, chainID, &cctx, math.NewUint(inputAmount), false) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -244,9 +236,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - }, + CoinType: zetacommon.CoinType_ERC20, } err := k.PayGasInERC20AndUpdateCctx(ctx, 999999, &cctx, math.NewUint(inputAmount), false) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -264,9 +254,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - }, + CoinType: zetacommon.CoinType_ERC20, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, @@ -305,9 +293,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - Asset: assetAddress, + Asset: assetAddress, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -357,9 +345,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - Asset: assetAddress, + Asset: assetAddress, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -415,9 +403,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_ERC20, - Asset: assetAddress, + Asset: assetAddress, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -460,9 +448,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, - }, + CoinType: zetacommon.CoinType_Zeta, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: chainID, @@ -486,9 +472,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // can call with undefined zeta fees cctx = types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, - }, + CoinType: zetacommon.CoinType_Zeta, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: chainID, @@ -511,9 +495,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Gas, - }, + CoinType: zetacommon.CoinType_Gas, } err := k.PayGasInZetaAndUpdateCctx(ctx, chainID, &cctx, math.NewUint(100000), false) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -522,9 +504,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, - }, + CoinType: zetacommon.CoinType_Zeta, } err := k.PayGasInZetaAndUpdateCctx(ctx, 999999, &cctx, math.NewUint(100000), false) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -544,8 +524,10 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_Zeta, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, + SenderChainId: chainID, + Sender: sample.EthAddress().String(), }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -576,8 +558,10 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ + CoinType: zetacommon.CoinType_Zeta, InboundTxParams: &types.InboundTxParams{ - CoinType: zetacommon.CoinType_Zeta, + SenderChainId: chainID, + Sender: sample.EthAddress().String(), }, OutboundTxParams: []*types.OutboundTxParams{ { diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 96db6a964d..afdb656331 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -80,6 +80,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s index := hash.Hex() cctx := types.CrossChainTx{ Creator: "", + CoinType: common.CoinType_Cmd, Index: index, ZetaFees: sdkmath.Uint{}, RelayedMessage: fmt.Sprintf("%s:%s", common.CmdMigrateTssFunds, "Funds Migrator Admin Cmd"), @@ -92,7 +93,6 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s Sender: "", SenderChainId: chainID, TxOrigin: "", - CoinType: common.CoinType_Cmd, Asset: "", Amount: amount, InboundTxObservedHash: tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()).String(), @@ -103,7 +103,6 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s OutboundTxParams: []*types.OutboundTxParams{{ Receiver: "", ReceiverChainId: chainID, - CoinType: common.CoinType_Cmd, Amount: amount, OutboundTxTssNonce: 0, OutboundTxGasLimit: 1_000_000, diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index fc651ec249..c79c6d81ff 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -43,7 +43,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // Check if aborted amount is available to maintain zeta accounting - if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { + if cctx.CoinType == common.CoinType_Zeta { err := k.RemoveZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) // if the zeta accounting is not found, it means the zeta accounting is not set yet and the refund should not be processed if errors.Is(err, types.ErrUnableToFindZetaAccounting) { diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 1c6f7da680..3331bc1e6d 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -55,7 +55,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -94,7 +94,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -133,7 +133,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta cctx.OutboundTxParams = nil k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) @@ -173,7 +173,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -212,7 +212,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_ERC20 + cctx.CoinType = common.CoinType_ERC20 cctx.InboundTxParams.Asset = asset k.SetCrossChainTx(ctx, *cctx) // deploy zrc20 @@ -262,7 +262,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -301,7 +301,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -332,7 +332,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -363,7 +363,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -396,7 +396,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ @@ -425,7 +425,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -456,7 +456,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -486,7 +486,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.InboundTxParams.CoinType = common.CoinType_Gas + cctx.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 870d1e08c5..4450280501 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -163,7 +163,6 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms Receiver: cctx.InboundTxParams.Sender, ReceiverChainId: cctx.InboundTxParams.SenderChainId, Amount: cctx.InboundTxParams.Amount, - CoinType: cctx.InboundTxParams.CoinType, OutboundTxGasLimit: gasLimit, } cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index e269f2312a..e690da980b 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -113,6 +113,7 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist // create a cmd cctx to whitelist the erc20 on the external chain cctx := types.CrossChainTx{ Creator: msg.Creator, + CoinType: common.CoinType_Cmd, Index: index, ZetaFees: sdk.NewUint(0), RelayedMessage: fmt.Sprintf("%s:%s", common.CmdWhitelistERC20, msg.Erc20Address), @@ -122,10 +123,10 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist LastUpdateTimestamp: 0, }, InboundTxParams: &types.InboundTxParams{ - Sender: "", - SenderChainId: 0, - TxOrigin: "", - CoinType: common.CoinType_Cmd, + Sender: "", + SenderChainId: 0, + TxOrigin: "", + Asset: "", Amount: math.Uint{}, InboundTxObservedHash: hash.String(), // all Upper case Cosmos TX HEX, with no 0x prefix @@ -137,7 +138,6 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist { Receiver: param.Erc20CustodyContractAddress, ReceiverChainId: msg.ChainId, - CoinType: common.CoinType_Cmd, Amount: math.NewUint(0), OutboundTxTssNonce: 0, OutboundTxGasLimit: 100_000, diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 9d10b7ce13..b29de2097e 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -12,7 +12,7 @@ import ( ) func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { - coinType := cctx.InboundTxParams.CoinType + coinType := cctx.CoinType switch coinType { case common.CoinType_Gas: return k.RefundAmountOnZetaChainGas(ctx, cctx, refundAddress) @@ -75,7 +75,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { refundAmount := GetAbortedAmount(cctx) // preliminary checks - if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { + if cctx.CoinType != common.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") } if !common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index e9ecfd346f..55cb674574 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -25,8 +25,8 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -52,8 +52,8 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -74,8 +74,8 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { chainID := getValidEthChainID(t) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -99,8 +99,8 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -125,8 +125,8 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -139,7 +139,7 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { sender, ) require.NoError(t, err) - coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) + coin := sdkk.BankKeeper.GetBalance(ctx, sender.Bytes(), config.BaseDenom) fmt.Println(coin.Amount.String()) require.Equal(t, "42", coin.Amount.String()) }) @@ -150,8 +150,8 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -171,8 +171,8 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), @@ -210,8 +210,8 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { ) err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: chainID, Sender: sender.String(), Asset: asset, @@ -232,8 +232,8 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { // can refund again err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: chainID, Sender: sender.String(), Asset: asset, @@ -251,25 +251,23 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_Zeta, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), + Amount: math.NewUint(42), }}, sample.EthAddress(), ) require.ErrorContains(t, err, "unsupported coin type") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Gas, - }}, + CoinType: common.CoinType_Gas}, sample.EthAddress(), ) require.ErrorContains(t, err, "unsupported coin type") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: 999999, Amount: math.NewUint(42), }}, @@ -278,8 +276,8 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { require.ErrorContains(t, err, "only EVM chains are supported") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Amount: math.Uint{}, @@ -289,8 +287,8 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { require.ErrorContains(t, err, "no amount to refund") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Amount: math.ZeroUint(), @@ -301,8 +299,8 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { // the foreign coin has not been set err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Asset: sample.EthAddress().String(), diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index e4b368e44c..5a421c9d55 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -54,7 +54,7 @@ func SetZetaAccounting( for ; iterator.Valid(); iterator.Next() { var val types.CrossChainTx cdc.MustUnmarshal(iterator.Value(), &val) - if val.CctxStatus.Status == types.CctxStatus_Aborted && val.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if val.CctxStatus.Status == types.CctxStatus_Aborted && val.CoinType == common.CoinType_Zeta { abortedAmountZeta = abortedAmountZeta.Add(val.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/migrations/v4/migrate_test.go b/x/crosschain/migrations/v4/migrate_test.go index d377f1a6fa..67113b9c0a 100644 --- a/x/crosschain/migrations/v4/migrate_test.go +++ b/x/crosschain/migrations/v4/migrate_test.go @@ -167,10 +167,10 @@ func SetRandomCctx(ctx sdk.Context, k keeper.Keeper) sdkmath.Uint { amount := sdkmath.NewUint(uint64(r.Uint32())) k.SetCrossChainTx(ctx, types.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_Zeta, CctxStatus: &types.Status{Status: types.CctxStatus_Aborted}, OutboundTxParams: []*types.OutboundTxParams{{ - Amount: amount, - CoinType: common.CoinType_Zeta, + Amount: amount, }}, }) totalZeta = totalZeta.Add(amount) diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index 27ceba92cc..cc29a265e6 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -93,7 +93,7 @@ func SetZetaAccounting( for _, cctx := range ccctxList { if cctx.CctxStatus.Status == types.CctxStatus_Aborted { - switch cctx.InboundTxParams.CoinType { + switch cctx.CoinType { case common.CoinType_ERC20: { receiverChain := observerKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go index 62169c0431..884777d626 100644 --- a/x/crosschain/migrations/v5/migrate_test.go +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -24,7 +24,7 @@ func TestMigrateStore(t *testing.T) { v4ZetaAccountingAmount := math.ZeroUint() for _, cctx := range cctxList { k.SetCrossChainTx(ctx, cctx) - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.GetCurrentOutTxParam().CoinType != common.CoinType_Zeta { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.CoinType != common.CoinType_Zeta { continue } v5ZetaAccountingAmount = v5ZetaAccountingAmount.Add(crosschainkeeper.GetAbortedAmount(cctx)) @@ -44,7 +44,7 @@ func TestMigrateStore(t *testing.T) { cctxListUpdated := k.GetAllCrossChainTx(ctx) // Check refund status of the cctx for _, cctx := range cctxListUpdated { - switch cctx.InboundTxParams.CoinType { + switch cctx.CoinType { case common.CoinType_ERC20: receiverChain := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) require.NotNil(t, receiverChain) @@ -180,28 +180,26 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_Zeta, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount.Add(math.NewUint(uint64(r.Uint32()))), - CoinType: common.CoinType_Zeta, + Amount: amount.Add(math.NewUint(uint64(r.Uint32()))), }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ - Amount: amount, - CoinType: common.CoinType_Zeta, + Amount: amount, }}, } for ; i < count; i++ { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_Zeta, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, - CoinType: common.CoinType_Zeta, + Amount: amount, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ - Amount: math.ZeroUint(), - CoinType: common.CoinType_Zeta, + Amount: math.ZeroUint(), }}, } } @@ -209,14 +207,13 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_ERC20, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, - CoinType: common.CoinType_ERC20, + Amount: amount, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ Amount: math.ZeroUint(), - CoinType: common.CoinType_ERC20, ReceiverChainId: common.ZetaPrivnetChain().ChainId, }}, } @@ -225,14 +222,13 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_ERC20, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, - CoinType: common.CoinType_ERC20, + Amount: amount, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ Amount: math.ZeroUint(), - CoinType: common.CoinType_ERC20, ReceiverChainId: common.GoerliLocalnetChain().ChainId, }}, } @@ -241,14 +237,13 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), + CoinType: common.CoinType_Gas, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, - CoinType: common.CoinType_Gas, + Amount: amount, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ - Amount: amount, - CoinType: common.CoinType_Gas, + Amount: amount, }}, } } diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index dd539f0f25..c0a76dba6a 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -95,7 +95,6 @@ type InboundTxParams struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` SenderChainId int64 `protobuf:"varint,2,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` TxOrigin string `protobuf:"bytes,3,opt,name=tx_origin,json=txOrigin,proto3" json:"tx_origin,omitempty"` - CoinType common.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` Asset string `protobuf:"bytes,5,opt,name=asset,proto3" json:"asset,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` InboundTxObservedHash string `protobuf:"bytes,7,opt,name=inbound_tx_observed_hash,json=inboundTxObservedHash,proto3" json:"inbound_tx_observed_hash,omitempty"` @@ -159,13 +158,6 @@ func (m *InboundTxParams) GetTxOrigin() string { return "" } -func (m *InboundTxParams) GetCoinType() common.CoinType { - if m != nil { - return m.CoinType - } - return common.CoinType_Zeta -} - func (m *InboundTxParams) GetAsset() string { if m != nil { return m.Asset @@ -249,7 +241,6 @@ var xxx_messageInfo_ZetaAccounting proto.InternalMessageInfo type OutboundTxParams struct { Receiver string `protobuf:"bytes,1,opt,name=receiver,proto3" json:"receiver,omitempty"` ReceiverChainId int64 `protobuf:"varint,2,opt,name=receiver_chainId,json=receiverChainId,proto3" json:"receiver_chainId,omitempty"` - CoinType common.CoinType `protobuf:"varint,3,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,4,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` OutboundTxTssNonce uint64 `protobuf:"varint,5,opt,name=outbound_tx_tss_nonce,json=outboundTxTssNonce,proto3" json:"outbound_tx_tss_nonce,omitempty"` OutboundTxGasLimit uint64 `protobuf:"varint,6,opt,name=outbound_tx_gas_limit,json=outboundTxGasLimit,proto3" json:"outbound_tx_gas_limit,omitempty"` @@ -313,13 +304,6 @@ func (m *OutboundTxParams) GetReceiverChainId() int64 { return 0 } -func (m *OutboundTxParams) GetCoinType() common.CoinType { - if m != nil { - return m.CoinType - } - return common.CoinType_Zeta -} - func (m *OutboundTxParams) GetOutboundTxTssNonce() uint64 { if m != nil { return m.OutboundTxTssNonce @@ -467,6 +451,7 @@ type CrossChainTx struct { InboundTxParams *InboundTxParams `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` OutboundTxParams []*OutboundTxParams `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` EventIndex uint64 `protobuf:"varint,11,opt,name=event_index,json=eventIndex,proto3" json:"event_index,omitempty"` + CoinType common.CoinType `protobuf:"varint,12,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -551,6 +536,13 @@ func (m *CrossChainTx) GetEventIndex() uint64 { return 0 } +func (m *CrossChainTx) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) @@ -564,78 +556,78 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1135 bytes of a gzipped FileDescriptorProto + // 1132 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, - 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, - 0x12, 0x25, 0x40, 0x24, 0xc4, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0x8d, 0x13, 0x23, 0x3f, 0x36, 0xb6, - 0xf6, 0xc5, 0x40, 0xb1, 0xa5, 0x76, 0xc7, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, - 0x10, 0x3d, 0xf4, 0x11, 0x7a, 0xe8, 0xa3, 0xe4, 0xd6, 0x1c, 0x8b, 0x1e, 0x8c, 0xc2, 0x3e, 0xe7, - 0xd2, 0x27, 0x28, 0x48, 0xee, 0x4a, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, 0x9b, - 0x21, 0xe7, 0x1b, 0x72, 0xa1, 0xe6, 0x47, 0x5c, 0x08, 0xbf, 0x47, 0x59, 0xd8, 0xd6, 0xa6, 0xa7, - 0x6d, 0x4f, 0x8e, 0x5b, 0xc3, 0x88, 0x4b, 0x4e, 0xee, 0xbc, 0x43, 0x49, 0xb5, 0xaf, 0xa5, 0x2d, - 0x1e, 0x61, 0x6b, 0x8a, 0x59, 0x5d, 0xf6, 0xf9, 0x60, 0xc0, 0xc3, 0xb6, 0xf9, 0x18, 0xcc, 0x6a, - 0xa5, 0xcb, 0xbb, 0x5c, 0x9b, 0x6d, 0x65, 0x19, 0x6f, 0xe3, 0x63, 0x0e, 0xca, 0xdb, 0x61, 0x87, - 0x8f, 0xc2, 0x60, 0x6f, 0xbc, 0x4b, 0x23, 0x3a, 0x10, 0xe4, 0x16, 0xe4, 0x05, 0x86, 0x01, 0x46, - 0x8e, 0x55, 0xb7, 0x9a, 0x45, 0x37, 0x1e, 0x91, 0x7b, 0x50, 0x36, 0x56, 0x9c, 0x0e, 0x0b, 0x9c, - 0x1b, 0x75, 0xab, 0x99, 0x75, 0x17, 0x8c, 0x7b, 0x53, 0x79, 0xb7, 0x03, 0x72, 0x1b, 0x8a, 0x72, - 0xec, 0xf1, 0x88, 0x75, 0x59, 0xe8, 0x64, 0x35, 0x45, 0x41, 0x8e, 0x77, 0xf4, 0x98, 0x3c, 0x82, - 0xa2, 0xcf, 0xd5, 0x5e, 0x8e, 0x87, 0xe8, 0xe4, 0xea, 0x56, 0x73, 0x71, 0xcd, 0x6e, 0xc5, 0x89, - 0x6e, 0x72, 0x16, 0xee, 0x1d, 0x0f, 0xd1, 0x2d, 0xf8, 0xb1, 0x45, 0x2a, 0x70, 0x93, 0x0a, 0x81, - 0xd2, 0xb9, 0xa9, 0x79, 0xcc, 0x80, 0x3c, 0x87, 0x3c, 0x1d, 0xf0, 0x51, 0x28, 0x9d, 0xbc, 0x72, - 0x6f, 0xb4, 0xdf, 0x9f, 0xd4, 0x32, 0xbf, 0x9d, 0xd4, 0xee, 0x77, 0x99, 0xec, 0x8d, 0x3a, 0x8a, - 0xaf, 0xed, 0x73, 0x31, 0xe0, 0x22, 0xfe, 0x3c, 0x12, 0xc1, 0xdb, 0xb6, 0x0a, 0x29, 0x5a, 0xfb, - 0x2c, 0x94, 0x6e, 0x0c, 0x27, 0x4f, 0xc1, 0x61, 0x66, 0xf7, 0x9e, 0x4a, 0xb9, 0x23, 0x30, 0x3a, - 0xc2, 0xc0, 0xeb, 0x51, 0xd1, 0x73, 0xe6, 0x74, 0xc4, 0x15, 0x96, 0x9c, 0xce, 0x4e, 0x3c, 0xfb, - 0x82, 0x8a, 0x1e, 0x79, 0x05, 0x9f, 0x5d, 0x04, 0xc4, 0xb1, 0xc4, 0x28, 0xa4, 0x7d, 0xaf, 0x87, - 0xac, 0xdb, 0x93, 0x4e, 0xa1, 0x6e, 0x35, 0x73, 0x6e, 0xed, 0x2f, 0x1c, 0xcf, 0xe2, 0x75, 0x2f, - 0xf4, 0x32, 0xf2, 0x05, 0x7c, 0x92, 0x62, 0xeb, 0xd0, 0x7e, 0x9f, 0x4b, 0x8f, 0x85, 0x01, 0x8e, - 0x9d, 0xa2, 0xce, 0xa2, 0x32, 0x61, 0xd8, 0xd0, 0x93, 0xdb, 0x6a, 0x8e, 0x6c, 0x41, 0x3d, 0x05, - 0x3b, 0x64, 0x21, 0xed, 0xb3, 0x77, 0x18, 0x78, 0x4a, 0x13, 0x49, 0x06, 0xa0, 0x33, 0xf8, 0x74, - 0x82, 0xdf, 0x4a, 0x56, 0x1d, 0xa0, 0xa4, 0x71, 0x78, 0x06, 0xb7, 0xa6, 0x78, 0x2a, 0x19, 0x0f, - 0x3d, 0x21, 0xa9, 0x1c, 0x09, 0xa7, 0xa4, 0x0b, 0xf4, 0xa4, 0x75, 0xa5, 0xde, 0x5a, 0x13, 0x56, - 0x8d, 0xfd, 0x5a, 0x43, 0xdd, 0x8a, 0xbc, 0xc0, 0xdb, 0xf8, 0x0e, 0x16, 0x55, 0xe0, 0x75, 0xdf, - 0x57, 0xe7, 0xcf, 0xc2, 0x2e, 0xf1, 0x60, 0x99, 0x76, 0x78, 0x24, 0x93, 0xbc, 0xe3, 0xc2, 0x5a, - 0xff, 0xae, 0xb0, 0x4b, 0x31, 0x97, 0x0e, 0xa2, 0x99, 0x1a, 0x3f, 0xce, 0x81, 0xbd, 0x33, 0x92, - 0xe7, 0x35, 0xbe, 0x0a, 0x85, 0x08, 0x7d, 0x64, 0x47, 0x13, 0x95, 0x4f, 0xc6, 0xe4, 0x01, 0xd8, - 0x89, 0x6d, 0x94, 0xbe, 0x9d, 0x08, 0xbd, 0x9c, 0xf8, 0x13, 0xa9, 0x9f, 0x53, 0x73, 0xf6, 0x5a, - 0x35, 0x4f, 0x75, 0x9b, 0xfb, 0x6f, 0xba, 0x7d, 0x0c, 0x2b, 0x3c, 0xde, 0x92, 0x2a, 0xbd, 0x14, - 0xc2, 0x0b, 0x79, 0xe8, 0xa3, 0x6e, 0x93, 0x9c, 0x4b, 0xf8, 0x64, 0xbf, 0x7b, 0x42, 0xbc, 0x51, - 0x33, 0xb3, 0x90, 0x2e, 0x15, 0x5e, 0x9f, 0x0d, 0x98, 0x69, 0xa1, 0x73, 0x90, 0xe7, 0x54, 0xbc, - 0x52, 0x33, 0x17, 0x41, 0x86, 0x11, 0xf3, 0x31, 0x6e, 0x8d, 0xf3, 0x90, 0x5d, 0x35, 0x43, 0x9a, - 0x60, 0xa7, 0x21, 0xba, 0x91, 0x0a, 0x7a, 0xf5, 0xe2, 0x74, 0xb5, 0xee, 0xa0, 0xa7, 0xe0, 0xa4, - 0x57, 0x5e, 0x20, 0xfa, 0x95, 0x29, 0x22, 0xad, 0xfa, 0x37, 0xf0, 0x79, 0x1a, 0x78, 0x69, 0xef, - 0x19, 0xe5, 0xd7, 0xa7, 0x24, 0x97, 0x34, 0x5f, 0x1b, 0x2a, 0xb3, 0xbb, 0x1c, 0x09, 0x0c, 0x9c, - 0x8a, 0xc6, 0x2f, 0x9d, 0xdb, 0xe4, 0xbe, 0xc0, 0x80, 0x48, 0xa8, 0xa5, 0x01, 0x78, 0x78, 0x88, - 0xbe, 0x64, 0x47, 0x98, 0x3a, 0xa0, 0x15, 0x5d, 0xde, 0x56, 0x5c, 0xde, 0x7b, 0x7f, 0xa3, 0xbc, - 0xdb, 0xa1, 0x74, 0x6f, 0x4f, 0x63, 0x3d, 0x4b, 0x48, 0x27, 0x27, 0xfb, 0xd5, 0x55, 0x51, 0x4d, - 0x25, 0x6f, 0xe9, 0x8c, 0x2f, 0x61, 0x31, 0x25, 0xbd, 0x03, 0xa0, 0xc4, 0x32, 0x1c, 0x75, 0xde, - 0xe2, 0xb1, 0x6e, 0xef, 0xa2, 0x5b, 0x94, 0x42, 0xec, 0x6a, 0xc7, 0x15, 0x37, 0xc1, 0xfc, 0xff, - 0x7d, 0x13, 0xfc, 0x62, 0x41, 0xde, 0x98, 0x64, 0x1d, 0xf2, 0x71, 0x14, 0x4b, 0x47, 0x79, 0x70, - 0x4d, 0x94, 0x4d, 0x5f, 0x8e, 0x63, 0xee, 0x18, 0x48, 0xee, 0xc2, 0xa2, 0xb1, 0xbc, 0x01, 0x0a, - 0x41, 0xbb, 0xa8, 0x3b, 0xb6, 0xe8, 0x2e, 0x18, 0xef, 0x6b, 0xe3, 0x24, 0x8f, 0xa1, 0xd2, 0xa7, - 0x42, 0xee, 0x0f, 0x03, 0x2a, 0xd1, 0x93, 0x6c, 0x80, 0x42, 0xd2, 0xc1, 0x50, 0xb7, 0x6e, 0xd6, - 0x5d, 0x9e, 0xce, 0xed, 0x25, 0x53, 0xa4, 0x09, 0x65, 0x26, 0xd6, 0xd5, 0xad, 0xe2, 0xe2, 0xe1, - 0x28, 0x0c, 0x30, 0xd0, 0xcd, 0x5b, 0x70, 0x67, 0xdd, 0x8d, 0x8f, 0x59, 0x98, 0xdf, 0x54, 0x59, - 0xea, 0xdb, 0x61, 0x6f, 0x4c, 0x1c, 0x98, 0xf3, 0x23, 0xa4, 0x92, 0x27, 0x77, 0x4c, 0x32, 0x54, - 0xcf, 0x9a, 0x51, 0xba, 0xc9, 0xd2, 0x0c, 0xc8, 0xb7, 0x50, 0xd4, 0x57, 0xe0, 0x21, 0xa2, 0x30, - 0x0f, 0xde, 0xc6, 0xe6, 0x3f, 0xbc, 0x21, 0xfe, 0x38, 0xa9, 0xd9, 0xc7, 0x74, 0xd0, 0xff, 0xb2, - 0x31, 0x61, 0x6a, 0xb8, 0x05, 0x65, 0x6f, 0x21, 0x0a, 0x72, 0x1f, 0xca, 0x11, 0xf6, 0xe9, 0x31, - 0x06, 0x93, 0x73, 0xca, 0x9b, 0xee, 0x8c, 0xdd, 0xc9, 0x41, 0x6d, 0x41, 0xc9, 0xf7, 0xe5, 0x38, - 0xa9, 0xbe, 0x6a, 0xe1, 0xd2, 0xda, 0xdd, 0x6b, 0xea, 0x12, 0xd7, 0x04, 0xfc, 0x49, 0x7d, 0xc8, - 0x01, 0x2c, 0xa5, 0x9e, 0xa8, 0xa1, 0xbe, 0x7c, 0x75, 0x7b, 0x97, 0xd6, 0x5a, 0xd7, 0xb0, 0xcd, - 0xfc, 0x96, 0xb8, 0x65, 0x36, 0xf3, 0x9f, 0xf2, 0x0d, 0x90, 0x74, 0x47, 0xc4, 0xe4, 0x50, 0xcf, - 0x36, 0x4b, 0x6b, 0xed, 0x6b, 0xc8, 0x67, 0x1f, 0x04, 0xd7, 0xe6, 0xb3, 0x4f, 0x44, 0x0d, 0x4a, - 0x78, 0x84, 0x61, 0x72, 0x27, 0x95, 0x74, 0x73, 0x81, 0x76, 0xe9, 0x8b, 0xe8, 0xe1, 0xf7, 0x00, - 0x53, 0x25, 0x12, 0x02, 0x8b, 0xbb, 0x18, 0x06, 0x2c, 0xec, 0xc6, 0x89, 0xdb, 0x19, 0xb2, 0x0c, - 0xe5, 0xd8, 0x97, 0xc4, 0xb3, 0x2d, 0xb2, 0x04, 0x0b, 0xc9, 0xe8, 0x35, 0x0b, 0x31, 0xb0, 0xb3, - 0xca, 0x15, 0xaf, 0x73, 0xf1, 0x08, 0x23, 0x69, 0xe7, 0xc8, 0x3c, 0x14, 0x8c, 0x8d, 0x81, 0x7d, - 0x93, 0x94, 0x60, 0x6e, 0xdd, 0x3c, 0x6c, 0x76, 0x7e, 0x35, 0xf7, 0xf3, 0x4f, 0x55, 0xeb, 0xe1, - 0x4b, 0xa8, 0x5c, 0xd4, 0x6d, 0xc4, 0x86, 0xf9, 0x37, 0x5c, 0x4e, 0x9e, 0x79, 0x3b, 0x43, 0x16, - 0xa0, 0x38, 0x1d, 0x5a, 0x8a, 0xf9, 0xd9, 0x18, 0xfd, 0x91, 0x22, 0xbb, 0x61, 0xc8, 0x36, 0x5e, - 0xbe, 0x3f, 0xad, 0x5a, 0x1f, 0x4e, 0xab, 0xd6, 0xef, 0xa7, 0x55, 0xeb, 0x87, 0xb3, 0x6a, 0xe6, - 0xc3, 0x59, 0x35, 0xf3, 0xeb, 0x59, 0x35, 0x73, 0xf0, 0x38, 0x25, 0x3c, 0x75, 0x90, 0x8f, 0xcc, - 0x6f, 0x69, 0x72, 0xa6, 0xed, 0x71, 0x3b, 0xf5, 0xb3, 0xaa, 0x75, 0xd8, 0xc9, 0xeb, 0x5f, 0xcb, - 0x27, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x87, 0xc1, 0xc0, 0x30, 0xc7, 0x0a, 0x00, 0x00, + 0x10, 0xd6, 0xc6, 0x8a, 0x22, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, + 0x12, 0x25, 0x40, 0x24, 0xc4, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0x8d, 0x13, 0x23, 0x89, 0x6d, 0x6c, + 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0x8e, 0x25, 0x22, 0xd2, 0x52, 0x5d, 0x52, 0x86, 0x14, 0xf4, + 0x21, 0xfa, 0x00, 0x3d, 0xf6, 0xd0, 0xa7, 0xe8, 0x39, 0xb7, 0xe6, 0x58, 0xf4, 0x60, 0x14, 0x36, + 0xfa, 0x02, 0x7d, 0x82, 0x62, 0x49, 0xae, 0xb4, 0x56, 0xfd, 0xd3, 0xbf, 0xd3, 0x0e, 0x87, 0xfc, + 0x86, 0xb3, 0x9c, 0xef, 0x1b, 0x12, 0xaa, 0x7e, 0xc4, 0x85, 0xf0, 0xbb, 0x94, 0x85, 0x2d, 0x65, + 0x7a, 0xca, 0xf6, 0xe4, 0xa8, 0x39, 0x88, 0xb8, 0xe4, 0xe4, 0xee, 0x3b, 0x94, 0x54, 0xf9, 0x9a, + 0xca, 0xe2, 0x11, 0x36, 0xa7, 0x98, 0xd5, 0x65, 0x9f, 0xf7, 0xfb, 0x3c, 0x6c, 0xe9, 0x8f, 0xc6, + 0xac, 0x96, 0x3b, 0xbc, 0xc3, 0x95, 0xd9, 0x8a, 0x2d, 0xed, 0xad, 0xff, 0x94, 0x85, 0xd2, 0x76, + 0xd8, 0xe6, 0xc3, 0x30, 0xd8, 0x1f, 0xed, 0xd1, 0x88, 0xf6, 0x05, 0xb9, 0x0d, 0x39, 0x81, 0x61, + 0x80, 0x91, 0x63, 0xd5, 0xac, 0x46, 0xc1, 0x35, 0x23, 0x72, 0x1f, 0x4a, 0xda, 0x32, 0xe9, 0xb0, + 0xc0, 0xb9, 0x51, 0xb3, 0x1a, 0x73, 0xee, 0x82, 0x76, 0x6f, 0xc6, 0xde, 0xed, 0x80, 0xdc, 0x81, + 0x82, 0x1c, 0x79, 0x3c, 0x62, 0x1d, 0x16, 0x3a, 0x73, 0x2a, 0x44, 0x5e, 0x8e, 0x76, 0xd5, 0x98, + 0x94, 0xe1, 0x26, 0x15, 0x02, 0xa5, 0x73, 0x53, 0x4d, 0xe8, 0x01, 0x79, 0x01, 0x39, 0xda, 0xe7, + 0xc3, 0x50, 0x3a, 0xb9, 0xd8, 0xbd, 0xd1, 0x7a, 0x7f, 0x52, 0xcd, 0xfc, 0x7a, 0x52, 0x7d, 0xd0, + 0x61, 0xb2, 0x3b, 0x6c, 0x37, 0x7d, 0xde, 0x6f, 0xf9, 0x5c, 0xf4, 0xb9, 0x30, 0x9f, 0xc7, 0x22, + 0x78, 0xdb, 0x92, 0xe3, 0x01, 0x8a, 0xe6, 0x01, 0x0b, 0xa5, 0x6b, 0xe0, 0xe4, 0x19, 0x38, 0x4c, + 0xff, 0x8e, 0x17, 0xe7, 0xd0, 0x16, 0x18, 0x1d, 0x63, 0xe0, 0x75, 0xa9, 0xe8, 0x3a, 0xb7, 0xd4, + 0x8e, 0x2b, 0x2c, 0xf9, 0xdd, 0x5d, 0x33, 0xfb, 0x92, 0x8a, 0x2e, 0x79, 0x0d, 0x9f, 0x5c, 0x04, + 0xc4, 0x91, 0xc4, 0x28, 0xa4, 0x3d, 0xaf, 0x8b, 0xac, 0xd3, 0x95, 0x4e, 0xbe, 0x66, 0x35, 0xb2, + 0x6e, 0xf5, 0x2f, 0x31, 0x9e, 0x9b, 0x75, 0x2f, 0xd5, 0x32, 0xf2, 0x19, 0x7c, 0x94, 0x8a, 0xd6, + 0xa6, 0xbd, 0x1e, 0x97, 0x1e, 0x0b, 0x03, 0x1c, 0x39, 0x05, 0x95, 0x45, 0x79, 0x12, 0x61, 0x43, + 0x4d, 0x6e, 0xc7, 0x73, 0x64, 0x0b, 0x6a, 0x29, 0xd8, 0x11, 0x0b, 0x69, 0x8f, 0xbd, 0xc3, 0xc0, + 0x8b, 0x8b, 0x9c, 0x64, 0x00, 0x2a, 0x83, 0x8f, 0x27, 0xf8, 0xad, 0x64, 0xd5, 0x21, 0x4a, 0x6a, + 0xb6, 0x67, 0x70, 0x7b, 0x8a, 0xa7, 0x92, 0xf1, 0xd0, 0x13, 0x92, 0xca, 0xa1, 0x70, 0x8a, 0x35, + 0xab, 0xb1, 0xb8, 0xf6, 0xb4, 0x79, 0x25, 0x81, 0x9a, 0x93, 0xa8, 0x0a, 0xfb, 0xa5, 0x82, 0xba, + 0x65, 0x79, 0x81, 0xb7, 0xfe, 0x0d, 0x2c, 0xc6, 0x1b, 0xaf, 0xfb, 0x7e, 0x7c, 0xfe, 0x2c, 0xec, + 0x10, 0x0f, 0x96, 0x69, 0x9b, 0x47, 0x32, 0xc9, 0xdb, 0x14, 0xd6, 0xfa, 0x77, 0x85, 0x5d, 0x32, + 0xb1, 0xd4, 0x26, 0x2a, 0x52, 0xfd, 0xf7, 0x1c, 0xd8, 0xbb, 0x43, 0x79, 0x9e, 0xb4, 0xab, 0x90, + 0x8f, 0xd0, 0x47, 0x76, 0x3c, 0xa1, 0xed, 0x64, 0x4c, 0x1e, 0x82, 0x9d, 0xd8, 0x9a, 0xba, 0xdb, + 0x09, 0x73, 0x4b, 0x89, 0x3f, 0xe1, 0xee, 0x94, 0x88, 0xd9, 0xff, 0x46, 0xc4, 0x27, 0xb0, 0xc2, + 0x4d, 0x8e, 0x71, 0x2d, 0xa5, 0x10, 0x5e, 0xc8, 0x43, 0x1f, 0x15, 0xef, 0xb3, 0x2e, 0xe1, 0x93, + 0x1f, 0xd8, 0x17, 0x62, 0x27, 0x9e, 0x99, 0x85, 0x74, 0xa8, 0xf0, 0x7a, 0xac, 0xcf, 0xb4, 0x26, + 0xce, 0x41, 0x5e, 0x50, 0xf1, 0x3a, 0x9e, 0xb9, 0x08, 0x32, 0x88, 0x98, 0x8f, 0x86, 0xeb, 0xe7, + 0x21, 0x7b, 0xf1, 0x0c, 0x69, 0x80, 0x9d, 0x86, 0x28, 0x65, 0xe4, 0xd5, 0xea, 0xc5, 0xe9, 0x6a, + 0x25, 0x89, 0x67, 0xe0, 0xa4, 0x57, 0x5e, 0xc0, 0xe2, 0x95, 0x29, 0x22, 0x4d, 0xe3, 0x1d, 0xf8, + 0x34, 0x0d, 0xbc, 0x54, 0x4c, 0x9a, 0xca, 0xb5, 0x69, 0x90, 0x4b, 0xd4, 0xd4, 0x82, 0xf2, 0xec, + 0x5f, 0x0e, 0x05, 0x06, 0x4e, 0x59, 0xe1, 0x97, 0xce, 0xfd, 0xe4, 0x81, 0xc0, 0x80, 0x48, 0xa8, + 0xa6, 0x01, 0x78, 0x74, 0x84, 0xbe, 0x64, 0xc7, 0x98, 0x3a, 0xa0, 0x15, 0x55, 0xde, 0xa6, 0x29, + 0xef, 0xfd, 0xbf, 0x51, 0xde, 0xed, 0x50, 0xba, 0x77, 0xa6, 0x7b, 0x3d, 0x4f, 0x82, 0x4e, 0x4e, + 0xf6, 0x8b, 0xab, 0x76, 0xd5, 0x95, 0xbc, 0xad, 0x32, 0xbe, 0x24, 0x8a, 0x2e, 0xe9, 0x5d, 0x80, + 0x98, 0x2c, 0x83, 0x61, 0xfb, 0x2d, 0x8e, 0x95, 0x5e, 0x0b, 0x6e, 0x41, 0x0a, 0xb1, 0xa7, 0x1c, + 0x57, 0x48, 0x7b, 0xfe, 0xff, 0x96, 0xf6, 0xcf, 0x16, 0xe4, 0xb4, 0x49, 0xd6, 0x21, 0x67, 0x76, + 0xb1, 0xd4, 0x2e, 0x0f, 0xaf, 0xd9, 0x65, 0xd3, 0x97, 0x23, 0x13, 0xdb, 0x00, 0xc9, 0x3d, 0x58, + 0xd4, 0x96, 0xd7, 0x47, 0x21, 0x68, 0x07, 0x95, 0x04, 0x0b, 0xee, 0x82, 0xf6, 0xbe, 0xd1, 0x4e, + 0xf2, 0x04, 0xca, 0x3d, 0x2a, 0xe4, 0xc1, 0x20, 0xa0, 0x12, 0x3d, 0xc9, 0xfa, 0x28, 0x24, 0xed, + 0x0f, 0xd4, 0x3d, 0x32, 0xe7, 0x2e, 0x4f, 0xe7, 0xf6, 0x93, 0x29, 0xd2, 0x80, 0x12, 0x13, 0xeb, + 0x71, 0x9b, 0x70, 0xf1, 0x68, 0x18, 0x06, 0x18, 0x28, 0xf1, 0xe6, 0xdd, 0x59, 0x77, 0xfd, 0xfb, + 0x2c, 0xcc, 0x6f, 0xc6, 0x59, 0x2a, 0xb9, 0xef, 0x8f, 0x88, 0x03, 0xb7, 0xfc, 0x08, 0xa9, 0xe4, + 0x49, 0xd3, 0x48, 0x86, 0xf1, 0x3d, 0xa5, 0x99, 0xae, 0xb3, 0xd4, 0x03, 0xf2, 0x35, 0x14, 0x54, + 0x4f, 0x3b, 0x42, 0x14, 0xfa, 0x06, 0xdb, 0xd8, 0xfc, 0x87, 0x1d, 0xe2, 0x8f, 0x93, 0xaa, 0x3d, + 0xa6, 0xfd, 0xde, 0xe7, 0xf5, 0x49, 0xa4, 0xba, 0x9b, 0x8f, 0xed, 0x2d, 0x44, 0x41, 0x1e, 0x40, + 0x29, 0xc2, 0x1e, 0x1d, 0x63, 0x30, 0x39, 0xa7, 0x9c, 0x56, 0xa7, 0x71, 0x27, 0x07, 0xb5, 0x05, + 0x45, 0xdf, 0x97, 0xa3, 0xa4, 0xfa, 0xb1, 0x84, 0x8b, 0x6b, 0xf7, 0xae, 0xa9, 0x8b, 0xa9, 0x09, + 0xf8, 0x93, 0xfa, 0x90, 0x43, 0x58, 0x4a, 0xdd, 0x39, 0x03, 0xd5, 0x4d, 0x95, 0xbc, 0x8b, 0x6b, + 0xcd, 0x6b, 0xa2, 0xcd, 0x3c, 0x1c, 0xdc, 0x12, 0x9b, 0x79, 0x49, 0x7c, 0x05, 0x24, 0xad, 0x08, + 0x13, 0x1c, 0x6a, 0x73, 0x8d, 0xe2, 0x5a, 0xeb, 0x9a, 0xe0, 0xb3, 0x1d, 0xde, 0xb5, 0xf9, 0x6c, + 0xcf, 0xaf, 0x42, 0x11, 0x8f, 0x31, 0x4c, 0x7a, 0x52, 0x51, 0x89, 0x0b, 0x94, 0x4b, 0x37, 0xa2, + 0xc7, 0x50, 0xf0, 0x79, 0xfc, 0x70, 0x1a, 0x0f, 0xd0, 0xe8, 0xc3, 0x6e, 0x9a, 0x57, 0xd1, 0x26, + 0x67, 0xe1, 0xfe, 0x78, 0x80, 0x6e, 0xde, 0x37, 0xd6, 0xa3, 0x6f, 0x01, 0xa6, 0xc4, 0x25, 0x04, + 0x16, 0xf7, 0x30, 0x0c, 0x58, 0xd8, 0x31, 0xff, 0x69, 0x67, 0xc8, 0x32, 0x94, 0x8c, 0x2f, 0x49, + 0xcf, 0xb6, 0xc8, 0x12, 0x2c, 0x24, 0xa3, 0x37, 0x2c, 0xc4, 0xc0, 0x9e, 0x8b, 0x5d, 0x66, 0x9d, + 0x8b, 0xc7, 0x18, 0x49, 0x3b, 0x4b, 0xe6, 0x21, 0xaf, 0x6d, 0x0c, 0xec, 0x9b, 0xa4, 0x08, 0xb7, + 0xd6, 0xf5, 0xc5, 0x66, 0xe7, 0x56, 0xb3, 0x3f, 0xfe, 0x50, 0xb1, 0x1e, 0xbd, 0x82, 0xf2, 0x45, + 0xe2, 0x24, 0x36, 0xcc, 0xef, 0x70, 0x39, 0xb9, 0xe6, 0xed, 0x0c, 0x59, 0x80, 0xc2, 0x74, 0x68, + 0xc5, 0x91, 0x9f, 0x8f, 0xd0, 0x1f, 0xc6, 0xc1, 0x6e, 0xe8, 0x60, 0x1b, 0xaf, 0xde, 0x9f, 0x56, + 0xac, 0x0f, 0xa7, 0x15, 0xeb, 0xb7, 0xd3, 0x8a, 0xf5, 0xdd, 0x59, 0x25, 0xf3, 0xe1, 0xac, 0x92, + 0xf9, 0xe5, 0xac, 0x92, 0x39, 0x7c, 0x92, 0xe2, 0x69, 0x7c, 0xee, 0x8f, 0xf5, 0x3b, 0x33, 0x29, + 0x41, 0x6b, 0xd4, 0x4a, 0xbd, 0x3e, 0x15, 0x6d, 0xdb, 0x39, 0xf5, 0x56, 0x7c, 0xfa, 0x67, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x55, 0xcf, 0x88, 0x02, 0x98, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -704,11 +696,6 @@ func (m *InboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x2a } - if m.CoinType != 0 { - i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) - i-- - dAtA[i] = 0x20 - } if len(m.TxOrigin) > 0 { i -= len(m.TxOrigin) copy(dAtA[i:], m.TxOrigin) @@ -868,11 +855,6 @@ func (m *OutboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x22 - if m.CoinType != 0 { - i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) - i-- - dAtA[i] = 0x18 - } if m.ReceiverChainId != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.ReceiverChainId)) i-- @@ -958,6 +940,11 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.CoinType != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x60 + } if m.EventIndex != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.EventIndex)) i-- @@ -1063,9 +1050,6 @@ func (m *InboundTxParams) Size() (n int) { if l > 0 { n += 1 + l + sovCrossChainTx(uint64(l)) } - if m.CoinType != 0 { - n += 1 + sovCrossChainTx(uint64(m.CoinType)) - } l = len(m.Asset) if l > 0 { n += 1 + l + sovCrossChainTx(uint64(l)) @@ -1116,9 +1100,6 @@ func (m *OutboundTxParams) Size() (n int) { if m.ReceiverChainId != 0 { n += 1 + sovCrossChainTx(uint64(m.ReceiverChainId)) } - if m.CoinType != 0 { - n += 1 + sovCrossChainTx(uint64(m.CoinType)) - } l = m.Amount.Size() n += 1 + l + sovCrossChainTx(uint64(l)) if m.OutboundTxTssNonce != 0 { @@ -1219,6 +1200,9 @@ func (m *CrossChainTx) Size() (n int) { if m.EventIndex != 0 { n += 1 + sovCrossChainTx(uint64(m.EventIndex)) } + if m.CoinType != 0 { + n += 1 + sovCrossChainTx(uint64(m.CoinType)) + } return n } @@ -1340,25 +1324,6 @@ func (m *InboundTxParams) Unmarshal(dAtA []byte) error { } m.TxOrigin = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) - } - m.CoinType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CoinType |= common.CoinType(b&0x7F) << shift - if b < 0x80 { - break - } - } case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) @@ -1731,25 +1696,6 @@ func (m *OutboundTxParams) Unmarshal(dAtA []byte) error { break } } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) - } - m.CoinType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CoinType |= common.CoinType(b&0x7F) << shift - if b < 0x80 { - break - } - } case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) @@ -2505,6 +2451,25 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { break } } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/emissions/client/tests/cli_test.go b/x/emissions/client/tests/cli_test.go deleted file mode 100644 index 4229cf2a36..0000000000 --- a/x/emissions/client/tests/cli_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package querytests - -import ( - "testing" - - "github.com/stretchr/testify/suite" - "github.com/zeta-chain/zetacore/testutil/network" -) - -func TestCLIQuerySuite(t *testing.T) { - cfg := network.DefaultConfig() - suite.Run(t, NewCLITestSuite(cfg)) -} diff --git a/x/emissions/client/tests/observer_rewards_test.go b/x/emissions/client/tests/observer_rewards_test.go deleted file mode 100644 index c8f11d2449..0000000000 --- a/x/emissions/client/tests/observer_rewards_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package querytests - -import ( - "fmt" - - sdkmath "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/client/flags" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/bank/client/cli" - "github.com/stretchr/testify/suite" - "github.com/zeta-chain/zetacore/cmd/zetacored/config" - emissionscli "github.com/zeta-chain/zetacore/x/emissions/client/cli" - emissionskeeper "github.com/zeta-chain/zetacore/x/emissions/keeper" - emissionstypes "github.com/zeta-chain/zetacore/x/emissions/types" - observercli "github.com/zeta-chain/zetacore/x/observer/client/cli" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -func (s *CliTestSuite) TestObserverRewards() { - emissionPool := "800000000000000000000azeta" - val := s.network.Validators[0] - - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdListPoolAddresses(), []string{"--output", "json"}) - s.Require().NoError(err) - resPools := emissionstypes.QueryListPoolAddressesResponse{} - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resPools)) - txArgs := []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(config.BaseDenom, sdk.NewInt(10))).String()), - } - - // Fund the emission pool to start the emission process - sendArgs := []string{val.Address.String(), - resPools.EmissionModuleAddress, emissionPool} - args := append(sendArgs, txArgs...) - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, cli.NewSendTxCmd(), args) - s.Require().NoError(err) - s.Require().NoError(s.network.WaitForNextBlock()) - - // Collect parameter values and build assertion map for the randomised ballot set created - emissionFactors := emissionstypes.QueryGetEmissionsFactorsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &emissionFactors)) - emissionParams := emissionstypes.QueryParamsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdQueryParams(), []string{"--output", "json"}) - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &emissionParams)) - observerParams := observertypes.QueryParamsResponse{} - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, observercli.CmdQueryParams(), []string{"--output", "json"}) - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &observerParams)) - _, err = s.network.WaitForHeight(s.ballots[0].BallotCreationHeight + observerParams.Params.BallotMaturityBlocks) - s.Require().NoError(err) - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdGetEmmisonsFactors(), []string{"--output", "json"}) - resFactorsNewBlocks := emissionstypes.QueryGetEmissionsFactorsResponse{} - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resFactorsNewBlocks)) - // Duration factor is calculated in the same block,so we need to query based from the committed state at which the distribution is done - // Would be cleaner to use `--height` flag, but it is not supported by the ExecTestCLICmd function yet - emissionFactors.DurationFactor = resFactorsNewBlocks.DurationFactor - asertValues := CalculateObserverRewards(&s.Suite, s.ballots, emissionParams.Params.ObserverEmissionPercentage, emissionFactors.ReservesFactor, emissionFactors.BondFactor, emissionFactors.DurationFactor) - - // Assert withdrawable rewards for each validator - resAvailable := emissionstypes.QueryShowAvailableEmissionsResponse{} - for i := 0; i < len(s.network.Validators); i++ { - out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, emissionscli.CmdShowAvailableEmissions(), []string{s.network.Validators[i].Address.String(), "--output", "json"}) - s.Require().NoError(err) - s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &resAvailable)) - s.Require().Equal(sdk.NewCoin(config.BaseDenom, asertValues[s.network.Validators[i].Address.String()]).String(), resAvailable.Amount, "Validator %s has incorrect withdrawable rewards", s.network.Validators[i].Address.String()) - } - -} - -func CalculateObserverRewards(s *suite.Suite, ballots []*observertypes.Ballot, observerEmissionPercentage, reservesFactor, bondFactor, durationFactor string) map[string]sdkmath.Int { - calculatedDistributer := map[string]sdkmath.Int{} - //blockRewards := sdk.MustNewDecFromStr(reservesFactor).Mul(sdk.MustNewDecFromStr(bondFactor)).Mul(sdk.MustNewDecFromStr(durationFactor)) - blockRewards, err := emissionskeeper.CalculateFixedValidatorRewards(emissionstypes.AvgBlockTime) - s.Require().NoError(err) - observerRewards := sdk.MustNewDecFromStr(observerEmissionPercentage).Mul(blockRewards).TruncateInt() - rewardsDistributer := map[string]int64{} - totalRewardsUnits := int64(0) - // BuildRewardsDistribution has a separate unit test - for _, ballot := range ballots { - totalRewardsUnits = totalRewardsUnits + ballot.BuildRewardsDistribution(rewardsDistributer) - } - rewardPerUnit := observerRewards.Quo(sdk.NewInt(totalRewardsUnits)) - for address, units := range rewardsDistributer { - if units == 0 { - calculatedDistributer[address] = sdk.ZeroInt() - continue - } - if units < 0 { - calculatedDistributer[address] = sdk.ZeroInt() - continue - } - if units > 0 { - calculatedDistributer[address] = rewardPerUnit.Mul(sdkmath.NewInt(units)) - } - } - return calculatedDistributer -} diff --git a/x/emissions/client/tests/suite.go b/x/emissions/client/tests/suite.go deleted file mode 100644 index c13294ddf7..0000000000 --- a/x/emissions/client/tests/suite.go +++ /dev/null @@ -1,113 +0,0 @@ -package querytests - -import ( - "crypto/rand" - "math/big" - "strconv" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - ethcfg "github.com/evmos/ethermint/cmd/config" - "github.com/stretchr/testify/suite" - "github.com/zeta-chain/zetacore/app" - cmdcfg "github.com/zeta-chain/zetacore/cmd/zetacored/config" - "github.com/zeta-chain/zetacore/testutil/network" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -type CliTestSuite struct { - suite.Suite - - cfg network.Config - network *network.Network - ballots []*observerTypes.Ballot -} - -func NewCLITestSuite(cfg network.Config) *CliTestSuite { - return &CliTestSuite{cfg: cfg} -} - -func (s *CliTestSuite) Setconfig() { - config := sdk.GetConfig() - cmdcfg.SetBech32Prefixes(config) - ethcfg.SetBip44CoinType(config) - // Make sure address is compatible with ethereum - config.SetAddressVerifier(app.VerifyAddressFormat) - config.Seal() -} -func (s *CliTestSuite) SetupSuite() { - s.T().Log("setting up integration test suite") - s.Setconfig() - minOBsDel, ok := sdk.NewIntFromString("100000000000000000000") - s.Require().True(ok) - s.cfg.StakingTokens = minOBsDel.Mul(sdk.NewInt(int64(10))) - s.cfg.BondedTokens = minOBsDel - observerList := []string{"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", - } - network.SetupZetaGenesisState(s.T(), s.cfg.GenesisState, s.cfg.Codec, observerList, false) - s.ballots = RandomBallotGenerator(s.T(), 20, observerList) - network.AddObserverData(s.T(), 2, s.cfg.GenesisState, s.cfg.Codec, s.ballots) - - net, err := network.New(s.T(), app.NodeDir, s.cfg) - s.Assert().NoError(err) - s.network = net - _, err = s.network.WaitForHeight(1) - s.Require().NoError(err) - -} - -func CreateRandomVoteList(t *testing.T, numberOfVotes int) []observerTypes.VoteType { - voteOptions := []observerTypes.VoteType{observerTypes.VoteType_SuccessObservation, observerTypes.VoteType_FailureObservation, observerTypes.VoteType_NotYetVoted} - minVoterOptions := 0 - maxBoterOptions := len(voteOptions) - 1 - - randomVoteOptions, err := rand.Int(rand.Reader, big.NewInt(int64(maxBoterOptions-minVoterOptions))) - if err != nil { - t.Fatal(err) - } - - voteList := make([]observerTypes.VoteType, numberOfVotes) - for i := 0; i < numberOfVotes; i++ { - voteList[i] = voteOptions[randomVoteOptions.Int64()] - } - return voteList -} -func RandomBallotGenerator(t *testing.T, numberOfBallots int, voterList []string) []*observerTypes.Ballot { - ballots := make([]*observerTypes.Ballot, numberOfBallots) - ballotStatus := []observerTypes.BallotStatus{observerTypes.BallotStatus_BallotFinalized_FailureObservation, observerTypes.BallotStatus_BallotFinalized_SuccessObservation} - minBallotStatus := 0 - maxBallotStatus := len(ballotStatus) - 1 - - randomBallotStatus, err := rand.Int(rand.Reader, big.NewInt(int64(maxBallotStatus-minBallotStatus))) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < numberOfBallots; i++ { - ballots[i] = &observerTypes.Ballot{ - Index: "", - BallotIdentifier: "TestBallot" + strconv.Itoa(i), - VoterList: voterList, - Votes: CreateRandomVoteList(t, len(voterList)), - ObservationType: observerTypes.ObservationType_InBoundTx, - BallotThreshold: sdk.MustNewDecFromStr("0.66"), - BallotStatus: ballotStatus[randomBallotStatus.Int64()], - BallotCreationHeight: 0, - } - } - return ballots -} - -func (s *CliTestSuite) TearDownSuite() { - s.T().Log("tearing down genesis test suite") - s.network.Cleanup() -} diff --git a/x/observer/keeper/msg_server_remove_chain_params_test.go b/x/observer/keeper/msg_server_remove_chain_params_test.go index 3eae032746..50b7257d8e 100644 --- a/x/observer/keeper/msg_server_remove_chain_params_test.go +++ b/x/observer/keeper/msg_server_remove_chain_params_test.go @@ -39,9 +39,8 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { }, }) - keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) - // remove chain params + keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) _, err := srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &types.MsgRemoveChainParams{ Creator: admin, ChainId: chain2, @@ -56,6 +55,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { require.Equal(t, chain3, chainParamsList.ChainParams[1].ChainId) // remove chain params + keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) _, err = srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &types.MsgRemoveChainParams{ Creator: admin, ChainId: chain1, @@ -69,6 +69,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { require.Equal(t, chain3, chainParamsList.ChainParams[0].ChainId) // remove chain params + keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) _, err = srv.RemoveChainParams(sdk.WrapSDKContext(ctx), &types.MsgRemoveChainParams{ Creator: admin, ChainId: chain3, diff --git a/x/observer/keeper/nonce_to_cctx_test.go b/x/observer/keeper/nonce_to_cctx_test.go index 75df5eb311..760e4f7111 100644 --- a/x/observer/keeper/nonce_to_cctx_test.go +++ b/x/observer/keeper/nonce_to_cctx_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetNonceToCctx(t *testing.T) { t.Run("Get nonce to cctx", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 1) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) @@ -22,7 +22,7 @@ func TestKeeper_GetNonceToCctx(t *testing.T) { } }) t.Run("Get nonce to cctx not found", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 1) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) @@ -31,7 +31,7 @@ func TestKeeper_GetNonceToCctx(t *testing.T) { require.False(t, found) }) t.Run("Get all nonce to cctx", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 10) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) diff --git a/x/observer/keeper/nonces_test.go b/x/observer/keeper/nonces_test.go index aa972eab3e..5ccd7909f6 100644 --- a/x/observer/keeper/nonces_test.go +++ b/x/observer/keeper/nonces_test.go @@ -9,7 +9,7 @@ import ( ) func TestChainNoncesGet(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) @@ -21,7 +21,7 @@ func TestChainNoncesGet(t *testing.T) { } } func TestChainNoncesRemove(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) @@ -34,7 +34,7 @@ func TestChainNoncesRemove(t *testing.T) { } func TestChainNoncesGetAll(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) diff --git a/x/observer/keeper/observer_set_test.go b/x/observer/keeper/observer_set_test.go index 6561405acf..cd4a4239a7 100644 --- a/x/observer/keeper/observer_set_test.go +++ b/x/observer/keeper/observer_set_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetObserverSet(t *testing.T) { t.Run("get observer set", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) tfm, found := k.GetObserverSet(ctx) @@ -21,7 +21,7 @@ func TestKeeper_GetObserverSet(t *testing.T) { func TestKeeper_IsAddressPartOfObserverSet(t *testing.T) { t.Run("address is part of observer set", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) require.True(t, k.IsAddressPartOfObserverSet(ctx, os.ObserverList[0])) @@ -31,7 +31,7 @@ func TestKeeper_IsAddressPartOfObserverSet(t *testing.T) { func TestKeeper_AddObserverToSet(t *testing.T) { t.Run("add observer to set", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) newObserver := sample.AccAddress() @@ -46,7 +46,7 @@ func TestKeeper_AddObserverToSet(t *testing.T) { func TestKeeper_RemoveObserverFromSet(t *testing.T) { t.Run("remove observer from set", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) k.RemoveObserverFromSet(ctx, os.ObserverList[0]) @@ -59,7 +59,7 @@ func TestKeeper_RemoveObserverFromSet(t *testing.T) { func TestKeeper_UpdateObserverAddress(t *testing.T) { t.Run("update observer address", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(10) @@ -72,7 +72,7 @@ func TestKeeper_UpdateObserverAddress(t *testing.T) { require.Equal(t, newObserverAddress, observerSet.ObserverList[len(observerSet.ObserverList)-1]) }) t.Run("update observer address long observerList", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(10000) @@ -85,7 +85,7 @@ func TestKeeper_UpdateObserverAddress(t *testing.T) { require.Equal(t, newObserverAddress, observerMappers.ObserverList[len(observerMappers.ObserverList)-1]) }) t.Run("update observer address short observerList", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(1) diff --git a/x/observer/keeper/pending_nonces_test.go b/x/observer/keeper/pending_nonces_test.go index 8ada35c5ba..6185e80bf1 100644 --- a/x/observer/keeper/pending_nonces_test.go +++ b/x/observer/keeper/pending_nonces_test.go @@ -12,7 +12,7 @@ import ( func TestKeeper_PendingNoncesAll(t *testing.T) { t.Run("Get all pending nonces paginated by limit", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 10) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId @@ -29,7 +29,7 @@ func TestKeeper_PendingNoncesAll(t *testing.T) { require.Equal(t, len(nonces), int(pageRes.Total)) }) t.Run("Get all pending nonces paginated by offset", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 42) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId @@ -48,7 +48,7 @@ func TestKeeper_PendingNoncesAll(t *testing.T) { require.Equal(t, len(nonces), int(pageRes.Total)) }) t.Run("Get all pending nonces ", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 10) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId diff --git a/x/observer/keeper/tss_funds_migrator_test.go b/x/observer/keeper/tss_funds_migrator_test.go index 46c8891ef9..1d32f19f92 100644 --- a/x/observer/keeper/tss_funds_migrator_test.go +++ b/x/observer/keeper/tss_funds_migrator_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetTssFundMigrator(t *testing.T) { t.Run("Successfully set funds migrator for chain", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) chain := sample.TssFundsMigrator(1) k.SetFundMigrator(ctx, chain) tfm, found := k.GetFundMigrator(ctx, chain.ChainId) @@ -18,7 +18,7 @@ func TestKeeper_GetTssFundMigrator(t *testing.T) { require.Equal(t, chain, tfm) }) t.Run("Verify only one migrator can be created for a chain", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tfm1 := sample.TssFundsMigrator(1) k.SetFundMigrator(ctx, tfm1) tfm2 := tfm1 diff --git a/x/observer/keeper/tss_test.go b/x/observer/keeper/tss_test.go index 06f763e4d3..6408f4f49a 100644 --- a/x/observer/keeper/tss_test.go +++ b/x/observer/keeper/tss_test.go @@ -17,7 +17,7 @@ import ( ) func TestTSSGet(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tss := sample.Tss() k.SetTSS(ctx, tss) tssQueried, found := k.GetTSS(ctx) @@ -26,7 +26,7 @@ func TestTSSGet(t *testing.T) { } func TestTSSRemove(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tss := sample.Tss() k.SetTSS(ctx, tss) k.RemoveTSS(ctx) @@ -35,7 +35,7 @@ func TestTSSRemove(t *testing.T) { } func TestTSSQuerySingle(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) //msgs := createTSS(keeper, ctx, 1) tss := sample.Tss() @@ -69,7 +69,7 @@ func TestTSSQuerySingle(t *testing.T) { } func TestTSSQueryHistory(t *testing.T) { - keeper, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) for _, tc := range []struct { desc string @@ -94,16 +94,16 @@ func TestTSSQueryHistory(t *testing.T) { t.Run(tc.desc, func(t *testing.T) { tssList := sample.TssList(tc.tssCount) for _, tss := range tssList { - keeper.SetTSS(ctx, tss) - keeper.SetTSSHistory(ctx, tss) + k.SetTSS(ctx, tss) + k.SetTSSHistory(ctx, tss) } request := &types.QueryTssHistoryRequest{} - response, err := keeper.TssHistory(wctx, request) + response, err := k.TssHistory(wctx, request) if tc.err != nil { require.ErrorIs(t, err, tc.err) } else { require.Equal(t, len(tssList), len(response.TssList)) - prevTss, found := keeper.GetPreviousTSS(ctx) + prevTss, found := k.GetPreviousTSS(ctx) require.Equal(t, tc.foundPrevious, found) if found { require.Equal(t, tssList[len(tssList)-2], prevTss) @@ -115,7 +115,7 @@ func TestTSSQueryHistory(t *testing.T) { func TestKeeper_TssHistory(t *testing.T) { t.Run("Get tss history paginated by limit", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(10) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) @@ -132,7 +132,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, len(tssList), int(pageRes.Total)) }) t.Run("Get tss history paginated by offset", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) offset := 20 for _, tss := range tssList { @@ -151,7 +151,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, len(tssList), int(pageRes.Total)) }) t.Run("Get all TSS without pagination", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) @@ -166,7 +166,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, tssList, rst) }) t.Run("Get historical TSS", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) diff --git a/x/observer/keeper/utils_test.go b/x/observer/keeper/utils_test.go index e68fb2edd7..e8e2a9ab98 100644 --- a/x/observer/keeper/utils_test.go +++ b/x/observer/keeper/utils_test.go @@ -43,7 +43,7 @@ func getValidEthChainIDWithIndex(t *testing.T, index int) int64 { func TestKeeper_IsAuthorized(t *testing.T) { t.Run("authorized observer", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) @@ -69,7 +69,7 @@ func TestKeeper_IsAuthorized(t *testing.T) { }) t.Run("not authorized for tombstoned observer", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) @@ -95,7 +95,7 @@ func TestKeeper_IsAuthorized(t *testing.T) { }) t.Run("not authorized for non-validator observer", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) diff --git a/zetaclient/bitcoin/bitcoin_signer.go b/zetaclient/bitcoin/bitcoin_signer.go index 05106e9a48..f250805a8f 100644 --- a/zetaclient/bitcoin/bitcoin_signer.go +++ b/zetaclient/bitcoin/bitcoin_signer.go @@ -259,7 +259,7 @@ func (signer *BTCSigner) TryProcessOutTx( Logger() params := cctx.GetCurrentOutTxParam() - if params.CoinType == common.CoinType_Zeta || params.CoinType == common.CoinType_ERC20 { + if cctx.CoinType == common.CoinType_Zeta || cctx.CoinType == common.CoinType_ERC20 { logger.Error().Msgf("BTC TryProcessOutTx: can only send BTC to a BTC network") return } diff --git a/zetaclient/evm/evm_client.go b/zetaclient/evm/evm_client.go index b0d85631ca..13193d443c 100644 --- a/zetaclient/evm/evm_client.go +++ b/zetaclient/evm/evm_client.go @@ -322,7 +322,7 @@ func (ob *ChainClient) Stop() { // If isConfirmed, it also post to ZetaCore func (ob *ChainClient) IsSendOutTxProcessed(cctx *types.CrossChainTx, logger zerolog.Logger) (bool, bool, error) { sendHash := cctx.Index - cointype := cctx.GetCurrentOutTxParam().CoinType + cointype := cctx.CoinType nonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce // skip if outtx is not confirmed diff --git a/zetaclient/evm/evm_signer.go b/zetaclient/evm/evm_signer.go index ae632df241..db94b9cfa2 100644 --- a/zetaclient/evm/evm_signer.go +++ b/zetaclient/evm/evm_signer.go @@ -386,7 +386,7 @@ func (signer *Signer) TryProcessOutTx( } var message []byte - if cctx.GetCurrentOutTxParam().CoinType != common.CoinType_Cmd { + if cctx.CoinType != common.CoinType_Cmd { message, err = base64.StdEncoding.DecodeString(cctx.RelayedMessage) if err != nil { logger.Err(err).Msgf("decode CCTX.Message %s error", cctx.RelayedMessage) @@ -457,9 +457,9 @@ func (signer *Signer) TryProcessOutTx( // compliance check goes first if clientcommon.IsCctxRestricted(cctx) { clientcommon.PrintComplianceLog(logger, signer.logger.Compliance, - true, evmClient.chain.ChainId, cctx.Index, cctx.InboundTxParams.Sender, to.Hex(), cctx.GetCurrentOutTxParam().CoinType.String()) + true, evmClient.chain.ChainId, cctx.Index, cctx.InboundTxParams.Sender, to.Hex(), cctx.CoinType.String()) tx, err = signer.SignCancelTx(nonce, gasprice, height) // cancel the tx - } else if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Cmd { // admin command + } else if cctx.CoinType == common.CoinType_Cmd { // admin command to := ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver) if to == (ethcommon.Address{}) { logger.Error().Msgf("invalid receiver %s", cctx.GetCurrentOutTxParam().Receiver) @@ -473,7 +473,7 @@ func (signer *Signer) TryProcessOutTx( } tx, err = signer.SignCommandTx(msg[0], msg[1], to, cctx.GetCurrentOutTxParam(), gasLimit, gasprice, height) } else if cctx.InboundTxParams.SenderChainId == zetaBridge.ZetaChain().ChainId && cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound && flags.IsOutboundEnabled { - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { + if cctx.CoinType == common.CoinType_Gas { logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignWithdrawTx( to, @@ -483,7 +483,7 @@ func (signer *Signer) TryProcessOutTx( height, ) } - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { + if cctx.CoinType == common.CoinType_ERC20 { asset := ethcommon.HexToAddress(cctx.InboundTxParams.Asset) logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignERC20WithdrawTx( @@ -496,7 +496,7 @@ func (signer *Signer) TryProcessOutTx( height, ) } - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Zeta { + if cctx.CoinType == common.CoinType_Zeta { logger.Info().Msgf("SignOutboundTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignOutboundTx( ethcommon.HexToAddress(cctx.InboundTxParams.Sender), @@ -512,7 +512,7 @@ func (signer *Signer) TryProcessOutTx( ) } } else if cctx.CctxStatus.Status == types.CctxStatus_PendingRevert && cctx.OutboundTxParams[0].ReceiverChainId == zetaBridge.ZetaChain().ChainId { - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_Gas { + if cctx.CoinType == common.CoinType_Gas { logger.Info().Msgf("SignWithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignWithdrawTx( to, @@ -522,7 +522,7 @@ func (signer *Signer) TryProcessOutTx( height, ) } - if cctx.GetCurrentOutTxParam().CoinType == common.CoinType_ERC20 { + if cctx.CoinType == common.CoinType_ERC20 { asset := ethcommon.HexToAddress(cctx.InboundTxParams.Asset) logger.Info().Msgf("SignERC20WithdrawTx: %d => %s, nonce %d, gasprice %d", cctx.InboundTxParams.SenderChainId, toChain, cctx.GetCurrentOutTxParam().OutboundTxTssNonce, gasprice) tx, err = signer.SignERC20WithdrawTx( diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index 2a2e112c4a..d69cb28c54 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -246,7 +246,7 @@ func (zs *ZetaSupplyChecker) GetPendingCCTXInTransit(receivingChains []common.Ch } nonceToCctxMap := make(map[uint64]*types.CrossChainTx) for _, c := range cctx { - if c.GetInboundTxParams().CoinType == common.CoinType_Zeta { + if c.CoinType == common.CoinType_Zeta { nonceToCctxMap[c.GetCurrentOutTxParam().OutboundTxTssNonce] = c } } From 822d4d4d715f745192ccef75d3b99b6923e64f8c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 6 Mar 2024 18:23:20 -0500 Subject: [PATCH 06/36] add defer to recover from panic if config is already set --- x/authority/types/policies_test.go | 6 ++++++ x/emissions/abci_test.go | 13 ++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/x/authority/types/policies_test.go b/x/authority/types/policies_test.go index 11d2f3f1a5..b71d4e93c9 100644 --- a/x/authority/types/policies_test.go +++ b/x/authority/types/policies_test.go @@ -1,6 +1,7 @@ package types_test import ( + "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,6 +13,11 @@ import ( // setConfig sets the global config to use zeta chain's bech32 prefixes func setConfig() { + defer func() { + if r := recover(); r != nil { + fmt.Println("config is already sealed", r) + } + }() cfg := sdk.GetConfig() cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) cfg.Seal() diff --git a/x/emissions/abci_test.go b/x/emissions/abci_test.go index 55e6188ba9..188477f42c 100644 --- a/x/emissions/abci_test.go +++ b/x/emissions/abci_test.go @@ -165,12 +165,6 @@ func TestDistributeObserverRewards(t *testing.T) { err = sk.BankKeeper.MintCoins(ctx, emissionstypes.ModuleName, totalRewardCoins) require.NoError(t, err) // Set starting emission for all observers to 100 so that we can calculate the rewards and slashes - for _, observer := range observerSet.ObserverList { - k.SetWithdrawableEmission(ctx, emissionstypes.WithdrawableEmissions{ - Address: observer, - Amount: sdkmath.NewInt(100), - }) - } tt := []struct { name string @@ -256,6 +250,12 @@ func TestDistributeObserverRewards(t *testing.T) { } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { + for _, observer := range observerSet.ObserverList { + k.SetWithdrawableEmission(ctx, emissionstypes.WithdrawableEmissions{ + Address: observer, + Amount: sdkmath.NewInt(100), + }) + } params := emissionstypes.DefaultParams() params.ObserverSlashAmount = tc.slashAmount k.SetParams(ctx, params) @@ -274,7 +274,6 @@ func TestDistributeObserverRewards(t *testing.T) { Height: 0, BallotsIndexList: ballotIdentifiers, }) - ctx = ctx.WithBlockHeight(100) err := emissionsModule.DistributeObserverRewards(ctx, tc.totalRewardsForBlock, *k) require.NoError(t, err) From b228a2883f71ffc501ec10d60112872b5a34e131 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 7 Mar 2024 01:47:33 -0500 Subject: [PATCH 07/36] add more unit tests --- x/crosschain/keeper/cctx_utils.go | 2 +- x/crosschain/keeper/cctx_utils_test.go | 110 +++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 4afe6546a0..f4ff43840b 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -59,7 +59,7 @@ func CreateNewCCTX( OutboundTxGasPrice: "", OutboundTxBallotIndex: "", OutboundTxObservedExternalHeight: 0, - Amount: sdk.NewUint(0), + Amount: sdkmath.ZeroUint(), TssPubkey: tssPubkey, } status := &types.Status{ diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index ddf7285b15..b23709e058 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -499,6 +499,116 @@ func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { }) } +func TestKeeper_GetInbound(t *testing.T) { + t.Run("should return a cctx with correct values", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + senderChain := getValidEthChain(t) + sender := sample.EthAddress() + receiverChain := getValidEthChain(t) + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + intxBlockHeight := uint64(420) + intxHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := common.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteOnObservedInboundTx{ + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InTxHash: intxHash.String(), + InBlockHeight: intxBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + zk.ObserverKeeper.SetTSS(ctx, tss) + cctx := k.GetInbound(ctx, &msg) + require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) + require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) + require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) + require.Equal(t, amount, cctx.GetInboundTxParams().Amount) + require.Equal(t, message, cctx.RelayedMessage) + require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) + require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) + require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) + require.Equal(t, asset, cctx.GetInboundTxParams().Asset) + require.Equal(t, eventIndex, cctx.EventIndex) + require.Equal(t, cointType, cctx.CoinType) + require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) + require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) + require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + }) +} + +func Test_IsPending(t *testing.T) { + tt := []struct { + status types.CctxStatus + expected bool + }{ + {types.CctxStatus_PendingInbound, false}, + {types.CctxStatus_PendingOutbound, true}, + {types.CctxStatus_PendingRevert, true}, + {types.CctxStatus_Reverted, false}, + {types.CctxStatus_Aborted, false}, + {types.CctxStatus_OutboundMined, false}, + } + for _, tc := range tt { + t.Run(fmt.Sprintf("status %s", tc.status), func(t *testing.T) { + require.Equal(t, tc.expected, crosschainkeeper.IsPending(types.CrossChainTx{CctxStatus: &types.Status{Status: tc.status}})) + }) + } +} + +func TestKeeper_SaveInbound(t *testing.T) { + t.Run("should save the cctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + k.SaveInbound(ctx, cctx) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) + require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, cctx.EventIndex)) + _, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + }) + + t.Run("should save the cctx and remove tracker", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + hash := sample.Hash() + cctx.InboundTxParams.InboundTxObservedHash = hash.String() + k.SetInTxTracker(ctx, types.InTxTracker{ + ChainId: senderChain.ChainId, + TxHash: hash.String(), + CoinType: 0, + }) + k.SaveInbound(ctx, cctx) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) + require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, cctx.EventIndex)) + _, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + _, found = k.GetInTxTracker(ctx, senderChain.ChainId, hash.String()) + require.False(t, found) + }) +} + func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.Chain, asset string, amount *big.Int) *types.CrossChainTx { cctx := sample.CrossChainTx(t, "test") cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} From f285fe4735d750125634e2d0e2d73d239b360c5f Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 7 Mar 2024 12:39:03 -0500 Subject: [PATCH 08/36] add validate --- x/crosschain/types/cctx_utils.go | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index bf3357c709..3b9b824f9f 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -5,6 +5,8 @@ import ( "strconv" sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/zeta-chain/zetacore/common" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -46,6 +48,81 @@ func GetAllAuthzZetaclientTxTypes() []string { } } +func (m CrossChainTx) Validate() error { + if m.InboundTxParams == nil { + return fmt.Errorf("inbound tx params cannot be nil") + } + if m.OutboundTxParams == nil { + return fmt.Errorf("outbound tx params cannot be nil") + } + if m.CctxStatus == nil { + return fmt.Errorf("cctx status cannot be nil") + } + if len(m.OutboundTxParams) > 2 { + return fmt.Errorf("outbound tx params cannot be more than 2") + } + if len(m.Index) != 66 { + return ErrInvalidCCTXIndex + } + + return nil +} + +func (m InboundTxParams) Validate() error { + if m.Sender == "" { + return fmt.Errorf("sender cannot be empty") + } + if m.InboundTxObservedHash == "" { + return fmt.Errorf("inbound tx observed hash cannot be empty") + } + if len(m.InboundTxBallotIndex) != 66 { + return fmt.Errorf("inbound tx ballot index must be 66 characters") + } + if common.IsEthereumChain(m.SenderChainId) { + if !ethcommon.IsHexAddress(m.Sender) { + return fmt.Errorf("sender a valid ethereum address") + } + } + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") + } + if common.IsBitcoinChain(m.SenderChainId) { + //if _, err := common.BitcoinAddressToPubKeyHash(m.Sender); err != nil { + // return fmt.Errorf("sender must be a valid bitcoin address") + //} + } + return nil +} + +func (m OutboundTxParams) Validate() error { + if m.Receiver == "" { + return fmt.Errorf("receiver cannot be empty") + } + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") + } + if m.OutboundTxGasPrice == "" { + return fmt.Errorf("outbound tx gas price cannot be empty") + } + if m.GasLimit == 0 { + return fmt.Errorf("gas limit cannot be 0") + } + if m.ReceiverChainId == 0 { + return fmt.Errorf("receiver chain id cannot be 0") + } + if common.IsEthereumChain(m.ReceiverChainId) { + if !ethcommon.IsHexAddress(m.Receiver) { + return fmt.Errorf("receiver must be a valid ethereum address") + } + } + if common.IsBitcoinChain(m.ReceiverChainId) { + //if _, err := common.BitcoinAddressToPubKeyHash(m.Receiver); err != nil { + // return fmt.Errorf("receiver must be a valid bitcoin address") + //} + } + return nil +} + // GetGasPrice returns the gas price of the outbound tx func (m OutboundTxParams) GetGasPrice() (uint64, error) { gasPrice, err := strconv.ParseUint(m.OutboundTxGasPrice, 10, 64) From 806a6f58cf9b3433166b572d4b18cd97739b59ef Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 8 Mar 2024 01:00:23 -0500 Subject: [PATCH 09/36] add validate function for cctx --- .../keeper/msg_server_vote_inbound_tx.go | 4 + x/crosschain/types/cctx_utils.go | 120 +++++++++++++----- x/crosschain/types/errors.go | 2 +- x/crosschain/types/message_refund_aborted.go | 2 +- 4 files changed, 96 insertions(+), 32 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index c515d541f0..b59b538517 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -90,6 +90,10 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg } inboundCctx := k.GetInbound(ctx, msg) + err = inboundCctx.Validate() + if err != nil { + return nil, err + } k.ProcessInbound(ctx, &inboundCctx) k.SaveInbound(ctx, &inboundCctx) return &types.MsgVoteOnObservedInboundTxResponse{}, nil diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index 3b9b824f9f..f87430a4e0 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -4,8 +4,11 @@ import ( "fmt" "strconv" + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcutil" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/zeta-chain/zetacore/common" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -61,8 +64,21 @@ func (m CrossChainTx) Validate() error { if len(m.OutboundTxParams) > 2 { return fmt.Errorf("outbound tx params cannot be more than 2") } - if len(m.Index) != 66 { - return ErrInvalidCCTXIndex + if m.Index != "" { + err := ValidateZetaIndex(m.Index) + if err != nil { + return err + } + } + err := m.InboundTxParams.Validate() + if err != nil { + return err + } + for _, outboundTxParam := range m.OutboundTxParams { + err = outboundTxParam.Validate() + if err != nil { + return err + } } return nil @@ -72,54 +88,98 @@ func (m InboundTxParams) Validate() error { if m.Sender == "" { return fmt.Errorf("sender cannot be empty") } - if m.InboundTxObservedHash == "" { - return fmt.Errorf("inbound tx observed hash cannot be empty") + err := ValidateAddressForChain(m.Sender, m.SenderChainId) + if err != nil { + return err } - if len(m.InboundTxBallotIndex) != 66 { - return fmt.Errorf("inbound tx ballot index must be 66 characters") + if common.GetChainFromChainID(m.SenderChainId) == nil { + return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) } - if common.IsEthereumChain(m.SenderChainId) { - if !ethcommon.IsHexAddress(m.Sender) { - return fmt.Errorf("sender a valid ethereum address") + if m.TxOrigin != "" { + errTxOrigin := ValidateAddressForChain(m.TxOrigin, m.SenderChainId) + if errTxOrigin != nil { + return errTxOrigin } } if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } - if common.IsBitcoinChain(m.SenderChainId) { - //if _, err := common.BitcoinAddressToPubKeyHash(m.Sender); err != nil { - // return fmt.Errorf("sender must be a valid bitcoin address") - //} + err = ValidateHashForChain(m.InboundTxObservedHash, m.SenderChainId) + if err != nil { + return err + } + if m.InboundTxBallotIndex != "" { + err = ValidateZetaIndex(m.InboundTxBallotIndex) + if err != nil { + return err + } + } + return nil +} + +func ValidateZetaIndex(index string) error { + if len(index) != 66 { + return ErrInvalidIndexValue } return nil } +func ValidateHashForChain(hash string, chainID int64) error { + if common.IsEthereumChain(chainID) { + _, err := hexutil.Decode(hash) + if err != nil { + return fmt.Errorf("hash must be a valid ethereum hash") + } + } + if common.IsBitcoinChain(chainID) { + _, err := chainhash.NewHashFromStr(hash) + if err != nil { + return fmt.Errorf("hash must be a valid bitcoin hash") + } + } + return fmt.Errorf("invalid chain id %d", chainID) +} + +func ValidateAddressForChain(address string, chainID int64) error { + if common.IsEthereumChain(chainID) { + if !ethcommon.IsHexAddress(address) { + return fmt.Errorf("sender a valid ethereum address") + } + return nil + } + if common.IsBitcoinChain(chainID) { + addr, err := common.DecodeBtcAddress(address, chainID) + if err != nil { + return fmt.Errorf("invalid address %s: %s", address, err) + } + _, ok := addr.(*btcutil.AddressWitnessPubKeyHash) + if !ok { + return fmt.Errorf(" invalid address %s (not P2WPKH address)", address) + } + return nil + } + return fmt.Errorf("invalid chain id %d", chainID) +} func (m OutboundTxParams) Validate() error { if m.Receiver == "" { return fmt.Errorf("receiver cannot be empty") } - if m.Amount.IsNil() { - return fmt.Errorf("amount cannot be nil") - } - if m.OutboundTxGasPrice == "" { - return fmt.Errorf("outbound tx gas price cannot be empty") + err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) + if err != nil { + return err } - if m.GasLimit == 0 { - return fmt.Errorf("gas limit cannot be 0") + if common.GetChainFromChainID(m.ReceiverChainId) == nil { + return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) } - if m.ReceiverChainId == 0 { - return fmt.Errorf("receiver chain id cannot be 0") + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") } - if common.IsEthereumChain(m.ReceiverChainId) { - if !ethcommon.IsHexAddress(m.Receiver) { - return fmt.Errorf("receiver must be a valid ethereum address") + if m.OutboundTxBallotIndex != "" { + err = ValidateZetaIndex(m.OutboundTxBallotIndex) + if err != nil { + return err } } - if common.IsBitcoinChain(m.ReceiverChainId) { - //if _, err := common.BitcoinAddressToPubKeyHash(m.Receiver); err != nil { - // return fmt.Errorf("receiver must be a valid bitcoin address") - //} - } return nil } diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 2c5a595eb5..62720aaf66 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -36,7 +36,7 @@ var ( ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") ErrInsufficientFundsTssMigration = errorsmod.Register(ModuleName, 1145, "insufficient funds for TSS migration") - ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1146, "invalid cctx index") + ErrInvalidIndexValue = errorsmod.Register(ModuleName, 1146, "invalid index hash") ErrInvalidStatus = errorsmod.Register(ModuleName, 1147, "invalid cctx status") ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") diff --git a/x/crosschain/types/message_refund_aborted.go b/x/crosschain/types/message_refund_aborted.go index 698d499b09..20115aec21 100644 --- a/x/crosschain/types/message_refund_aborted.go +++ b/x/crosschain/types/message_refund_aborted.go @@ -46,7 +46,7 @@ func (msg *MsgRefundAbortedCCTX) ValidateBasic() error { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } if len(msg.CctxIndex) != 66 { - return ErrInvalidCCTXIndex + return ErrInvalidIndexValue } if msg.RefundAddress != "" && !ethcommon.IsHexAddress(msg.RefundAddress) { return ErrInvalidAddress From d8164899f593d14e523119875791cdb735ad4849 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 8 Mar 2024 01:47:34 -0500 Subject: [PATCH 10/36] add validate function for cctx --- testutil/sample/common.go | 8 ++++ testutil/sample/sample.go | 7 ++++ x/crosschain/keeper/cctx_utils.go | 2 +- x/crosschain/types/cctx_utils.go | 58 ++++++++++++++------------- x/crosschain/types/cctx_utils_test.go | 29 ++++++++++++++ x/crosschain/types/keys.go | 1 - 6 files changed, 76 insertions(+), 29 deletions(-) diff --git a/testutil/sample/common.go b/testutil/sample/common.go index d32ca30274..0beba4695c 100644 --- a/testutil/sample/common.go +++ b/testutil/sample/common.go @@ -91,3 +91,11 @@ func EventIndex() uint64 { r := newRandFromSeed(1) return r.Uint64() } + +func EthChain() common.Chain { + return common.EthChain() +} + +func BtcChain() common.Chain { + return common.BtcMainnetChain() +} diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 020ff9104b..f0d7a23753 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -8,6 +8,7 @@ import ( "testing" sdkmath "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/crypto" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -111,6 +112,12 @@ func Hash() ethcommon.Hash { return EthAddress().Hash() } +func ZetaIndex(t *testing.T) string { + msg := CrossChainTx(t, "foo") + hash := crypto.Keccak256Hash([]byte(msg.String())) + return hash.Hex() +} + // Bytes returns a sample byte array func Bytes() []byte { return []byte("sample") diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index f4ff43840b..43917f4520 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -92,7 +92,7 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C nonce, found := k.GetObserverKeeper().GetChainNonces(ctx, chain.ChainName.String()) if !found { - return cosmoserrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) + return cosmoserrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String())) } // SET nonce diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index f87430a4e0..437b1a9698 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -2,9 +2,9 @@ package types import ( "fmt" + "regexp" "strconv" - "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -80,7 +80,6 @@ func (m CrossChainTx) Validate() error { return err } } - return nil } @@ -117,6 +116,29 @@ func (m InboundTxParams) Validate() error { return nil } +func (m OutboundTxParams) Validate() error { + if m.Receiver == "" { + return fmt.Errorf("receiver cannot be empty") + } + err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) + if err != nil { + return err + } + if common.GetChainFromChainID(m.ReceiverChainId) == nil { + return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) + } + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") + } + if m.OutboundTxBallotIndex != "" { + err = ValidateZetaIndex(m.OutboundTxBallotIndex) + if err != nil { + return err + } + } + return nil +} + func ValidateZetaIndex(index string) error { if len(index) != 66 { return ErrInvalidIndexValue @@ -129,12 +151,17 @@ func ValidateHashForChain(hash string, chainID int64) error { if err != nil { return fmt.Errorf("hash must be a valid ethereum hash") } + return nil } if common.IsBitcoinChain(chainID) { - _, err := chainhash.NewHashFromStr(hash) + r, err := regexp.Compile("^[a-fA-F0-9]{64}$") if err != nil { + return fmt.Errorf("error compiling regex") + } + if !r.MatchString(hash) { return fmt.Errorf("hash must be a valid bitcoin hash") } + return nil } return fmt.Errorf("invalid chain id %d", chainID) } @@ -142,7 +169,7 @@ func ValidateHashForChain(hash string, chainID int64) error { func ValidateAddressForChain(address string, chainID int64) error { if common.IsEthereumChain(chainID) { if !ethcommon.IsHexAddress(address) { - return fmt.Errorf("sender a valid ethereum address") + return fmt.Errorf("invalid address %s", address) } return nil } @@ -160,29 +187,6 @@ func ValidateAddressForChain(address string, chainID int64) error { return fmt.Errorf("invalid chain id %d", chainID) } -func (m OutboundTxParams) Validate() error { - if m.Receiver == "" { - return fmt.Errorf("receiver cannot be empty") - } - err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) - if err != nil { - return err - } - if common.GetChainFromChainID(m.ReceiverChainId) == nil { - return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) - } - if m.Amount.IsNil() { - return fmt.Errorf("amount cannot be nil") - } - if m.OutboundTxBallotIndex != "" { - err = ValidateZetaIndex(m.OutboundTxBallotIndex) - if err != nil { - return err - } - } - return nil -} - // GetGasPrice returns the gas price of the outbound tx func (m OutboundTxParams) GetGasPrice() (uint64, error) { gasPrice, err := strconv.ParseUint(m.OutboundTxGasPrice, 10, 64) diff --git a/x/crosschain/types/cctx_utils_test.go b/x/crosschain/types/cctx_utils_test.go index 381ef47f6c..c06fe0007a 100644 --- a/x/crosschain/types/cctx_utils_test.go +++ b/x/crosschain/types/cctx_utils_test.go @@ -5,10 +5,39 @@ import ( "testing" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/types" ) +func TestValidateAddressForChain(t *testing.T) { + require.Error(t, types.ValidateAddressForChain("0x123", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("%%%%", common.GoerliChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3", common.BtcMainnetChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcMainnetChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("", common.BtcRegtestChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu", common.BtcMainnetChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcRegtestChain().ChainId)) +} + +func TestValidateZetaIndex(t *testing.T) { + require.NoError(t, types.ValidateZetaIndex("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910")) + require.NoError(t, types.ValidateZetaIndex(sample.ZetaIndex(t))) + require.Error(t, types.ValidateZetaIndex("0")) + require.Error(t, types.ValidateZetaIndex("0x70e967acFcC17c3941E87562161406d41676FD83")) +} + +func TestValidateHashForChain(t *testing.T) { + require.NoError(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateHashForChain("", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.GoerliChain().ChainId)) + require.NoError(t, types.ValidateHashForChain("15b7880f5d236e857a5e8f043ce9d56f5ef01e1c3f2a786baf740fc0bb7a22a3", common.BtcMainnetChain().ChainId)) + require.NoError(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.BtcTestNetChain().ChainId)) + require.Error(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.BtcMainnetChain().ChainId)) +} + func TestCrossChainTx_GetCurrentOutTxParam(t *testing.T) { r := rand.New(rand.NewSource(42)) cctx := sample.CrossChainTx(t, "foo") diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index 4adac4d73f..ab572e3cb6 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -75,7 +75,6 @@ func (m CrossChainTx) LogIdentifierForCCTX() string { i := len(m.OutboundTxParams) - 1 outTx := m.OutboundTxParams[i] return fmt.Sprintf("%s-%d-%d-%d", m.InboundTxParams.Sender, m.InboundTxParams.SenderChainId, outTx.ReceiverChainId, outTx.OutboundTxTssNonce) - } func FinalizedInboundKey(intxHash string, chainID int64, eventIndex uint64) string { From be6dc4e6c8276f24a4651f1f878ccf9226b6db5e Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 8 Mar 2024 14:11:22 -0500 Subject: [PATCH 11/36] add validate unit tests --- proto/crosschain/cross_chain_tx.proto | 3 + testutil/sample/crosschain.go | 30 ++++++++ x/crosschain/migrations/v6/migrate.go | 27 +++++++ x/crosschain/migrations/v6/migrate_test.go | 1 + x/crosschain/types/cctx_utils.go | 19 ++--- x/crosschain/types/cctx_utils_test.go | 84 ++++++++++++++++++++++ 6 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 x/crosschain/migrations/v6/migrate.go create mode 100644 x/crosschain/migrations/v6/migrate_test.go diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 9853e66621..7e1b43eeb7 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -93,3 +93,6 @@ message CrossChainTx { uint64 event_index = 11; common.CoinType coin_type = 12; } + + + diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index be45fcbb43..0e3125b695 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -51,6 +51,20 @@ func InboundTxParams(r *rand.Rand) *types.InboundTxParams { } } +func InboundTxParamsValidChainId(r *rand.Rand) *types.InboundTxParams { + return &types.InboundTxParams{ + Sender: EthAddress().String(), + SenderChainId: common.GoerliChain().ChainId, + TxOrigin: EthAddress().String(), + Asset: StringRandom(r, 32), + Amount: math.NewUint(uint64(r.Int63())), + InboundTxObservedHash: StringRandom(r, 32), + InboundTxObservedExternalHeight: r.Uint64(), + InboundTxBallotIndex: StringRandom(r, 32), + InboundTxFinalizedZetaHeight: r.Uint64(), + } +} + func OutboundTxParams(r *rand.Rand) *types.OutboundTxParams { return &types.OutboundTxParams{ Receiver: EthAddress().String(), @@ -67,6 +81,22 @@ func OutboundTxParams(r *rand.Rand) *types.OutboundTxParams { } } +func OutboundTxParamsValidChainId(r *rand.Rand) *types.OutboundTxParams { + return &types.OutboundTxParams{ + Receiver: EthAddress().String(), + ReceiverChainId: common.GoerliChain().ChainId, + Amount: math.NewUint(uint64(r.Int63())), + OutboundTxTssNonce: r.Uint64(), + OutboundTxGasLimit: r.Uint64(), + OutboundTxGasPrice: math.NewUint(uint64(r.Int63())).String(), + OutboundTxHash: StringRandom(r, 32), + OutboundTxBallotIndex: StringRandom(r, 32), + OutboundTxObservedExternalHeight: r.Uint64(), + OutboundTxGasUsed: r.Uint64(), + OutboundTxEffectiveGasPrice: math.NewInt(r.Int63()), + } +} + func Status(t *testing.T, index string) *types.Status { r := newRandFromStringSeed(t, index) diff --git a/x/crosschain/migrations/v6/migrate.go b/x/crosschain/migrations/v6/migrate.go new file mode 100644 index 0000000000..87eae5e90e --- /dev/null +++ b/x/crosschain/migrations/v6/migrate.go @@ -0,0 +1,27 @@ +package v6 + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// crosschainKeeper is an interface to prevent cyclic dependency +type crosschainKeeper interface { + GetStoreKey() storetypes.StoreKey + GetCodec() codec.Codec + GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx + + SetCrossChainTx(ctx sdk.Context, cctx types.CrossChainTx) + AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) + + SetZetaAccounting(ctx sdk.Context, accounting types.ZetaAccounting) +} + +// MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 +// It resets the aborted zeta amount to use the inbound tx amount instead in situations where the outbound cctx is never created. +func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper, observerKeeper types.ObserverKeeper) error { + + return nil +} diff --git a/x/crosschain/migrations/v6/migrate_test.go b/x/crosschain/migrations/v6/migrate_test.go new file mode 100644 index 0000000000..41c0ebe310 --- /dev/null +++ b/x/crosschain/migrations/v6/migrate_test.go @@ -0,0 +1 @@ +package v6_test diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index 437b1a9698..5f0b4b15f8 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -87,13 +87,14 @@ func (m InboundTxParams) Validate() error { if m.Sender == "" { return fmt.Errorf("sender cannot be empty") } + if common.GetChainFromChainID(m.SenderChainId) == nil { + return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) + } err := ValidateAddressForChain(m.Sender, m.SenderChainId) if err != nil { return err } - if common.GetChainFromChainID(m.SenderChainId) == nil { - return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) - } + if m.TxOrigin != "" { errTxOrigin := ValidateAddressForChain(m.TxOrigin, m.SenderChainId) if errTxOrigin != nil { @@ -120,13 +121,13 @@ func (m OutboundTxParams) Validate() error { if m.Receiver == "" { return fmt.Errorf("receiver cannot be empty") } + if common.GetChainFromChainID(m.ReceiverChainId) == nil { + return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) + } err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) if err != nil { return err } - if common.GetChainFromChainID(m.ReceiverChainId) == nil { - return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) - } if m.Amount.IsNil() { return fmt.Errorf("amount cannot be nil") } @@ -141,7 +142,7 @@ func (m OutboundTxParams) Validate() error { func ValidateZetaIndex(index string) error { if len(index) != 66 { - return ErrInvalidIndexValue + return fmt.Errorf("invalid index hash %s", index) } return nil } @@ -149,7 +150,7 @@ func ValidateHashForChain(hash string, chainID int64) error { if common.IsEthereumChain(chainID) { _, err := hexutil.Decode(hash) if err != nil { - return fmt.Errorf("hash must be a valid ethereum hash") + return fmt.Errorf("hash must be a valid ethereum hash %s", hash) } return nil } @@ -159,7 +160,7 @@ func ValidateHashForChain(hash string, chainID int64) error { return fmt.Errorf("error compiling regex") } if !r.MatchString(hash) { - return fmt.Errorf("hash must be a valid bitcoin hash") + return fmt.Errorf("hash must be a valid bitcoin hash %s", hash) } return nil } diff --git a/x/crosschain/types/cctx_utils_test.go b/x/crosschain/types/cctx_utils_test.go index c06fe0007a..f3368ea386 100644 --- a/x/crosschain/types/cctx_utils_test.go +++ b/x/crosschain/types/cctx_utils_test.go @@ -4,6 +4,7 @@ import ( "math/rand" "testing" + sdkmath "cosmossdk.io/math" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/testutil/sample" @@ -38,6 +39,89 @@ func TestValidateHashForChain(t *testing.T) { require.Error(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.BtcMainnetChain().ChainId)) } +func TestInboundTxParams_Validate(t *testing.T) { + r := rand.New(rand.NewSource(42)) + inTxParams := sample.InboundTxParamsValidChainId(r) + inTxParams.Sender = "" + require.ErrorContains(t, inTxParams.Validate(), "sender cannot be empty") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.SenderChainId = 1000 + require.ErrorContains(t, inTxParams.Validate(), "invalid sender chain id 1000") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.SenderChainId = common.GoerliChain().ChainId + inTxParams.Sender = "0x123" + require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.SenderChainId = common.GoerliChain().ChainId + inTxParams.TxOrigin = "0x123" + require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.Amount = sdkmath.Uint{} + require.ErrorContains(t, inTxParams.Validate(), "amount cannot be nil") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.InboundTxObservedHash = "12" + require.ErrorContains(t, inTxParams.Validate(), "hash must be a valid ethereum hash 12") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.InboundTxObservedHash = sample.Hash().String() + inTxParams.InboundTxBallotIndex = "12" + require.ErrorContains(t, inTxParams.Validate(), "invalid index hash 12") + inTxParams = sample.InboundTxParamsValidChainId(r) + inTxParams.InboundTxObservedHash = sample.Hash().String() + inTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) + require.NoError(t, inTxParams.Validate()) +} + +func TestOutboundTxParams_Validate(t *testing.T) { + r := rand.New(rand.NewSource(42)) + outTxParams := sample.OutboundTxParamsValidChainId(r) + outTxParams.Receiver = "" + require.ErrorContains(t, outTxParams.Validate(), "receiver cannot be empty") + outTxParams = sample.OutboundTxParamsValidChainId(r) + outTxParams.ReceiverChainId = 1000 + require.ErrorContains(t, outTxParams.Validate(), "invalid receiver chain id 1000") + outTxParams = sample.OutboundTxParamsValidChainId(r) + outTxParams.Receiver = "0x123" + require.ErrorContains(t, outTxParams.Validate(), "invalid address 0x123") + outTxParams = sample.OutboundTxParamsValidChainId(r) + outTxParams.Amount = sdkmath.Uint{} + require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") + outTxParams = sample.OutboundTxParamsValidChainId(r) + outTxParams.OutboundTxBallotIndex = "12" + require.ErrorContains(t, outTxParams.Validate(), "invalid index hash 12") + outTxParams = sample.OutboundTxParamsValidChainId(r) + outTxParams.OutboundTxBallotIndex = sample.ZetaIndex(t) + require.NoError(t, outTxParams.Validate()) +} + +func TestCrossChainTx_Validate(t *testing.T) { + cctx := sample.CrossChainTx(t, "foo") + cctx.InboundTxParams = nil + require.ErrorContains(t, cctx.Validate(), "inbound tx params cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = nil + require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.CctxStatus = nil + require.ErrorContains(t, cctx.Validate(), "cctx status cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = make([]*types.OutboundTxParams, 3) + require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be more than 2") + cctx = sample.CrossChainTx(t, "foo") + cctx.Index = "0" + require.ErrorContains(t, cctx.Validate(), "invalid index hash 0") + cctx = sample.CrossChainTx(t, "foo") + cctx.InboundTxParams = sample.InboundTxParamsValidChainId(rand.New(rand.NewSource(42))) + cctx.InboundTxParams.SenderChainId = 1000 + require.ErrorContains(t, cctx.Validate(), "invalid sender chain id 1000") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParamsValidChainId(rand.New(rand.NewSource(42)))} + cctx.InboundTxParams = sample.InboundTxParamsValidChainId(rand.New(rand.NewSource(42))) + cctx.InboundTxParams.InboundTxObservedHash = sample.Hash().String() + cctx.InboundTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) + cctx.OutboundTxParams[0].ReceiverChainId = 1000 + require.ErrorContains(t, cctx.Validate(), "invalid receiver chain id 1000") +} + func TestCrossChainTx_GetCurrentOutTxParam(t *testing.T) { r := rand.New(rand.NewSource(42)) cctx := sample.CrossChainTx(t, "foo") From 639f2a47cb2c115c36d4eb080e583818e644038a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sat, 9 Mar 2024 00:31:59 -0500 Subject: [PATCH 12/36] add migration test --- app/setup_handlers.go | 2 +- changelog.md | 8 +- proto/crosschain/cross_chain_tx.proto | 4 +- proto/crosschain/cross_chain_tx_v14.proto | 65 + testutil/sample/crosschain.go | 1 + testutil/sample/crosschain_legacy.go | 56 + x/crosschain/keeper/migrator.go | 5 + x/crosschain/migrations/v6/migrate.go | 66 +- x/crosschain/migrations/v6/migrate_test.go | 75 + x/crosschain/module.go | 6 +- x/crosschain/types/cross_chain_tx_v14.pb.go | 2051 +++++++++++++++++ .../client/cli/tx_updat_observer_test.go | 13 + x/observer/client/cli/tx_update_observer.go | 4 +- 13 files changed, 2346 insertions(+), 10 deletions(-) create mode 100644 proto/crosschain/cross_chain_tx_v14.proto create mode 100644 testutil/sample/crosschain_legacy.go create mode 100644 x/crosschain/types/cross_chain_tx_v14.pb.go create mode 100644 x/observer/client/cli/tx_updat_observer_test.go diff --git a/app/setup_handlers.go b/app/setup_handlers.go index b773745398..26ed86a255 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -8,7 +8,7 @@ import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) -const releaseVersion = "v14" +const releaseVersion = "v15" func SetupHandlers(app *App) { app.UpgradeKeeper.SetUpgradeHandler(releaseVersion, func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) { diff --git a/changelog.md b/changelog.md index 9da339d95a..41f672eb7e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,15 @@ # CHANGELOG + +## Unreleased + +### Refactor +* [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx . Refactor CCTX struct to remove duplicate CoinType + ## Version: v14 ### Fixes - [1817](https://github.com/zeta-chain/node/pull/1817) - Add migration script to fix pending and chain nonces on testnet -## Unreleased - ### Breaking Changes * Admin policies have been moved from `observer` to a new module `authority`. diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 7e1b43eeb7..3f6557594e 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -4,6 +4,7 @@ package zetachain.zetacore.crosschain; import "common/common.proto"; import "gogoproto/gogo.proto"; +//TODO : fix the descriptor numbers for the fields option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; enum CctxStatus { @@ -93,6 +94,3 @@ message CrossChainTx { uint64 event_index = 11; common.CoinType coin_type = 12; } - - - diff --git a/proto/crosschain/cross_chain_tx_v14.proto b/proto/crosschain/cross_chain_tx_v14.proto new file mode 100644 index 0000000000..255ddb3d42 --- /dev/null +++ b/proto/crosschain/cross_chain_tx_v14.proto @@ -0,0 +1,65 @@ +syntax = "proto3"; +package zetachain.zetacore.crosschain; + +import "common/common.proto"; +import "crosschain/cross_chain_tx.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; + +message InboundTxParamsV14 { + string sender = 1; // this address is the immediate contract/EOA that calls the Connector.send() + int64 sender_chain_id = 2; + string tx_origin = 3; // this address is the EOA that signs the inbound tx + common.CoinType coin_type = 4; + string asset = 5; // for ERC20 coin type, the asset is an address of the ERC20 contract + string amount = 6 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; + string inbound_tx_observed_hash = 7; + uint64 inbound_tx_observed_external_height = 8; + string inbound_tx_ballot_index = 9; + uint64 inbound_tx_finalized_zeta_height = 10; + TxFinalizationStatus tx_finalization_status = 11; +} + +message OutboundTxParamsV14 { + string receiver = 1; + int64 receiver_chainId = 2; + common.CoinType coin_type = 3; + string amount = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; + uint64 outbound_tx_tss_nonce = 5; + uint64 outbound_tx_gas_limit = 6; + string outbound_tx_gas_price = 7; + // the above are commands for zetaclients + // the following fields are used when the outbound tx is mined + string outbound_tx_hash = 8; + string outbound_tx_ballot_index = 9; + uint64 outbound_tx_observed_external_height = 10; + uint64 outbound_tx_gas_used = 20; + string outbound_tx_effective_gas_price = 21 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + uint64 outbound_tx_effective_gas_limit = 22; + string tss_pubkey = 11; + TxFinalizationStatus tx_finalization_status = 12; +} + +message CrossChainTxV14 { + string creator = 1; + string index = 2; + string zeta_fees = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"zeta_fees\"" + ]; + string relayed_message = 6; // Not used by protocol , just relayed across + Status cctx_status = 8; + InboundTxParamsV14 inbound_tx_params = 9; + repeated OutboundTxParamsV14 outbound_tx_params = 10; +} diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 0e3125b695..4f439e73fc 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -123,6 +123,7 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { CctxStatus: Status(t, index), InboundTxParams: InboundTxParams(r), OutboundTxParams: []*types.OutboundTxParams{OutboundTxParams(r), OutboundTxParams(r)}, + EventIndex: r.Uint64(), } } diff --git a/testutil/sample/crosschain_legacy.go b/testutil/sample/crosschain_legacy.go new file mode 100644 index 0000000000..f32f7caa58 --- /dev/null +++ b/testutil/sample/crosschain_legacy.go @@ -0,0 +1,56 @@ +package sample + +import ( + "math/rand" + "testing" + + "cosmossdk.io/math" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func CrossChainTxV14(t *testing.T, index string) *types.CrossChainTxV14 { + r := newRandFromStringSeed(t, index) + cointType := common.CoinType(r.Intn(100)) + return &types.CrossChainTxV14{ + Creator: AccAddress(), + Index: GetCctxIndexFromString(index), + ZetaFees: math.NewUint(uint64(r.Int63())), + RelayedMessage: StringRandom(r, 32), + CctxStatus: Status(t, index), + InboundTxParams: InboundTxParamsV14(r, cointType), + OutboundTxParams: []*types.OutboundTxParamsV14{OutboundTxParamsV14(r, cointType), OutboundTxParamsV14(r, cointType)}, + } +} + +func InboundTxParamsV14(r *rand.Rand, coinType common.CoinType) *types.InboundTxParamsV14 { + return &types.InboundTxParamsV14{ + Sender: EthAddress().String(), + SenderChainId: r.Int63(), + TxOrigin: EthAddress().String(), + Asset: StringRandom(r, 32), + Amount: math.NewUint(uint64(r.Int63())), + InboundTxObservedHash: StringRandom(r, 32), + InboundTxObservedExternalHeight: r.Uint64(), + InboundTxBallotIndex: StringRandom(r, 32), + InboundTxFinalizedZetaHeight: r.Uint64(), + CoinType: coinType, + } +} + +func OutboundTxParamsV14(r *rand.Rand, coinType common.CoinType) *types.OutboundTxParamsV14 { + return &types.OutboundTxParamsV14{ + Receiver: EthAddress().String(), + ReceiverChainId: r.Int63(), + Amount: math.NewUint(uint64(r.Int63())), + OutboundTxTssNonce: r.Uint64(), + OutboundTxGasLimit: r.Uint64(), + OutboundTxGasPrice: math.NewUint(uint64(r.Int63())).String(), + OutboundTxHash: StringRandom(r, 32), + OutboundTxBallotIndex: StringRandom(r, 32), + OutboundTxObservedExternalHeight: r.Uint64(), + OutboundTxGasUsed: r.Uint64(), + OutboundTxEffectiveGasPrice: math.NewInt(r.Int63()), + CoinType: coinType, + } +} diff --git a/x/crosschain/keeper/migrator.go b/x/crosschain/keeper/migrator.go index 4de64140c8..51fe3a8f7d 100644 --- a/x/crosschain/keeper/migrator.go +++ b/x/crosschain/keeper/migrator.go @@ -6,6 +6,7 @@ import ( v3 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v3" v4 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v4" v5 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v5" + v6 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v6" ) // Migrator is a struct for handling in-place store migrations. @@ -39,3 +40,7 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error { func (m Migrator) Migrate4to5(ctx sdk.Context) error { return v5.MigrateStore(ctx, m.crossChainKeeper, m.crossChainKeeper.zetaObserverKeeper) } + +func (m Migrator) Migrate5to6(ctx sdk.Context) error { + return v6.MigrateStore(ctx, m.crossChainKeeper) +} diff --git a/x/crosschain/migrations/v6/migrate.go b/x/crosschain/migrations/v6/migrate.go index 87eae5e90e..ca95dc0cf4 100644 --- a/x/crosschain/migrations/v6/migrate.go +++ b/x/crosschain/migrations/v6/migrate.go @@ -1,7 +1,10 @@ package v6 import ( + "fmt" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/x/crosschain/types" @@ -21,7 +24,68 @@ type crosschainKeeper interface { // MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 // It resets the aborted zeta amount to use the inbound tx amount instead in situations where the outbound cctx is never created. -func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper, observerKeeper types.ObserverKeeper) error { +func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper) error { + cctxListV14 := GetV14CCTX(ctx, crosschainKeeper) + for _, cctx := range cctxListV14 { + OutBoundParamsV15 := make([]*types.OutboundTxParams, len(cctx.OutboundTxParams)) + for j, outBoundParams := range cctx.OutboundTxParams { + OutBoundParamsV15[j] = &types.OutboundTxParams{ + Receiver: outBoundParams.Receiver, + ReceiverChainId: outBoundParams.ReceiverChainId, + Amount: outBoundParams.Amount, + OutboundTxTssNonce: outBoundParams.OutboundTxTssNonce, + OutboundTxGasLimit: outBoundParams.OutboundTxGasLimit, + OutboundTxGasPrice: outBoundParams.OutboundTxGasPrice, + OutboundTxHash: outBoundParams.OutboundTxHash, + OutboundTxBallotIndex: outBoundParams.OutboundTxBallotIndex, + OutboundTxObservedExternalHeight: outBoundParams.OutboundTxObservedExternalHeight, + OutboundTxGasUsed: outBoundParams.OutboundTxGasUsed, + OutboundTxEffectiveGasPrice: outBoundParams.OutboundTxEffectiveGasPrice, + OutboundTxEffectiveGasLimit: outBoundParams.OutboundTxEffectiveGasLimit, + TssPubkey: outBoundParams.TssPubkey, + TxFinalizationStatus: outBoundParams.TxFinalizationStatus, + } + } + cctxV15 := types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + Sender: cctx.InboundTxParams.Sender, + SenderChainId: cctx.InboundTxParams.SenderChainId, + TxOrigin: cctx.InboundTxParams.TxOrigin, + Asset: cctx.InboundTxParams.Asset, + Amount: cctx.InboundTxParams.Amount, + InboundTxObservedHash: cctx.InboundTxParams.InboundTxObservedHash, + InboundTxObservedExternalHeight: cctx.InboundTxParams.InboundTxObservedExternalHeight, + InboundTxBallotIndex: cctx.InboundTxParams.InboundTxBallotIndex, + InboundTxFinalizedZetaHeight: cctx.InboundTxParams.InboundTxFinalizedZetaHeight, + TxFinalizationStatus: cctx.InboundTxParams.TxFinalizationStatus, + }, + Index: cctx.Index, + Creator: cctx.Creator, + OutboundTxParams: OutBoundParamsV15, + CctxStatus: cctx.CctxStatus, + CoinType: cctx.InboundTxParams.CoinType, + ZetaFees: cctx.ZetaFees, + RelayedMessage: cctx.RelayedMessage, + EventIndex: 1, // We don't have this information in the old version + } + crosschainKeeper.SetCrossChainTx(ctx, cctxV15) + } return nil } + +func GetV14CCTX(ctx sdk.Context, crosschainKeeper crosschainKeeper) (list []types.CrossChainTxV14) { + p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) + store := prefix.NewStore(ctx.KVStore(crosschainKeeper.GetStoreKey()), p) + + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.CrossChainTxV14 + crosschainKeeper.GetCodec().MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + return list +} diff --git a/x/crosschain/migrations/v6/migrate_test.go b/x/crosschain/migrations/v6/migrate_test.go index 41c0ebe310..30b9985918 100644 --- a/x/crosschain/migrations/v6/migrate_test.go +++ b/x/crosschain/migrations/v6/migrate_test.go @@ -1 +1,76 @@ package v6_test + +import ( + "fmt" + "sort" + "testing" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" + v6 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v6" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestMigrateStore(t *testing.T) { + t.Run("sucessfull migrate cctx from v14 to v15", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + v14cctxList := make([]*types.CrossChainTxV14, 10) + for i := 0; i < 10; i++ { + v14cctxList[i] = sample.CrossChainTxV14(t, fmt.Sprintf("%d-%s", i, "v14")) + SetCrossChainTxV14(ctx, *v14cctxList[i], k) + } + err := v6.MigrateStore(ctx, k) + require.NoError(t, err) + cctxListv15 := k.GetAllCrossChainTx(ctx) + require.Len(t, cctxListv15, 10) + sort.Slice(cctxListv15, func(i, j int) bool { + return cctxListv15[i].Index < cctxListv15[j].Index + }) + sort.Slice(v14cctxList, func(i, j int) bool { + return v14cctxList[i].Index < v14cctxList[j].Index + }) + for i := 0; i < 10; i++ { + require.Equal(t, v14cctxList[i].Index, cctxListv15[i].Index) + require.Equal(t, v14cctxList[i].Creator, cctxListv15[i].Creator) + require.Equal(t, v14cctxList[i].ZetaFees, cctxListv15[i].ZetaFees) + require.Equal(t, v14cctxList[i].RelayedMessage, cctxListv15[i].RelayedMessage) + require.Equal(t, v14cctxList[i].CctxStatus, cctxListv15[i].CctxStatus) + require.Equal(t, v14cctxList[i].InboundTxParams.Sender, cctxListv15[i].InboundTxParams.Sender) + require.Equal(t, v14cctxList[i].InboundTxParams.SenderChainId, cctxListv15[i].InboundTxParams.SenderChainId) + require.Equal(t, v14cctxList[i].InboundTxParams.TxOrigin, cctxListv15[i].InboundTxParams.TxOrigin) + require.Equal(t, v14cctxList[i].InboundTxParams.Asset, cctxListv15[i].InboundTxParams.Asset) + require.Equal(t, v14cctxList[i].InboundTxParams.Amount, cctxListv15[i].InboundTxParams.Amount) + require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxObservedHash, cctxListv15[i].InboundTxParams.InboundTxObservedHash) + require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxObservedExternalHeight, cctxListv15[i].InboundTxParams.InboundTxObservedExternalHeight) + require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxBallotIndex, cctxListv15[i].InboundTxParams.InboundTxBallotIndex) + require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxFinalizedZetaHeight, cctxListv15[i].InboundTxParams.InboundTxFinalizedZetaHeight) + require.Equal(t, v14cctxList[i].InboundTxParams.CoinType, cctxListv15[i].CoinType) + require.Len(t, v14cctxList[i].OutboundTxParams, len(cctxListv15[i].OutboundTxParams)) + for j := 0; j < len(cctxListv15[i].OutboundTxParams); j++ { + require.Equal(t, v14cctxList[i].OutboundTxParams[j].Receiver, cctxListv15[i].OutboundTxParams[j].Receiver) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].ReceiverChainId, cctxListv15[i].OutboundTxParams[j].ReceiverChainId) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].Amount, cctxListv15[i].OutboundTxParams[j].Amount) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxTssNonce, cctxListv15[i].OutboundTxParams[j].OutboundTxTssNonce) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasLimit, cctxListv15[i].OutboundTxParams[j].OutboundTxGasLimit) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasPrice, cctxListv15[i].OutboundTxParams[j].OutboundTxGasPrice) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxHash, cctxListv15[i].OutboundTxParams[j].OutboundTxHash) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxBallotIndex, cctxListv15[i].OutboundTxParams[j].OutboundTxBallotIndex) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxObservedExternalHeight, cctxListv15[i].OutboundTxParams[j].OutboundTxObservedExternalHeight) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasUsed, cctxListv15[i].OutboundTxParams[j].OutboundTxGasUsed) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxEffectiveGasPrice, cctxListv15[i].OutboundTxParams[j].OutboundTxEffectiveGasPrice) + require.Equal(t, v14cctxList[i].OutboundTxParams[j].CoinType, cctxListv15[i].CoinType) + } + } + }) +} + +func SetCrossChainTxV14(ctx sdk.Context, cctx types.CrossChainTxV14, k *keeper.Keeper) { + p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), p) + b := k.GetCodec().MustMarshal(&cctx) + store.Set(types.KeyPrefix(cctx.Index), b) +} diff --git a/x/crosschain/module.go b/x/crosschain/module.go index 7c81f220e8..4bc2aa5244 100644 --- a/x/crosschain/module.go +++ b/x/crosschain/module.go @@ -154,6 +154,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate4to5); err != nil { panic(err) } + if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate5to6); err != nil { + panic(err) + } + } // RegisterInvariants registers the crosschain module's invariants. @@ -181,7 +185,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 5 } +func (AppModule) ConsensusVersion() uint64 { return 6 } // BeginBlock executes all ABCI BeginBlock logic respective to the crosschain module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { diff --git a/x/crosschain/types/cross_chain_tx_v14.pb.go b/x/crosschain/types/cross_chain_tx_v14.pb.go new file mode 100644 index 0000000000..be51a85fd0 --- /dev/null +++ b/x/crosschain/types/cross_chain_tx_v14.pb.go @@ -0,0 +1,2051 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: crosschain/cross_chain_tx_v14.proto + +package types + +import ( + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + common "github.com/zeta-chain/zetacore/common" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type InboundTxParamsV14 struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + SenderChainId int64 `protobuf:"varint,2,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` + TxOrigin string `protobuf:"bytes,3,opt,name=tx_origin,json=txOrigin,proto3" json:"tx_origin,omitempty"` + CoinType common.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` + Asset string `protobuf:"bytes,5,opt,name=asset,proto3" json:"asset,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` + InboundTxObservedHash string `protobuf:"bytes,7,opt,name=inbound_tx_observed_hash,json=inboundTxObservedHash,proto3" json:"inbound_tx_observed_hash,omitempty"` + InboundTxObservedExternalHeight uint64 `protobuf:"varint,8,opt,name=inbound_tx_observed_external_height,json=inboundTxObservedExternalHeight,proto3" json:"inbound_tx_observed_external_height,omitempty"` + InboundTxBallotIndex string `protobuf:"bytes,9,opt,name=inbound_tx_ballot_index,json=inboundTxBallotIndex,proto3" json:"inbound_tx_ballot_index,omitempty"` + InboundTxFinalizedZetaHeight uint64 `protobuf:"varint,10,opt,name=inbound_tx_finalized_zeta_height,json=inboundTxFinalizedZetaHeight,proto3" json:"inbound_tx_finalized_zeta_height,omitempty"` + TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,11,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` +} + +func (m *InboundTxParamsV14) Reset() { *m = InboundTxParamsV14{} } +func (m *InboundTxParamsV14) String() string { return proto.CompactTextString(m) } +func (*InboundTxParamsV14) ProtoMessage() {} +func (*InboundTxParamsV14) Descriptor() ([]byte, []int) { + return fileDescriptor_9a400eff2bb43434, []int{0} +} +func (m *InboundTxParamsV14) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InboundTxParamsV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InboundTxParamsV14.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InboundTxParamsV14) XXX_Merge(src proto.Message) { + xxx_messageInfo_InboundTxParamsV14.Merge(m, src) +} +func (m *InboundTxParamsV14) XXX_Size() int { + return m.Size() +} +func (m *InboundTxParamsV14) XXX_DiscardUnknown() { + xxx_messageInfo_InboundTxParamsV14.DiscardUnknown(m) +} + +var xxx_messageInfo_InboundTxParamsV14 proto.InternalMessageInfo + +func (m *InboundTxParamsV14) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *InboundTxParamsV14) GetSenderChainId() int64 { + if m != nil { + return m.SenderChainId + } + return 0 +} + +func (m *InboundTxParamsV14) GetTxOrigin() string { + if m != nil { + return m.TxOrigin + } + return "" +} + +func (m *InboundTxParamsV14) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + +func (m *InboundTxParamsV14) GetAsset() string { + if m != nil { + return m.Asset + } + return "" +} + +func (m *InboundTxParamsV14) GetInboundTxObservedHash() string { + if m != nil { + return m.InboundTxObservedHash + } + return "" +} + +func (m *InboundTxParamsV14) GetInboundTxObservedExternalHeight() uint64 { + if m != nil { + return m.InboundTxObservedExternalHeight + } + return 0 +} + +func (m *InboundTxParamsV14) GetInboundTxBallotIndex() string { + if m != nil { + return m.InboundTxBallotIndex + } + return "" +} + +func (m *InboundTxParamsV14) GetInboundTxFinalizedZetaHeight() uint64 { + if m != nil { + return m.InboundTxFinalizedZetaHeight + } + return 0 +} + +func (m *InboundTxParamsV14) GetTxFinalizationStatus() TxFinalizationStatus { + if m != nil { + return m.TxFinalizationStatus + } + return TxFinalizationStatus_NotFinalized +} + +type OutboundTxParamsV14 struct { + Receiver string `protobuf:"bytes,1,opt,name=receiver,proto3" json:"receiver,omitempty"` + ReceiverChainId int64 `protobuf:"varint,2,opt,name=receiver_chainId,json=receiverChainId,proto3" json:"receiver_chainId,omitempty"` + CoinType common.CoinType `protobuf:"varint,3,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,4,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` + OutboundTxTssNonce uint64 `protobuf:"varint,5,opt,name=outbound_tx_tss_nonce,json=outboundTxTssNonce,proto3" json:"outbound_tx_tss_nonce,omitempty"` + OutboundTxGasLimit uint64 `protobuf:"varint,6,opt,name=outbound_tx_gas_limit,json=outboundTxGasLimit,proto3" json:"outbound_tx_gas_limit,omitempty"` + OutboundTxGasPrice string `protobuf:"bytes,7,opt,name=outbound_tx_gas_price,json=outboundTxGasPrice,proto3" json:"outbound_tx_gas_price,omitempty"` + // the above are commands for zetaclients + // the following fields are used when the outbound tx is mined + OutboundTxHash string `protobuf:"bytes,8,opt,name=outbound_tx_hash,json=outboundTxHash,proto3" json:"outbound_tx_hash,omitempty"` + OutboundTxBallotIndex string `protobuf:"bytes,9,opt,name=outbound_tx_ballot_index,json=outboundTxBallotIndex,proto3" json:"outbound_tx_ballot_index,omitempty"` + OutboundTxObservedExternalHeight uint64 `protobuf:"varint,10,opt,name=outbound_tx_observed_external_height,json=outboundTxObservedExternalHeight,proto3" json:"outbound_tx_observed_external_height,omitempty"` + OutboundTxGasUsed uint64 `protobuf:"varint,20,opt,name=outbound_tx_gas_used,json=outboundTxGasUsed,proto3" json:"outbound_tx_gas_used,omitempty"` + OutboundTxEffectiveGasPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,21,opt,name=outbound_tx_effective_gas_price,json=outboundTxEffectiveGasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"outbound_tx_effective_gas_price"` + OutboundTxEffectiveGasLimit uint64 `protobuf:"varint,22,opt,name=outbound_tx_effective_gas_limit,json=outboundTxEffectiveGasLimit,proto3" json:"outbound_tx_effective_gas_limit,omitempty"` + TssPubkey string `protobuf:"bytes,11,opt,name=tss_pubkey,json=tssPubkey,proto3" json:"tss_pubkey,omitempty"` + TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,12,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` +} + +func (m *OutboundTxParamsV14) Reset() { *m = OutboundTxParamsV14{} } +func (m *OutboundTxParamsV14) String() string { return proto.CompactTextString(m) } +func (*OutboundTxParamsV14) ProtoMessage() {} +func (*OutboundTxParamsV14) Descriptor() ([]byte, []int) { + return fileDescriptor_9a400eff2bb43434, []int{1} +} +func (m *OutboundTxParamsV14) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OutboundTxParamsV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OutboundTxParamsV14.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *OutboundTxParamsV14) XXX_Merge(src proto.Message) { + xxx_messageInfo_OutboundTxParamsV14.Merge(m, src) +} +func (m *OutboundTxParamsV14) XXX_Size() int { + return m.Size() +} +func (m *OutboundTxParamsV14) XXX_DiscardUnknown() { + xxx_messageInfo_OutboundTxParamsV14.DiscardUnknown(m) +} + +var xxx_messageInfo_OutboundTxParamsV14 proto.InternalMessageInfo + +func (m *OutboundTxParamsV14) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *OutboundTxParamsV14) GetReceiverChainId() int64 { + if m != nil { + return m.ReceiverChainId + } + return 0 +} + +func (m *OutboundTxParamsV14) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + +func (m *OutboundTxParamsV14) GetOutboundTxTssNonce() uint64 { + if m != nil { + return m.OutboundTxTssNonce + } + return 0 +} + +func (m *OutboundTxParamsV14) GetOutboundTxGasLimit() uint64 { + if m != nil { + return m.OutboundTxGasLimit + } + return 0 +} + +func (m *OutboundTxParamsV14) GetOutboundTxGasPrice() string { + if m != nil { + return m.OutboundTxGasPrice + } + return "" +} + +func (m *OutboundTxParamsV14) GetOutboundTxHash() string { + if m != nil { + return m.OutboundTxHash + } + return "" +} + +func (m *OutboundTxParamsV14) GetOutboundTxBallotIndex() string { + if m != nil { + return m.OutboundTxBallotIndex + } + return "" +} + +func (m *OutboundTxParamsV14) GetOutboundTxObservedExternalHeight() uint64 { + if m != nil { + return m.OutboundTxObservedExternalHeight + } + return 0 +} + +func (m *OutboundTxParamsV14) GetOutboundTxGasUsed() uint64 { + if m != nil { + return m.OutboundTxGasUsed + } + return 0 +} + +func (m *OutboundTxParamsV14) GetOutboundTxEffectiveGasLimit() uint64 { + if m != nil { + return m.OutboundTxEffectiveGasLimit + } + return 0 +} + +func (m *OutboundTxParamsV14) GetTssPubkey() string { + if m != nil { + return m.TssPubkey + } + return "" +} + +func (m *OutboundTxParamsV14) GetTxFinalizationStatus() TxFinalizationStatus { + if m != nil { + return m.TxFinalizationStatus + } + return TxFinalizationStatus_NotFinalized +} + +type CrossChainTxV14 struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` + ZetaFees github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,5,opt,name=zeta_fees,json=zetaFees,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"zeta_fees" yaml:"zeta_fees"` + RelayedMessage string `protobuf:"bytes,6,opt,name=relayed_message,json=relayedMessage,proto3" json:"relayed_message,omitempty"` + CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` + InboundTxParams *InboundTxParamsV14 `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` + OutboundTxParams []*OutboundTxParamsV14 `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` +} + +func (m *CrossChainTxV14) Reset() { *m = CrossChainTxV14{} } +func (m *CrossChainTxV14) String() string { return proto.CompactTextString(m) } +func (*CrossChainTxV14) ProtoMessage() {} +func (*CrossChainTxV14) Descriptor() ([]byte, []int) { + return fileDescriptor_9a400eff2bb43434, []int{2} +} +func (m *CrossChainTxV14) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CrossChainTxV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CrossChainTxV14.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *CrossChainTxV14) XXX_Merge(src proto.Message) { + xxx_messageInfo_CrossChainTxV14.Merge(m, src) +} +func (m *CrossChainTxV14) XXX_Size() int { + return m.Size() +} +func (m *CrossChainTxV14) XXX_DiscardUnknown() { + xxx_messageInfo_CrossChainTxV14.DiscardUnknown(m) +} + +var xxx_messageInfo_CrossChainTxV14 proto.InternalMessageInfo + +func (m *CrossChainTxV14) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *CrossChainTxV14) GetIndex() string { + if m != nil { + return m.Index + } + return "" +} + +func (m *CrossChainTxV14) GetRelayedMessage() string { + if m != nil { + return m.RelayedMessage + } + return "" +} + +func (m *CrossChainTxV14) GetCctxStatus() *Status { + if m != nil { + return m.CctxStatus + } + return nil +} + +func (m *CrossChainTxV14) GetInboundTxParams() *InboundTxParamsV14 { + if m != nil { + return m.InboundTxParams + } + return nil +} + +func (m *CrossChainTxV14) GetOutboundTxParams() []*OutboundTxParamsV14 { + if m != nil { + return m.OutboundTxParams + } + return nil +} + +func init() { + proto.RegisterType((*InboundTxParamsV14)(nil), "zetachain.zetacore.crosschain.InboundTxParamsV14") + proto.RegisterType((*OutboundTxParamsV14)(nil), "zetachain.zetacore.crosschain.OutboundTxParamsV14") + proto.RegisterType((*CrossChainTxV14)(nil), "zetachain.zetacore.crosschain.CrossChainTxV14") +} + +func init() { + proto.RegisterFile("crosschain/cross_chain_tx_v14.proto", fileDescriptor_9a400eff2bb43434) +} + +var fileDescriptor_9a400eff2bb43434 = []byte{ + // 913 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x51, 0x6f, 0x1a, 0x47, + 0x10, 0x36, 0x81, 0xd8, 0x30, 0xb4, 0x86, 0x6c, 0xb0, 0x7b, 0x72, 0x1a, 0x40, 0x4e, 0x9b, 0xd0, + 0x07, 0x73, 0x82, 0xa4, 0x8a, 0xd4, 0x47, 0xbb, 0x71, 0x82, 0x9a, 0xc6, 0xd6, 0xd5, 0xe9, 0x43, + 0xa4, 0xea, 0xb2, 0xdc, 0x8d, 0x61, 0x15, 0xb8, 0x45, 0xb7, 0x8b, 0x75, 0xe4, 0x57, 0xf4, 0xad, + 0x7f, 0x29, 0x8f, 0x79, 0xa9, 0x54, 0xf5, 0xc1, 0xaa, 0xec, 0x3f, 0x50, 0xf5, 0x17, 0x54, 0xbb, + 0x7b, 0x77, 0x1c, 0x36, 0xb6, 0x5b, 0xb5, 0x4f, 0xcc, 0xce, 0xce, 0xf7, 0xed, 0xee, 0xcc, 0x37, + 0xc3, 0xc1, 0x03, 0x2f, 0xe4, 0x42, 0x78, 0x43, 0xca, 0x02, 0x5b, 0x9b, 0xae, 0xb6, 0x5d, 0x19, + 0xb9, 0x27, 0x9d, 0x27, 0xed, 0x49, 0xc8, 0x25, 0x27, 0xf7, 0xdf, 0xa3, 0xa4, 0xda, 0xdf, 0xd6, + 0x16, 0x0f, 0xb1, 0x3d, 0xc7, 0x6d, 0xdd, 0xf5, 0xf8, 0x78, 0xcc, 0x03, 0xdb, 0xfc, 0x18, 0xcc, + 0x56, 0xe3, 0x4a, 0xe2, 0x38, 0xa0, 0x36, 0xe0, 0x03, 0xae, 0x4d, 0x5b, 0x59, 0xc6, 0xbb, 0xfd, + 0x67, 0x01, 0x48, 0x2f, 0xe8, 0xf3, 0x69, 0xe0, 0x1f, 0x45, 0x87, 0x34, 0xa4, 0x63, 0xf1, 0x63, + 0xe7, 0x09, 0xd9, 0x84, 0x55, 0x81, 0x81, 0x8f, 0xa1, 0x95, 0x6b, 0xe6, 0x5a, 0x25, 0x27, 0x5e, + 0x91, 0x87, 0x50, 0x31, 0x56, 0xcc, 0xce, 0x7c, 0xeb, 0x56, 0x33, 0xd7, 0xca, 0x3b, 0x9f, 0x1a, + 0xf7, 0x9e, 0xf2, 0xf6, 0x7c, 0x72, 0x0f, 0x4a, 0x32, 0x72, 0x79, 0xc8, 0x06, 0x2c, 0xb0, 0xf2, + 0x9a, 0xa2, 0x28, 0xa3, 0x03, 0xbd, 0x26, 0x3b, 0x50, 0xf2, 0xb8, 0xba, 0xda, 0x6c, 0x82, 0x56, + 0xa1, 0x99, 0x6b, 0xad, 0x77, 0xab, 0xed, 0xf8, 0x31, 0x7b, 0x9c, 0x05, 0x47, 0xb3, 0x09, 0x3a, + 0x45, 0x2f, 0xb6, 0x48, 0x0d, 0x6e, 0x53, 0x21, 0x50, 0x5a, 0xb7, 0x35, 0x8f, 0x59, 0x90, 0xe7, + 0xb0, 0x4a, 0xc7, 0x7c, 0x1a, 0x48, 0x6b, 0x55, 0xb9, 0x77, 0xed, 0x0f, 0xa7, 0x8d, 0x95, 0xdf, + 0x4f, 0x1b, 0x8f, 0x06, 0x4c, 0x0e, 0xa7, 0x7d, 0xc5, 0x67, 0x7b, 0x5c, 0x8c, 0xb9, 0x88, 0x7f, + 0x76, 0x84, 0xff, 0xce, 0x56, 0x47, 0x8a, 0xf6, 0x6b, 0x16, 0x48, 0x27, 0x86, 0x93, 0xa7, 0x60, + 0x31, 0x93, 0x00, 0x55, 0x04, 0xde, 0x17, 0x18, 0x9e, 0xa0, 0xef, 0x0e, 0xa9, 0x18, 0x5a, 0x6b, + 0xfa, 0xc4, 0x0d, 0x96, 0x24, 0xe8, 0x20, 0xde, 0x7d, 0x41, 0xc5, 0x90, 0xbc, 0x84, 0x07, 0xcb, + 0x80, 0x18, 0x49, 0x0c, 0x03, 0x3a, 0x72, 0x87, 0xc8, 0x06, 0x43, 0x69, 0x15, 0x9b, 0xb9, 0x56, + 0xc1, 0x69, 0x5c, 0xe2, 0x78, 0x16, 0xc7, 0xbd, 0xd0, 0x61, 0xe4, 0x6b, 0xf8, 0x2c, 0xc3, 0xd6, + 0xa7, 0xa3, 0x11, 0x97, 0x2e, 0x0b, 0x7c, 0x8c, 0xac, 0x92, 0xbe, 0x45, 0x2d, 0x65, 0xd8, 0xd5, + 0x9b, 0x3d, 0xb5, 0x47, 0xf6, 0xa1, 0x99, 0x81, 0x1d, 0xb3, 0x80, 0x8e, 0xd8, 0x7b, 0xf4, 0x5d, + 0xa5, 0x9b, 0xe4, 0x06, 0xa0, 0x6f, 0xf0, 0x79, 0x8a, 0xdf, 0x4f, 0xa2, 0xde, 0xa0, 0xa4, 0xf1, + 0xf1, 0x0c, 0x36, 0xe7, 0x78, 0x2a, 0x19, 0x0f, 0x5c, 0x21, 0xa9, 0x9c, 0x0a, 0xab, 0xac, 0x0b, + 0xf4, 0xb8, 0x7d, 0xad, 0x26, 0xdb, 0x29, 0xab, 0xc6, 0xfe, 0xa0, 0xa1, 0x4e, 0x4d, 0x2e, 0xf1, + 0x6e, 0xff, 0xb2, 0x06, 0x77, 0x0f, 0xa6, 0xf2, 0x92, 0xe6, 0xb6, 0xa0, 0x18, 0xa2, 0x87, 0xec, + 0x24, 0x55, 0x5d, 0xba, 0x26, 0x5f, 0x41, 0x35, 0xb1, 0x8d, 0xf2, 0x7a, 0x89, 0xf0, 0x2a, 0x89, + 0x3f, 0x91, 0xde, 0x82, 0xba, 0xf2, 0x37, 0xaa, 0x6b, 0xae, 0xa3, 0xc2, 0x7f, 0xd3, 0x51, 0x07, + 0x36, 0x78, 0xfc, 0x2a, 0x55, 0x0a, 0x29, 0x84, 0x1b, 0xf0, 0xc0, 0x43, 0x2d, 0xdb, 0x82, 0x43, + 0x78, 0xfa, 0xe4, 0x23, 0x21, 0x5e, 0xa9, 0x9d, 0x8b, 0x90, 0x01, 0x15, 0xee, 0x88, 0x8d, 0x99, + 0x91, 0xf4, 0x02, 0xe4, 0x39, 0x15, 0x2f, 0xd5, 0xce, 0x32, 0xc8, 0x24, 0x64, 0x1e, 0xc6, 0x52, + 0x5d, 0x84, 0x1c, 0xaa, 0x1d, 0xd2, 0x82, 0x6a, 0x16, 0xa2, 0x85, 0x5d, 0xd4, 0xd1, 0xeb, 0xf3, + 0x68, 0xad, 0xe8, 0xa7, 0x60, 0x65, 0x23, 0x97, 0x88, 0x70, 0x63, 0x8e, 0xc8, 0xaa, 0xf0, 0x15, + 0x7c, 0x91, 0x05, 0x5e, 0xd9, 0x0b, 0x46, 0x89, 0xcd, 0x39, 0xc9, 0x15, 0xcd, 0x60, 0x43, 0xed, + 0xe2, 0x2b, 0xa7, 0x02, 0x7d, 0xab, 0xa6, 0xf1, 0x77, 0x16, 0x1e, 0xf9, 0x5a, 0xa0, 0x4f, 0x24, + 0x34, 0xb2, 0x00, 0x3c, 0x3e, 0x46, 0x4f, 0xb2, 0x13, 0xcc, 0x24, 0x68, 0x43, 0x97, 0xb7, 0x1d, + 0x97, 0xf7, 0xe1, 0x3f, 0x28, 0x6f, 0x2f, 0x90, 0xce, 0xbd, 0xf9, 0x59, 0xcf, 0x12, 0xd2, 0x34, + 0xb3, 0xdf, 0x5e, 0x77, 0xaa, 0xa9, 0xe4, 0xa6, 0xbe, 0xf1, 0x15, 0x2c, 0xa6, 0xa4, 0xf7, 0x01, + 0x94, 0x58, 0x26, 0xd3, 0xfe, 0x3b, 0x9c, 0xe9, 0x76, 0x2b, 0x39, 0x25, 0x29, 0xc4, 0xa1, 0x76, + 0x5c, 0xd3, 0x99, 0x9f, 0xfc, 0xdf, 0x9d, 0xf9, 0x6b, 0x1e, 0x2a, 0x7b, 0x0a, 0xa9, 0x7b, 0xe9, + 0x28, 0x52, 0x5d, 0x69, 0xc1, 0x9a, 0x17, 0x22, 0x95, 0x3c, 0x69, 0xca, 0x64, 0xa9, 0xe6, 0xb2, + 0x91, 0xc6, 0x2d, 0x33, 0x97, 0xf5, 0x82, 0xbc, 0x85, 0x92, 0x9e, 0x3d, 0xc7, 0x88, 0xc2, 0x4c, + 0xec, 0xdd, 0xbd, 0x7f, 0xd9, 0x52, 0x7f, 0x9d, 0x36, 0xaa, 0x33, 0x3a, 0x1e, 0x7d, 0xb3, 0x9d, + 0x32, 0x6d, 0x3b, 0x45, 0x65, 0xef, 0x23, 0x0a, 0xf2, 0x08, 0x2a, 0x21, 0x8e, 0xe8, 0x0c, 0x7d, + 0x77, 0x8c, 0x42, 0xd0, 0x01, 0x9a, 0xbf, 0x00, 0x67, 0x3d, 0x76, 0x7f, 0x6f, 0xbc, 0x64, 0x1f, + 0xca, 0x9e, 0x27, 0xa3, 0x24, 0x5d, 0x4a, 0xf3, 0xe5, 0xee, 0x97, 0x37, 0xa4, 0x2b, 0x4e, 0x10, + 0x28, 0xa4, 0xb1, 0xc9, 0x4f, 0x70, 0x27, 0x33, 0x63, 0x27, 0x7a, 0x60, 0xe9, 0x7e, 0x28, 0x77, + 0x3b, 0x37, 0xb0, 0x5d, 0xfe, 0x6b, 0x75, 0x2a, 0x6c, 0xd1, 0x47, 0xde, 0x02, 0xc9, 0xaa, 0x28, + 0xe6, 0x87, 0x66, 0xbe, 0x55, 0xee, 0x76, 0x6f, 0xe0, 0x5f, 0x32, 0x47, 0x9d, 0x2a, 0xbf, 0xe0, + 0xdc, 0xfd, 0xee, 0xc3, 0x59, 0x3d, 0xf7, 0xf1, 0xac, 0x9e, 0xfb, 0xe3, 0xac, 0x9e, 0xfb, 0xf9, + 0xbc, 0xbe, 0xf2, 0xf1, 0xbc, 0xbe, 0xf2, 0xdb, 0x79, 0x7d, 0xe5, 0x4d, 0x27, 0x53, 0x12, 0xc5, + 0xbf, 0x63, 0x3e, 0x20, 0x92, 0xa3, 0xec, 0xc8, 0xce, 0x7c, 0x56, 0xe8, 0x0a, 0xf5, 0x57, 0xf5, + 0x87, 0xc3, 0xe3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x77, 0x00, 0xe1, 0x29, 0xca, 0x08, 0x00, + 0x00, +} + +func (m *InboundTxParamsV14) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InboundTxParamsV14) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InboundTxParamsV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TxFinalizationStatus != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.TxFinalizationStatus)) + i-- + dAtA[i] = 0x58 + } + if m.InboundTxFinalizedZetaHeight != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.InboundTxFinalizedZetaHeight)) + i-- + dAtA[i] = 0x50 + } + if len(m.InboundTxBallotIndex) > 0 { + i -= len(m.InboundTxBallotIndex) + copy(dAtA[i:], m.InboundTxBallotIndex) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.InboundTxBallotIndex))) + i-- + dAtA[i] = 0x4a + } + if m.InboundTxObservedExternalHeight != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.InboundTxObservedExternalHeight)) + i-- + dAtA[i] = 0x40 + } + if len(m.InboundTxObservedHash) > 0 { + i -= len(m.InboundTxObservedHash) + copy(dAtA[i:], m.InboundTxObservedHash) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.InboundTxObservedHash))) + i-- + dAtA[i] = 0x3a + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.Asset) > 0 { + i -= len(m.Asset) + copy(dAtA[i:], m.Asset) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Asset))) + i-- + dAtA[i] = 0x2a + } + if m.CoinType != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x20 + } + if len(m.TxOrigin) > 0 { + i -= len(m.TxOrigin) + copy(dAtA[i:], m.TxOrigin) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.TxOrigin))) + i-- + dAtA[i] = 0x1a + } + if m.SenderChainId != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.SenderChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *OutboundTxParamsV14) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OutboundTxParamsV14) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OutboundTxParamsV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.OutboundTxEffectiveGasLimit != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxEffectiveGasLimit)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb0 + } + { + size := m.OutboundTxEffectiveGasPrice.Size() + i -= size + if _, err := m.OutboundTxEffectiveGasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xaa + if m.OutboundTxGasUsed != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxGasUsed)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.TxFinalizationStatus != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.TxFinalizationStatus)) + i-- + dAtA[i] = 0x60 + } + if len(m.TssPubkey) > 0 { + i -= len(m.TssPubkey) + copy(dAtA[i:], m.TssPubkey) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.TssPubkey))) + i-- + dAtA[i] = 0x5a + } + if m.OutboundTxObservedExternalHeight != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxObservedExternalHeight)) + i-- + dAtA[i] = 0x50 + } + if len(m.OutboundTxBallotIndex) > 0 { + i -= len(m.OutboundTxBallotIndex) + copy(dAtA[i:], m.OutboundTxBallotIndex) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxBallotIndex))) + i-- + dAtA[i] = 0x4a + } + if len(m.OutboundTxHash) > 0 { + i -= len(m.OutboundTxHash) + copy(dAtA[i:], m.OutboundTxHash) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxHash))) + i-- + dAtA[i] = 0x42 + } + if len(m.OutboundTxGasPrice) > 0 { + i -= len(m.OutboundTxGasPrice) + copy(dAtA[i:], m.OutboundTxGasPrice) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxGasPrice))) + i-- + dAtA[i] = 0x3a + } + if m.OutboundTxGasLimit != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxGasLimit)) + i-- + dAtA[i] = 0x30 + } + if m.OutboundTxTssNonce != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxTssNonce)) + i-- + dAtA[i] = 0x28 + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.CoinType != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x18 + } + if m.ReceiverChainId != 0 { + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.ReceiverChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *CrossChainTxV14) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CrossChainTxV14) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CrossChainTxV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.OutboundTxParams) > 0 { + for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.OutboundTxParams[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if m.InboundTxParams != nil { + { + size, err := m.InboundTxParams.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + if m.CctxStatus != nil { + { + size, err := m.CctxStatus.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if len(m.RelayedMessage) > 0 { + i -= len(m.RelayedMessage) + copy(dAtA[i:], m.RelayedMessage) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.RelayedMessage))) + i-- + dAtA[i] = 0x32 + } + { + size := m.ZetaFees.Size() + i -= size + if _, err := m.ZetaFees.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.Index) > 0 { + i -= len(m.Index) + copy(dAtA[i:], m.Index) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Index))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintCrossChainTxV14(dAtA []byte, offset int, v uint64) int { + offset -= sovCrossChainTxV14(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *InboundTxParamsV14) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.SenderChainId != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.SenderChainId)) + } + l = len(m.TxOrigin) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.CoinType != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.CoinType)) + } + l = len(m.Asset) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + l = len(m.InboundTxObservedHash) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.InboundTxObservedExternalHeight != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.InboundTxObservedExternalHeight)) + } + l = len(m.InboundTxBallotIndex) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.InboundTxFinalizedZetaHeight != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.InboundTxFinalizedZetaHeight)) + } + if m.TxFinalizationStatus != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.TxFinalizationStatus)) + } + return n +} + +func (m *OutboundTxParamsV14) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.ReceiverChainId != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.ReceiverChainId)) + } + if m.CoinType != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.CoinType)) + } + l = m.Amount.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + if m.OutboundTxTssNonce != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxTssNonce)) + } + if m.OutboundTxGasLimit != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxGasLimit)) + } + l = len(m.OutboundTxGasPrice) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + l = len(m.OutboundTxHash) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + l = len(m.OutboundTxBallotIndex) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.OutboundTxObservedExternalHeight != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxObservedExternalHeight)) + } + l = len(m.TssPubkey) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.TxFinalizationStatus != 0 { + n += 1 + sovCrossChainTxV14(uint64(m.TxFinalizationStatus)) + } + if m.OutboundTxGasUsed != 0 { + n += 2 + sovCrossChainTxV14(uint64(m.OutboundTxGasUsed)) + } + l = m.OutboundTxEffectiveGasPrice.Size() + n += 2 + l + sovCrossChainTxV14(uint64(l)) + if m.OutboundTxEffectiveGasLimit != 0 { + n += 2 + sovCrossChainTxV14(uint64(m.OutboundTxEffectiveGasLimit)) + } + return n +} + +func (m *CrossChainTxV14) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + l = len(m.Index) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + l = m.ZetaFees.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + l = len(m.RelayedMessage) + if l > 0 { + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.CctxStatus != nil { + l = m.CctxStatus.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if m.InboundTxParams != nil { + l = m.InboundTxParams.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + if len(m.OutboundTxParams) > 0 { + for _, e := range m.OutboundTxParams { + l = e.Size() + n += 1 + l + sovCrossChainTxV14(uint64(l)) + } + } + return n +} + +func sovCrossChainTxV14(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozCrossChainTxV14(x uint64) (n int) { + return sovCrossChainTxV14(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *InboundTxParamsV14) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InboundTxParamsV14: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InboundTxParamsV14: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderChainId", wireType) + } + m.SenderChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SenderChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxOrigin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxOrigin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Asset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InboundTxObservedHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InboundTxObservedHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InboundTxObservedExternalHeight", wireType) + } + m.InboundTxObservedExternalHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InboundTxObservedExternalHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InboundTxBallotIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InboundTxBallotIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InboundTxFinalizedZetaHeight", wireType) + } + m.InboundTxFinalizedZetaHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InboundTxFinalizedZetaHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) + } + m.TxFinalizationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OutboundTxParamsV14) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OutboundTxParamsV14: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OutboundTxParamsV14: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReceiverChainId", wireType) + } + m.ReceiverChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReceiverChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxTssNonce", wireType) + } + m.OutboundTxTssNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutboundTxTssNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasLimit", wireType) + } + m.OutboundTxGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutboundTxGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OutboundTxGasPrice = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OutboundTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxBallotIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OutboundTxBallotIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxObservedExternalHeight", wireType) + } + m.OutboundTxObservedExternalHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutboundTxObservedExternalHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TssPubkey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TssPubkey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) + } + m.TxFinalizationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasUsed", wireType) + } + m.OutboundTxGasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutboundTxGasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 21: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxEffectiveGasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.OutboundTxEffectiveGasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 22: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxEffectiveGasLimit", wireType) + } + m.OutboundTxEffectiveGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutboundTxEffectiveGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CrossChainTxV14) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CrossChainTxV14: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CrossChainTxV14: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Index = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ZetaFees", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ZetaFees.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RelayedMessage", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RelayedMessage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CctxStatus", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CctxStatus == nil { + m.CctxStatus = &Status{} + } + if err := m.CctxStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InboundTxParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.InboundTxParams == nil { + m.InboundTxParams = &InboundTxParamsV14{} + } + if err := m.InboundTxParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxParams", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OutboundTxParams = append(m.OutboundTxParams, &OutboundTxParamsV14{}) + if err := m.OutboundTxParams[len(m.OutboundTxParams)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCrossChainTxV14 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCrossChainTxV14(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCrossChainTxV14 + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthCrossChainTxV14 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupCrossChainTxV14 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthCrossChainTxV14 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthCrossChainTxV14 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCrossChainTxV14 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupCrossChainTxV14 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/observer/client/cli/tx_updat_observer_test.go b/x/observer/client/cli/tx_updat_observer_test.go new file mode 100644 index 0000000000..c32a4216f8 --- /dev/null +++ b/x/observer/client/cli/tx_updat_observer_test.go @@ -0,0 +1,13 @@ +package cli_test + +import ( + "fmt" + "testing" + + "github.com/zeta-chain/zetacore/x/observer/client/cli" +) + +func Test_UpdateObserver(t *testing.T) { + r, err := cli.ParseUpdateReason(0) + fmt.Println(r, err) +} diff --git a/x/observer/client/cli/tx_update_observer.go b/x/observer/client/cli/tx_update_observer.go index f052106136..fbdab40555 100644 --- a/x/observer/client/cli/tx_update_observer.go +++ b/x/observer/client/cli/tx_update_observer.go @@ -28,7 +28,7 @@ func CmdUpdateObserver() *cobra.Command { return err } // #nosec G701 parsed in range - updateReason, err := parseUpdateReason(int32(updateReasonInt)) + updateReason, err := ParseUpdateReason(int32(updateReasonInt)) if err != nil { return err } @@ -48,7 +48,7 @@ func CmdUpdateObserver() *cobra.Command { return cmd } -func parseUpdateReason(i int32) (types.ObserverUpdateReason, error) { +func ParseUpdateReason(i int32) (types.ObserverUpdateReason, error) { if _, ok := types.ObserverUpdateReason_name[i]; ok { switch i { case 1: From 1c1fea65d98d299033dd3e3de27ece0146d49e33 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sat, 9 Mar 2024 00:33:13 -0500 Subject: [PATCH 13/36] set module version --- x/crosschain/module.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crosschain/module.go b/x/crosschain/module.go index 4bc2aa5244..197ecb2564 100644 --- a/x/crosschain/module.go +++ b/x/crosschain/module.go @@ -154,7 +154,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate4to5); err != nil { panic(err) } - if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate5to6); err != nil { + if err := cfg.RegisterMigration(types.ModuleName, 5, m.Migrate5to6); err != nil { panic(err) } From 4cdfaf8441802b16381dfb974b3f9c8eb3eb8b8c Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sat, 9 Mar 2024 00:50:40 -0500 Subject: [PATCH 14/36] fix unit tests --- x/crosschain/keeper/cctx_utils.go | 2 +- x/crosschain/migrations/v6/migrate_test.go | 2 +- x/crosschain/types/cctx_utils.go | 10 ++++++++-- x/crosschain/types/cctx_utils_test.go | 1 + x/crosschain/types/message_refund_aborted_test.go | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 43917f4520..f4ff43840b 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -92,7 +92,7 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C nonce, found := k.GetObserverKeeper().GetChainNonces(ctx, chain.ChainName.String()) if !found { - return cosmoserrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String())) + return cosmoserrors.Wrap(types.ErrCannotFindReceiverNonce, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX())) } // SET nonce diff --git a/x/crosschain/migrations/v6/migrate_test.go b/x/crosschain/migrations/v6/migrate_test.go index 30b9985918..a6bb9eed8f 100644 --- a/x/crosschain/migrations/v6/migrate_test.go +++ b/x/crosschain/migrations/v6/migrate_test.go @@ -16,7 +16,7 @@ import ( ) func TestMigrateStore(t *testing.T) { - t.Run("sucessfull migrate cctx from v14 to v15", func(t *testing.T) { + t.Run("successful migrate cctx from v14 to v15", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) v14cctxList := make([]*types.CrossChainTxV14, 10) for i := 0; i < 10; i++ { diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index 5f0b4b15f8..2d0dff74bf 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -137,6 +137,12 @@ func (m OutboundTxParams) Validate() error { return err } } + if m.OutboundTxHash != "" { + err = ValidateHashForChain(m.OutboundTxHash, m.ReceiverChainId) + if err != nil { + return err + } + } return nil } @@ -147,7 +153,7 @@ func ValidateZetaIndex(index string) error { return nil } func ValidateHashForChain(hash string, chainID int64) error { - if common.IsEthereumChain(chainID) { + if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { _, err := hexutil.Decode(hash) if err != nil { return fmt.Errorf("hash must be a valid ethereum hash %s", hash) @@ -168,7 +174,7 @@ func ValidateHashForChain(hash string, chainID int64) error { } func ValidateAddressForChain(address string, chainID int64) error { - if common.IsEthereumChain(chainID) { + if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { if !ethcommon.IsHexAddress(address) { return fmt.Errorf("invalid address %s", address) } diff --git a/x/crosschain/types/cctx_utils_test.go b/x/crosschain/types/cctx_utils_test.go index f3368ea386..28d35b577d 100644 --- a/x/crosschain/types/cctx_utils_test.go +++ b/x/crosschain/types/cctx_utils_test.go @@ -90,6 +90,7 @@ func TestOutboundTxParams_Validate(t *testing.T) { require.ErrorContains(t, outTxParams.Validate(), "invalid index hash 12") outTxParams = sample.OutboundTxParamsValidChainId(r) outTxParams.OutboundTxBallotIndex = sample.ZetaIndex(t) + outTxParams.OutboundTxHash = sample.Hash().String() require.NoError(t, outTxParams.Validate()) } diff --git a/x/crosschain/types/message_refund_aborted_test.go b/x/crosschain/types/message_refund_aborted_test.go index 40c432881b..c0bb3f7537 100644 --- a/x/crosschain/types/message_refund_aborted_test.go +++ b/x/crosschain/types/message_refund_aborted_test.go @@ -21,7 +21,7 @@ func TestNewMsgRefundAbortedCCTX(t *testing.T) { }) t.Run("invalid cctx index", func(t *testing.T) { msg := types.NewMsgRefundAbortedCCTX(sample.AccAddress(), "invalid", "") - require.ErrorContains(t, msg.ValidateBasic(), "invalid cctx index") + require.ErrorContains(t, msg.ValidateBasic(), "invalid index hash") }) t.Run("invalid refund address", func(t *testing.T) { cctx := sample.CrossChainTx(t, "test") From 8d17e2dcc0df17f61781ce610ead3514cb856907 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Sat, 9 Mar 2024 01:04:09 -0500 Subject: [PATCH 15/36] remove unnecessary test --- x/observer/client/cli/tx_updat_observer_test.go | 13 ------------- x/observer/client/cli/tx_update_observer.go | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 x/observer/client/cli/tx_updat_observer_test.go diff --git a/x/observer/client/cli/tx_updat_observer_test.go b/x/observer/client/cli/tx_updat_observer_test.go deleted file mode 100644 index c32a4216f8..0000000000 --- a/x/observer/client/cli/tx_updat_observer_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package cli_test - -import ( - "fmt" - "testing" - - "github.com/zeta-chain/zetacore/x/observer/client/cli" -) - -func Test_UpdateObserver(t *testing.T) { - r, err := cli.ParseUpdateReason(0) - fmt.Println(r, err) -} diff --git a/x/observer/client/cli/tx_update_observer.go b/x/observer/client/cli/tx_update_observer.go index fbdab40555..f052106136 100644 --- a/x/observer/client/cli/tx_update_observer.go +++ b/x/observer/client/cli/tx_update_observer.go @@ -28,7 +28,7 @@ func CmdUpdateObserver() *cobra.Command { return err } // #nosec G701 parsed in range - updateReason, err := ParseUpdateReason(int32(updateReasonInt)) + updateReason, err := parseUpdateReason(int32(updateReasonInt)) if err != nil { return err } @@ -48,7 +48,7 @@ func CmdUpdateObserver() *cobra.Command { return cmd } -func ParseUpdateReason(i int32) (types.ObserverUpdateReason, error) { +func parseUpdateReason(i int32) (types.ObserverUpdateReason, error) { if _, ok := types.ObserverUpdateReason_name[i]; ok { switch i { case 1: From eb51c8967366d727dcde83fa049f5597d18d699a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 11 Mar 2024 02:42:31 -0400 Subject: [PATCH 16/36] update upgrade docker file --- Dockerfile-upgrade | 4 ++-- x/crosschain/keeper/cctx_utils.go | 8 ++++---- x/crosschain/migrations/v6/migrate.go | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Dockerfile-upgrade b/Dockerfile-upgrade index 065f8622f0..e53b766256 100644 --- a/Dockerfile-upgrade +++ b/Dockerfile-upgrade @@ -20,8 +20,8 @@ WORKDIR /go/delivery/zeta-node RUN mkdir -p $GOPATH/bin/old RUN mkdir -p $GOPATH/bin/new -ARG OLD_VERSION=v13.0.0 -ENV NEW_VERSION=v14 +ARG OLD_VERSION=v14.0.0 +ENV NEW_VERSION=v15 # Build new release from the current source COPY go.mod /go/delivery/zeta-node/ diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index f4ff43840b..381b7a9b7e 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -226,10 +226,10 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) // we create a new cached context, and we don't commit the previous one with EVM deposit - tmpCtx, commit := ctx.CacheContext() + tmpCtxRevert, commitRevert := ctx.CacheContext() err = func() error { err := k.PayGasAndUpdateCctx( - tmpCtx, + tmpCtxRevert, senderChain.ChainId, cctx, cctx.InboundTxParams.Amount, @@ -239,13 +239,13 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return err } // Update nonce using senderchain id as this is a revert tx and would go back to the original sender - return k.UpdateNonce(tmpCtx, senderChain.ChainId, cctx) + return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) }() if err != nil { cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) return } - commit() + commitRevert() cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) return } diff --git a/x/crosschain/migrations/v6/migrate.go b/x/crosschain/migrations/v6/migrate.go index ca95dc0cf4..fb00ff2574 100644 --- a/x/crosschain/migrations/v6/migrate.go +++ b/x/crosschain/migrations/v6/migrate.go @@ -25,7 +25,8 @@ type crosschainKeeper interface { // MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 // It resets the aborted zeta amount to use the inbound tx amount instead in situations where the outbound cctx is never created. func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper) error { - cctxListV14 := GetV14CCTX(ctx, crosschainKeeper) + tmpctx, commit := ctx.CacheContext() + cctxListV14 := GetV14CCTX(tmpctx, crosschainKeeper) for _, cctx := range cctxListV14 { OutBoundParamsV15 := make([]*types.OutboundTxParams, len(cctx.OutboundTxParams)) for j, outBoundParams := range cctx.OutboundTxParams { @@ -69,8 +70,9 @@ func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper) error { RelayedMessage: cctx.RelayedMessage, EventIndex: 1, // We don't have this information in the old version } - crosschainKeeper.SetCrossChainTx(ctx, cctxV15) + crosschainKeeper.SetCrossChainTx(tmpctx, cctxV15) } + commit() return nil } From 77ae6847a76740dbe0c782fb67f31b8ac5c305b9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 11 Mar 2024 03:21:01 -0400 Subject: [PATCH 17/36] generate files --- docs/openapi/openapi.swagger.yaml | 9 +- typescript/crosschain/cross_chain_tx_pb.d.ts | 20 +- .../crosschain/cross_chain_tx_v14_pb.d.ts | 243 ++++++++++++++++++ typescript/crosschain/index.d.ts | 1 + 4 files changed, 259 insertions(+), 14 deletions(-) create mode 100644 typescript/crosschain/cross_chain_tx_v14_pb.d.ts diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 8e2cb02f21..e658cefb3b 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -53657,6 +53657,11 @@ definitions: items: type: object $ref: '#/definitions/crosschainOutboundTxParams' + event_index: + type: string + format: uint64 + coin_type: + $ref: '#/definitions/commonCoinType' crosschainGasPrice: type: object properties: @@ -53715,8 +53720,6 @@ definitions: tx_origin: type: string title: this address is the EOA that signs the inbound tx - coin_type: - $ref: '#/definitions/commonCoinType' asset: type: string title: for ERC20 coin type, the asset is an address of the ERC20 contract @@ -53807,8 +53810,6 @@ definitions: receiver_chainId: type: string format: int64 - coin_type: - $ref: '#/definitions/commonCoinType' amount: type: string outbound_tx_tss_nonce: diff --git a/typescript/crosschain/cross_chain_tx_pb.d.ts b/typescript/crosschain/cross_chain_tx_pb.d.ts index 0157548d54..a370b8a079 100644 --- a/typescript/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/crosschain/cross_chain_tx_pb.d.ts @@ -103,11 +103,6 @@ export declare class InboundTxParams extends Message { */ txOrigin: string; - /** - * @generated from field: common.CoinType coin_type = 4; - */ - coinType: CoinType; - /** * for ERC20 coin type, the asset is an address of the ERC20 contract * @@ -200,11 +195,6 @@ export declare class OutboundTxParams extends Message { */ receiverChainId: bigint; - /** - * @generated from field: common.CoinType coin_type = 3; - */ - coinType: CoinType; - /** * @generated from field: string amount = 4; */ @@ -363,6 +353,16 @@ export declare class CrossChainTx extends Message { */ outboundTxParams: OutboundTxParams[]; + /** + * @generated from field: uint64 event_index = 11; + */ + eventIndex: bigint; + + /** + * @generated from field: common.CoinType coin_type = 12; + */ + coinType: CoinType; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/crosschain/cross_chain_tx_v14_pb.d.ts b/typescript/crosschain/cross_chain_tx_v14_pb.d.ts new file mode 100644 index 0000000000..7f47395c89 --- /dev/null +++ b/typescript/crosschain/cross_chain_tx_v14_pb.d.ts @@ -0,0 +1,243 @@ +// @generated by protoc-gen-es v1.3.0 with parameter "target=dts" +// @generated from file crosschain/cross_chain_tx_v14.proto (package zetachain.zetacore.crosschain, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; +import type { CoinType } from "../common/common_pb.js"; +import type { Status, TxFinalizationStatus } from "./cross_chain_tx_pb.js"; + +/** + * @generated from message zetachain.zetacore.crosschain.InboundTxParamsV14 + */ +export declare class InboundTxParamsV14 extends Message { + /** + * this address is the immediate contract/EOA that calls the Connector.send() + * + * @generated from field: string sender = 1; + */ + sender: string; + + /** + * @generated from field: int64 sender_chain_id = 2; + */ + senderChainId: bigint; + + /** + * this address is the EOA that signs the inbound tx + * + * @generated from field: string tx_origin = 3; + */ + txOrigin: string; + + /** + * @generated from field: common.CoinType coin_type = 4; + */ + coinType: CoinType; + + /** + * for ERC20 coin type, the asset is an address of the ERC20 contract + * + * @generated from field: string asset = 5; + */ + asset: string; + + /** + * @generated from field: string amount = 6; + */ + amount: string; + + /** + * @generated from field: string inbound_tx_observed_hash = 7; + */ + inboundTxObservedHash: string; + + /** + * @generated from field: uint64 inbound_tx_observed_external_height = 8; + */ + inboundTxObservedExternalHeight: bigint; + + /** + * @generated from field: string inbound_tx_ballot_index = 9; + */ + inboundTxBallotIndex: string; + + /** + * @generated from field: uint64 inbound_tx_finalized_zeta_height = 10; + */ + inboundTxFinalizedZetaHeight: bigint; + + /** + * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 11; + */ + txFinalizationStatus: TxFinalizationStatus; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.InboundTxParamsV14"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): InboundTxParamsV14; + + static fromJson(jsonValue: JsonValue, options?: Partial): InboundTxParamsV14; + + static fromJsonString(jsonString: string, options?: Partial): InboundTxParamsV14; + + static equals(a: InboundTxParamsV14 | PlainMessage | undefined, b: InboundTxParamsV14 | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.crosschain.OutboundTxParamsV14 + */ +export declare class OutboundTxParamsV14 extends Message { + /** + * @generated from field: string receiver = 1; + */ + receiver: string; + + /** + * @generated from field: int64 receiver_chainId = 2; + */ + receiverChainId: bigint; + + /** + * @generated from field: common.CoinType coin_type = 3; + */ + coinType: CoinType; + + /** + * @generated from field: string amount = 4; + */ + amount: string; + + /** + * @generated from field: uint64 outbound_tx_tss_nonce = 5; + */ + outboundTxTssNonce: bigint; + + /** + * @generated from field: uint64 outbound_tx_gas_limit = 6; + */ + outboundTxGasLimit: bigint; + + /** + * @generated from field: string outbound_tx_gas_price = 7; + */ + outboundTxGasPrice: string; + + /** + * the above are commands for zetaclients + * the following fields are used when the outbound tx is mined + * + * @generated from field: string outbound_tx_hash = 8; + */ + outboundTxHash: string; + + /** + * @generated from field: string outbound_tx_ballot_index = 9; + */ + outboundTxBallotIndex: string; + + /** + * @generated from field: uint64 outbound_tx_observed_external_height = 10; + */ + outboundTxObservedExternalHeight: bigint; + + /** + * @generated from field: uint64 outbound_tx_gas_used = 20; + */ + outboundTxGasUsed: bigint; + + /** + * @generated from field: string outbound_tx_effective_gas_price = 21; + */ + outboundTxEffectiveGasPrice: string; + + /** + * @generated from field: uint64 outbound_tx_effective_gas_limit = 22; + */ + outboundTxEffectiveGasLimit: bigint; + + /** + * @generated from field: string tss_pubkey = 11; + */ + tssPubkey: string; + + /** + * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 12; + */ + txFinalizationStatus: TxFinalizationStatus; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.OutboundTxParamsV14"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): OutboundTxParamsV14; + + static fromJson(jsonValue: JsonValue, options?: Partial): OutboundTxParamsV14; + + static fromJsonString(jsonString: string, options?: Partial): OutboundTxParamsV14; + + static equals(a: OutboundTxParamsV14 | PlainMessage | undefined, b: OutboundTxParamsV14 | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.crosschain.CrossChainTxV14 + */ +export declare class CrossChainTxV14 extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: string index = 2; + */ + index: string; + + /** + * @generated from field: string zeta_fees = 5; + */ + zetaFees: string; + + /** + * Not used by protocol , just relayed across + * + * @generated from field: string relayed_message = 6; + */ + relayedMessage: string; + + /** + * @generated from field: zetachain.zetacore.crosschain.Status cctx_status = 8; + */ + cctxStatus?: Status; + + /** + * @generated from field: zetachain.zetacore.crosschain.InboundTxParamsV14 inbound_tx_params = 9; + */ + inboundTxParams?: InboundTxParamsV14; + + /** + * @generated from field: repeated zetachain.zetacore.crosschain.OutboundTxParamsV14 outbound_tx_params = 10; + */ + outboundTxParams: OutboundTxParamsV14[]; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.CrossChainTxV14"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): CrossChainTxV14; + + static fromJson(jsonValue: JsonValue, options?: Partial): CrossChainTxV14; + + static fromJsonString(jsonString: string, options?: Partial): CrossChainTxV14; + + static equals(a: CrossChainTxV14 | PlainMessage | undefined, b: CrossChainTxV14 | PlainMessage | undefined): boolean; +} + diff --git a/typescript/crosschain/index.d.ts b/typescript/crosschain/index.d.ts index 4c073541bc..f5fb4873df 100644 --- a/typescript/crosschain/index.d.ts +++ b/typescript/crosschain/index.d.ts @@ -1,4 +1,5 @@ export * from "./cross_chain_tx_pb"; +export * from "./cross_chain_tx_v14_pb"; export * from "./events_pb"; export * from "./gas_price_pb"; export * from "./genesis_pb"; From ea1812eb42fa0128e317459ff02308b9086881fa Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 12 Mar 2024 19:10:41 -0400 Subject: [PATCH 18/36] modify logs --- x/crosschain/types/cctx_utils.go | 4 ++-- zetaclient/bitcoin/bitcoin_client.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index 2d0dff74bf..a95c19f786 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -176,14 +176,14 @@ func ValidateHashForChain(hash string, chainID int64) error { func ValidateAddressForChain(address string, chainID int64) error { if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { if !ethcommon.IsHexAddress(address) { - return fmt.Errorf("invalid address %s", address) + return fmt.Errorf("invalid address %s , chain %d", address, chainID) } return nil } if common.IsBitcoinChain(chainID) { addr, err := common.DecodeBtcAddress(address, chainID) if err != nil { - return fmt.Errorf("invalid address %s: %s", address, err) + return fmt.Errorf("invalid address %s , chain %d: %s", address, chainID, err) } _, ok := addr.(*btcutil.AddressWitnessPubKeyHash) if !ok { diff --git a/zetaclient/bitcoin/bitcoin_client.go b/zetaclient/bitcoin/bitcoin_client.go index bb47a6eaa4..b9c42049c7 100644 --- a/zetaclient/bitcoin/bitcoin_client.go +++ b/zetaclient/bitcoin/bitcoin_client.go @@ -691,7 +691,7 @@ func (ob *BTCChainClient) GetInboundVoteMessageFromBtcEvent(inTx *BTCInTxEvnet) inTx.FromAddress, ob.chain.ChainId, inTx.FromAddress, - inTx.FromAddress, + inTx.ToAddress, ob.zetaClient.ZetaChain().ChainId, cosmosmath.NewUintFromBigInt(amountInt), message, From 40807922499c702aa2b9b325b87b41b85a42bdde Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 12 Mar 2024 19:51:45 -0400 Subject: [PATCH 19/36] ignore address validation for zetachain --- x/crosschain/types/cctx_utils.go | 10 ++++++++-- x/crosschain/types/cctx_utils_test.go | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index a95c19f786..d24fd8d6a8 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -153,7 +153,10 @@ func ValidateZetaIndex(index string) error { return nil } func ValidateHashForChain(hash string, chainID int64) error { - if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { + if common.IsZetaChain(chainID) { + return nil + } + if common.IsEthereumChain(chainID) { _, err := hexutil.Decode(hash) if err != nil { return fmt.Errorf("hash must be a valid ethereum hash %s", hash) @@ -174,7 +177,10 @@ func ValidateHashForChain(hash string, chainID int64) error { } func ValidateAddressForChain(address string, chainID int64) error { - if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { + if common.IsZetaChain(chainID) { + return nil + } + if common.IsEthereumChain(chainID) { if !ethcommon.IsHexAddress(address) { return fmt.Errorf("invalid address %s , chain %d", address, chainID) } diff --git a/x/crosschain/types/cctx_utils_test.go b/x/crosschain/types/cctx_utils_test.go index f35e9da9db..e28581ac88 100644 --- a/x/crosschain/types/cctx_utils_test.go +++ b/x/crosschain/types/cctx_utils_test.go @@ -21,6 +21,8 @@ func TestValidateAddressForChain(t *testing.T) { require.Error(t, types.ValidateAddressForChain("", common.BtcRegtestChain().ChainId)) require.NoError(t, types.ValidateAddressForChain("bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu", common.BtcMainnetChain().ChainId)) require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcRegtestChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.ZetaChainMainnet().ChainId)) + require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.ZetaChainMainnet().ChainId)) } func TestValidateZetaIndex(t *testing.T) { From 5f4f37b51200d91b90a28550a54772978dc6bb21 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 12 Mar 2024 20:00:50 -0400 Subject: [PATCH 20/36] ignore address validation for zetachain --- x/crosschain/types/cctx_utils.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index d24fd8d6a8..d33070ecd1 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -177,6 +177,7 @@ func ValidateHashForChain(hash string, chainID int64) error { } func ValidateAddressForChain(address string, chainID int64) error { + // we do not validate the address for zeta chain as the address field can be btc or eth address if common.IsZetaChain(chainID) { return nil } From 117fe62bbd9c0225ae3dd27111dfec842c20f41e Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 12 Mar 2024 20:02:56 -0400 Subject: [PATCH 21/36] ignore tx hash check --- x/crosschain/types/cctx_utils.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index d33070ecd1..695cb152f3 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -153,10 +153,7 @@ func ValidateZetaIndex(index string) error { return nil } func ValidateHashForChain(hash string, chainID int64) error { - if common.IsZetaChain(chainID) { - return nil - } - if common.IsEthereumChain(chainID) { + if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { _, err := hexutil.Decode(hash) if err != nil { return fmt.Errorf("hash must be a valid ethereum hash %s", hash) From 152a3de0548812174ea88c3715b0daea53a75c1d Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 18 Mar 2024 14:06:09 -0400 Subject: [PATCH 22/36] refactor: outboud vote (#1886) --- testutil/keeper/crosschain.go | 29 ++ .../client/integrationtests/cli_helpers.go | 322 ------------ .../client/integrationtests/cli_test.go | 12 - .../integrationtests/inbound_voter_test.go | 304 ----------- .../integrationtests/outbound_voter_test.go | 248 --------- x/crosschain/client/integrationtests/suite.go | 65 --- x/crosschain/keeper/cctx_utils_outbound.go | 249 +++++++++ .../keeper/cctx_utils_outbound_test.go | 490 ++++++++++++++++++ x/crosschain/keeper/cctx_utils_test.go | 4 +- x/crosschain/keeper/events.go | 8 +- .../keeper/msg_server_vote_outbound_tx.go | 185 +------ .../msg_server_vote_outbound_tx_test.go | 333 +++++++++++- 12 files changed, 1122 insertions(+), 1127 deletions(-) delete mode 100644 x/crosschain/client/integrationtests/cli_helpers.go delete mode 100644 x/crosschain/client/integrationtests/cli_test.go delete mode 100644 x/crosschain/client/integrationtests/inbound_voter_test.go delete mode 100644 x/crosschain/client/integrationtests/outbound_voter_test.go delete mode 100644 x/crosschain/client/integrationtests/suite.go create mode 100644 x/crosschain/keeper/cctx_utils_outbound.go create mode 100644 x/crosschain/keeper/cctx_utils_outbound_test.go diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index e586cb1e70..78538827da 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -269,3 +269,32 @@ func MockRevertForHandleEVMDeposit(m *crosschainmocks.CrosschainFungibleKeeper, mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) } + +func MockVoteOnOutboundSuccessBallot(m *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, cctx *types.CrossChainTx, senderChain common.Chain, observer string) { + m.On("VoteOnOutboundBallot", ctx, mock.Anything, cctx.GetCurrentOutTxParam().ReceiverChainId, common.ReceiveStatus_Success, observer). + Return(true, true, observertypes.Ballot{BallotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation}, senderChain.ChainName.String(), nil).Once() +} + +func MockVoteOnOutboundFailedBallot(m *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, cctx *types.CrossChainTx, senderChain common.Chain, observer string) { + m.On("VoteOnOutboundBallot", ctx, mock.Anything, cctx.GetCurrentOutTxParam().ReceiverChainId, common.ReceiveStatus_Failed, observer). + Return(true, true, observertypes.Ballot{BallotStatus: observertypes.BallotStatus_BallotFinalized_FailureObservation}, senderChain.ChainName.String(), nil).Once() +} + +func MockGetOutBound(m *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context) { + m.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() +} + +func MockSaveOutBound(m *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, cctx *types.CrossChainTx, tss observertypes.TSS) { + m.On("RemoveFromPendingNonces", + ctx, tss.TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId, mock.Anything). + Return().Once() + m.On("GetTSS", ctx).Return(observertypes.TSS{}, true) +} + +func MockSaveOutBoundNewRevertCreated(m *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, cctx *types.CrossChainTx, tss observertypes.TSS) { + m.On("RemoveFromPendingNonces", + ctx, tss.TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId, mock.Anything). + Return().Once() + m.On("GetTSS", ctx).Return(observertypes.TSS{}, true) + m.On("SetNonceToCctx", mock.Anything, mock.Anything).Return().Once() +} diff --git a/x/crosschain/client/integrationtests/cli_helpers.go b/x/crosschain/client/integrationtests/cli_helpers.go deleted file mode 100644 index 3195782031..0000000000 --- a/x/crosschain/client/integrationtests/cli_helpers.go +++ /dev/null @@ -1,322 +0,0 @@ -package integrationtests - -import ( - "fmt" - "os" - "strconv" - "testing" - - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - "github.com/cosmos/cosmos-sdk/testutil" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - sdk "github.com/cosmos/cosmos-sdk/types" - authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/stretchr/testify/require" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/testutil/network" - "github.com/zeta-chain/zetacore/x/crosschain/client/cli" - "github.com/zeta-chain/zetacore/x/crosschain/types" - fungiblecli "github.com/zeta-chain/zetacore/x/fungible/client/cli" -) - -func TxSignExec(clientCtx client.Context, from fmt.Stringer, filename string, extraArgs ...string) (testutil.BufferWriter, error) { - args := []string{ - fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), - fmt.Sprintf("--from=%s", from.String()), - fmt.Sprintf("--%s=%s", flags.FlagChainID, clientCtx.ChainID), - filename, - } - - cmd := authcli.GetSignCommand() - tmcli.PrepareBaseCmd(cmd, "", "") - - return clitestutil.ExecTestCLICmd(clientCtx, cmd, append(args, extraArgs...)) -} - -func WriteToNewTempFile(t testing.TB, s string) *os.File { - t.Helper() - - fp := TempFile(t) - _, err := fp.WriteString(s) - - require.Nil(t, err) - - return fp -} - -// TempFile returns a writable temporary file for the test to use. -func TempFile(t testing.TB) *os.File { - t.Helper() - - fp, err := os.CreateTemp(GetTempDir(t), "") - require.NoError(t, err) - - return fp -} - -// GetTempDir returns a writable temporary director for the test to use. -func GetTempDir(t testing.TB) string { - t.Helper() - // os.MkDir() is used instead of testing.T.TempDir() - // see https://github.com/cosmos/cosmos-sdk/pull/8475 and - // https://github.com/cosmos/cosmos-sdk/pull/10341 for - // this change's rationale. - tempdir, err := os.MkdirTemp("", "") - require.NoError(t, err) - t.Cleanup(func() { - err := os.RemoveAll(tempdir) - require.NoError(t, err) - }) - return tempdir -} - -func BuildSignedDeploySystemContract(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI) *os.File { - cmd := fungiblecli.CmdDeploySystemContracts() - txArgs := []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(100))).String()), - // gas limit - fmt.Sprintf("--%s=%d", flags.FlagGas, 4000000), - } - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, txArgs) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedUpdateSystemContract( - t testing.TB, - val *network.Validator, - denom string, - account authtypes.AccountI, - systemContractAddress string, -) *os.File { - cmd := fungiblecli.CmdUpdateSystemContract() - txArgs := []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(100))).String()), - // gas limit - fmt.Sprintf("--%s=%d", flags.FlagGas, 4000000), - } - args := append([]string{systemContractAddress}, txArgs...) - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedDeployETHZRC20( - t testing.TB, - val *network.Validator, - denom string, - account authtypes.AccountI, -) *os.File { - cmd := fungiblecli.CmdDeployFungibleCoinZRC4() - txArgs := []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(100))).String()), - // gas limit - fmt.Sprintf("--%s=%d", flags.FlagGas, 10000000), - } - args := append([]string{ - "", - strconv.FormatInt(common.GoerliLocalnetChain().ChainId, 10), - "18", - "ETH", - "gETH", - strconv.FormatInt(int64(common.CoinType_Gas), 10), - "1000000", - }, txArgs...) - out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedGasPriceVote(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI) *os.File { - cmd := cli.CmdGasPriceVoter() - inboundVoterArgs := []string{ - strconv.FormatInt(common.GoerliLocalnetChain().ChainId, 10), - "10000000000", - "100", - "100", - } - txArgs := []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.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) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedTssVote(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI) *os.File { - cmd := cli.CmdCreateTSSVoter() - inboundVoterArgs := []string{ - "tsspubkey", - "1", - "0", - } - txArgs := []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.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) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedOutboundVote( - t testing.TB, - val *network.Validator, - denom string, - account authtypes.AccountI, - nonce uint64, - cctxIndex, - outTxHash, - valueReceived, - status string, -) *os.File { - cmd := cli.CmdCCTXOutboundVoter() - outboundVoterArgs := []string{ - cctxIndex, - outTxHash, - "1", - "0", - "0", - "0", - valueReceived, - status, - strconv.FormatInt(common.GoerliLocalnetChain().ChainId, 10), - strconv.FormatUint(nonce, 10), - "Zeta", - } - txArgs := []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.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) - require.NoError(t, err) - - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI, message string, eventIndex int) *os.File { - cmd := cli.CmdCCTXInboundVoter() - inboundVoterArgs := []string{ - "0x96B05C238b99768F349135de0653b687f9c13fEE", - strconv.FormatInt(common.GoerliLocalnetChain().ChainId, 10), - "0x3b9Fe88DE29efD13240829A0c18E9EC7A44C3CA7", - "0x96B05C238b99768F349135de0653b687f9c13fEE", - strconv.FormatInt(common.GoerliLocalnetChain().ChainId, 10), - "10000000000000000000", - message, - "0x19398991572a825894b34b904ac1e3692720895351466b5c9e6bb7ae1e21d680", - "100", - "Zeta", - "", - strconv.Itoa(eventIndex), - } - txArgs := []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.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) - require.NoError(t, err) - unsignerdTx := WriteToNewTempFile(t, out.String()) - res, err := TxSignExec(val.ClientCtx, val.Address, unsignerdTx.Name(), - "--offline", "--account-number", strconv.FormatUint(account.GetAccountNumber(), 10), "--sequence", strconv.FormatUint(account.GetSequence(), 10)) - require.NoError(t, err) - return WriteToNewTempFile(t, res.String()) -} - -func GetBallotIdentifier(message string, eventIndex int) string { - msg := types.NewMsgVoteOnObservedInboundTx( - "", - "0x96B05C238b99768F349135de0653b687f9c13fEE", - common.GoerliLocalnetChain().ChainId, - "0x3b9Fe88DE29efD13240829A0c18E9EC7A44C3CA7", - "0x96B05C238b99768F349135de0653b687f9c13fEE", - common.GoerliLocalnetChain().ChainId, - sdk.NewUint(10000000000000000000), - message, - "0x19398991572a825894b34b904ac1e3692720895351466b5c9e6bb7ae1e21d680", - 100, - 250_000, - common.CoinType_Zeta, - "", - // #nosec G701 always positive - uint(eventIndex), - ) - return msg.Digest() -} - -func GetBallotIdentifierOutBound(nonce uint64, cctxindex, outtxHash, valueReceived string) string { - msg := types.NewMsgVoteOnObservedOutboundTx( - "", - cctxindex, - outtxHash, - 1, - 0, - math.ZeroInt(), - 0, - math.NewUintFromString(valueReceived), - 0, - common.GoerliLocalnetChain().ChainId, - nonce, - common.CoinType_Zeta, - ) - return msg.Digest() -} diff --git a/x/crosschain/client/integrationtests/cli_test.go b/x/crosschain/client/integrationtests/cli_test.go deleted file mode 100644 index 46db24fbae..0000000000 --- a/x/crosschain/client/integrationtests/cli_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package integrationtests - -import ( - "testing" - - "github.com/zeta-chain/zetacore/testutil/network" -) - -func TestIntegrationTestSuite(t *testing.T) { - _ = network.DefaultConfig() - //suite.Run(t, NewIntegrationTestSuite(cfg)) -} diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go deleted file mode 100644 index 50cf041a64..0000000000 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ /dev/null @@ -1,304 +0,0 @@ -package integrationtests - -import ( - "encoding/json" - "fmt" - "strings" - - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - crosschaincli "github.com/zeta-chain/zetacore/x/crosschain/client/cli" - crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" - observercli "github.com/zeta-chain/zetacore/x/observer/client/cli" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -type messageLog struct { - Events []event `json:"events"` -} - -type event struct { - Type string `json:"type"` - Attributes []attribute `json:"attributes"` -} - -type attribute struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// fetchAttribute fetches the attribute from the tx response -func fetchAttribute(rawLog string, key string) (string, error) { - var logs []messageLog - err := json.Unmarshal([]byte(rawLog), &logs) - if err != nil { - return "", err - } - - var attributes []string - for _, log := range logs { - for _, event := range log.Events { - for _, attr := range event.Attributes { - attributes = append(attributes, attr.Key) - if strings.EqualFold(attr.Key, key) { - address := attr.Value - - // trim the quotes - address = address[1 : len(address)-1] - - return address, nil - } - - } - } - } - - return "", fmt.Errorf("attribute %s not found, attributes: %+v", key, attributes) -} - -type txRes struct { - RawLog string `json:"raw_log"` -} - -func ExtractRawLog(str string) (string, error) { - var data txRes - - err := json.Unmarshal([]byte(str), &data) - if err != nil { - return "", err - } - - return data.RawLog, nil -} - -func (s *IntegrationTestSuite) TestCCTXInboundVoter() { - broadcaster := s.network.Validators[0] - - var systemContractAddr string - // Initialize system contract - { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{broadcaster.Address.String(), "--output", "json"}) - s.Require().NoError(err) - var account authtypes.AccountI - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx := BuildSignedDeploySystemContract(s.T(), broadcaster, s.cfg.BondDenom, account) - res, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "block"}) - s.Require().NoError(err) - - rawLog, err := ExtractRawLog(res.String()) - s.Require().NoError(err) - - systemContractAddr, err = fetchAttribute(rawLog, "system_contract") - s.Require().NoError(err) - - // update system contract - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{broadcaster.Address.String(), "--output", "json"}) - s.Require().NoError(err) - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx = BuildSignedUpdateSystemContract(s.T(), broadcaster, s.cfg.BondDenom, account, systemContractAddr) - res, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "block"}) - s.Require().NoError(err) - } - - // Deploy ETH ZRC20 - { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{broadcaster.Address.String(), "--output", "json"}) - s.Require().NoError(err) - var account authtypes.AccountI - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx := BuildSignedDeployETHZRC20(s.T(), broadcaster, s.cfg.BondDenom, account) - _, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "block"}) - s.Require().NoError(err) - } - - tt := []struct { - name string - votes map[string]observerTypes.VoteType - ballotResult observerTypes.BallotStatus - cctxStatus crosschaintypes.CctxStatus - falseBallotIdentifier string - }{ - { - name: "All observers voted success", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_SuccessObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - }, - { - name: "5 votes only ballot does not get finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_NotYetVoted, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - }, - { - name: "1 false vote but correct ballot is still finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - }, - ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - }, - { - name: "2 ballots with 5 votes each no ballot gets finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - }, - { - name: "majority wrong votes incorrect ballot finalized / correct ballot still in progress", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_FailureObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_FailureObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", - }, - { - name: "7 votes only just crossed threshold", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - }, - } - for i, test := range tt { - test := test - s.Run(test.name, func() { - // Vote the gas price - for _, val := range s.network.Validators { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - s.Require().NoError(err) - - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx := BuildSignedGasPriceVote(s.T(), val, s.cfg.BondDenom, account) - _, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) - s.Require().NoError(err) - } - - s.Require().NoError(s.network.WaitForNBlocks(2)) - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdListPendingNonces(), []string{"--output", "json"}) - s.Require().NoError(err) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdGetSupportedChains(), []string{"--output", "json"}) - s.Require().NoError(err) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdListGasPrice(), []string{"--output", "json"}) - s.Require().NoError(err) - - // Vote the inbound tx - for _, val := range s.network.Validators { - vote := test.votes[val.Address.String()] - if vote == observerTypes.VoteType_NotYetVoted { - continue - } - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - - message := test.name - if vote == observerTypes.VoteType_FailureObservation { - message = message + "falseVote" - } - signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, i) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "block"}) - s.Require().NoError(err) - fmt.Println(out.String()) - } - s.Require().NoError(s.network.WaitForNBlocks(2)) - - // Get the ballot - ballotIdentifier := GetBallotIdentifier(test.name, i) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdBallotByIdentifier(), []string{ballotIdentifier, "--output", "json"}) - s.Require().NoError(err) - ballot := observerTypes.QueryBallotByIdentifierResponse{} - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ballot)) - - // Check the vote in the ballot - s.Require().Equal(len(test.votes), len(ballot.Voters)) - for _, vote := range ballot.Voters { - if test.votes[vote.VoterAddress] == observerTypes.VoteType_FailureObservation { - s.Assert().Equal(observerTypes.VoteType_NotYetVoted.String(), vote.VoteType.String()) - continue - } - s.Assert().Equal(test.votes[vote.VoterAddress].String(), vote.VoteType.String(), "incorrect vote for voter: %s", vote.VoterAddress) - } - s.Require().Equal(test.ballotResult.String(), ballot.BallotStatus.String()) - - // Get the cctx and check its status - cctxIdentifier := ballotIdentifier - if test.falseBallotIdentifier != "" { - cctxIdentifier = GetBallotIdentifier(test.falseBallotIdentifier, i) - } - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdShowSend(), []string{cctxIdentifier, "--output", "json"}) - cctx := crosschaintypes.QueryGetCctxResponse{} - if test.cctxStatus == crosschaintypes.CctxStatus_PendingRevert { - s.Require().Contains(out.String(), "not found") - } else { - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &cctx)) - s.Require().Equal(test.cctxStatus.String(), cctx.CrossChainTx.CctxStatus.Status.String(), cctx.CrossChainTx.CctxStatus.StatusMessage) - } - }) - } - -} diff --git a/x/crosschain/client/integrationtests/outbound_voter_test.go b/x/crosschain/client/integrationtests/outbound_voter_test.go deleted file mode 100644 index d388adc003..0000000000 --- a/x/crosschain/client/integrationtests/outbound_voter_test.go +++ /dev/null @@ -1,248 +0,0 @@ -package integrationtests - -import ( - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - authcli "github.com/cosmos/cosmos-sdk/x/auth/client/cli" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - crosschaincli "github.com/zeta-chain/zetacore/x/crosschain/client/cli" - crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" - observercli "github.com/zeta-chain/zetacore/x/observer/client/cli" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -func (s *IntegrationTestSuite) TestCCTXOutBoundVoter() { - type Vote struct { - voterAddress string - voteType observerTypes.VoteType - isFakeVote bool - } - tt := []struct { - name string - votes []Vote - valueReceived string // TODO : calculate this value - correctBallotResult observerTypes.BallotStatus - cctxStatus crosschaintypes.CctxStatus - falseBallotIdentifier string - }{ - { - name: "All observers voted success or not voted", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_NotYetVoted, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7991636132140714751", - }, - { - name: "1 fake vote but ballot still success", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7990439496224753106", - }, - { - name: "Half success and half false", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - valueReceived: "7990439496224753106", - }, - { - name: "Fake ballot has more votes outbound gets finalized", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7987124742653889020", - }, - { - name: "5 success 5 Failed votes ", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - valueReceived: "7991636132140714751", - }, - } - for i, test := range tt { - // Buffer event index so that it does not clash with the inbound voter test - eventIndex := i + 100 - test := test - s.Run(test.name, func() { - broadcaster := s.network.Validators[0] - - // Vote the gas price - for _, val := range s.network.Validators { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx := BuildSignedGasPriceVote(s.T(), val, s.cfg.BondDenom, account) - _, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) - s.Require().NoError(err) - } - s.Require().NoError(s.network.WaitForNBlocks(2)) - - // Vote the tss - for _, val := range s.network.Validators { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - signedTx := BuildSignedTssVote(s.T(), val, s.cfg.BondDenom, account) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) - s.Require().NoError(err) - } - s.Require().NoError(s.network.WaitForNBlocks(2)) - - // Vote the inbound tx - for _, val := range s.network.Validators { - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - message := test.name - signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, eventIndex) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) - s.Require().NoError(err) - } - s.Require().NoError(s.network.WaitForNBlocks(2)) - - // Get the ballot - cctxIdentifier := GetBallotIdentifier(test.name, eventIndex) - out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdShowSend(), []string{cctxIdentifier, "--output", "json"}) - cctx := crosschaintypes.QueryGetCctxResponse{} - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &cctx)) - s.Assert().Equal(crosschaintypes.CctxStatus_PendingOutbound.String(), cctx.CrossChainTx.CctxStatus.Status.String(), cctx.CrossChainTx.CctxStatus.StatusMessage) - nonce := cctx.CrossChainTx.GetCurrentOutTxParam().OutboundTxTssNonce - // Check the vote in the ballot and vote the outbound tx - fakeVotes := []string{} - for _, val := range s.network.Validators { - valVote := Vote{} - for _, vote := range test.votes { - if vote.voterAddress == val.Address.String() { - valVote = vote - } - } - if valVote.voteType == observerTypes.VoteType_NotYetVoted { - continue - } - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetAccountCmd(), []string{val.Address.String(), "--output", "json"}) - var account authtypes.AccountI - s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) - - outTxhash := test.name - if valVote.isFakeVote { - outTxhash = outTxhash + "falseVote" - fakeVotes = append(fakeVotes, val.Address.String()) - } - votestring := "" - switch valVote.voteType { - case observerTypes.VoteType_SuccessObservation: - votestring = "0" - case observerTypes.VoteType_FailureObservation: - votestring = "1" - } - - // Vote the outbound tx - signedTx := BuildSignedOutboundVote(s.T(), val, s.cfg.BondDenom, account, nonce, cctxIdentifier, outTxhash, test.valueReceived, votestring) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync", "--output", "json"}) - s.Require().NoError(err) - } - s.Require().NoError(s.network.WaitForNBlocks(2)) - - // Get the cctx - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdShowSend(), []string{cctxIdentifier, "--output", "json"}) - cctx = crosschaintypes.QueryGetCctxResponse{} - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &cctx)) - s.Assert().Equal(test.cctxStatus.String(), cctx.CrossChainTx.CctxStatus.Status.String(), cctx.CrossChainTx.CctxStatus.StatusMessage) - - outboundBallotIdentifier := GetBallotIdentifierOutBound(nonce, cctxIdentifier, test.name, test.valueReceived) - - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdBallotByIdentifier(), []string{outboundBallotIdentifier, "--output", "json"}) - s.Require().NoError(err) - ballot := observerTypes.QueryBallotByIdentifierResponse{} - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ballot)) - - // Check the votes - s.Require().Equal(test.correctBallotResult.String(), ballot.BallotStatus.String()) - for _, vote := range test.votes { - for _, ballotvote := range ballot.Voters { - if vote.voterAddress == ballotvote.VoterAddress { - if !vote.isFakeVote { - s.Assert().Equal(vote.voteType.String(), ballotvote.VoteType.String()) - } else { - s.Assert().Equal(observerTypes.VoteType_NotYetVoted.String(), ballotvote.VoteType.String()) - } - break - } - } - } - if len(fakeVotes) > 0 { - outboundFakeBallotIdentifier := GetBallotIdentifierOutBound(nonce, cctxIdentifier, test.name+"falseVote", test.valueReceived) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdBallotByIdentifier(), []string{outboundFakeBallotIdentifier, "--output", "json"}) - s.Require().NoError(err) - fakeBallot := observerTypes.QueryBallotByIdentifierResponse{} - s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &fakeBallot)) - for _, vote := range test.votes { - if vote.isFakeVote { - for _, ballotVote := range fakeBallot.Voters { - if vote.voterAddress == ballotVote.VoterAddress { - s.Assert().Equal(vote.voteType.String(), ballotVote.VoteType.String()) - break - } - } - } - } - } - }) - } -} diff --git a/x/crosschain/client/integrationtests/suite.go b/x/crosschain/client/integrationtests/suite.go deleted file mode 100644 index b5f16a683d..0000000000 --- a/x/crosschain/client/integrationtests/suite.go +++ /dev/null @@ -1,65 +0,0 @@ -package integrationtests - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - ethcfg "github.com/evmos/ethermint/cmd/config" - "github.com/stretchr/testify/suite" - "github.com/zeta-chain/zetacore/app" - cmdcfg "github.com/zeta-chain/zetacore/cmd/zetacored/config" - "github.com/zeta-chain/zetacore/testutil/network" -) - -type IntegrationTestSuite struct { - suite.Suite - - cfg network.Config - network *network.Network -} - -func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { - return &IntegrationTestSuite{cfg: cfg} -} - -func (s *IntegrationTestSuite) Setconfig() { - config := sdk.GetConfig() - cmdcfg.SetBech32Prefixes(config) - ethcfg.SetBip44CoinType(config) - // Make sure address is compatible with ethereum - config.SetAddressVerifier(app.VerifyAddressFormat) - config.Seal() -} -func (s *IntegrationTestSuite) SetupSuite() { - s.T().Log("setting up integration test suite") - s.Setconfig() - minOBsDel, ok := sdk.NewIntFromString("100000000000000000000") - s.Require().True(ok) - s.cfg.StakingTokens = minOBsDel.Mul(sdk.NewInt(int64(10))) - s.cfg.BondedTokens = minOBsDel - observerList := []string{"zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", - } - network.SetupZetaGenesisState(s.T(), s.cfg.GenesisState, s.cfg.Codec, observerList, true) - network.AddCrosschainData(s.T(), 0, s.cfg.GenesisState, s.cfg.Codec) - network.AddObserverData(s.T(), 0, s.cfg.GenesisState, s.cfg.Codec, nil) - net, err := network.New(s.T(), app.NodeDir, s.cfg) - s.Require().NoError(err) - s.network = net - time.Sleep(3 * time.Second) - _, err = s.network.WaitForHeight(1) - s.Require().NoError(err) -} - -func (s *IntegrationTestSuite) TearDownSuite() { - s.T().Log("tearing down integration test suite") - s.network.Cleanup() -} diff --git a/x/crosschain/keeper/cctx_utils_outbound.go b/x/crosschain/keeper/cctx_utils_outbound.go new file mode 100644 index 0000000000..7ba5e291ee --- /dev/null +++ b/x/crosschain/keeper/cctx_utils_outbound.go @@ -0,0 +1,249 @@ +package keeper + +import ( + "fmt" + "math/big" + + cosmoserrors "cosmossdk.io/errors" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// SetRevertOutboundValues does the following things in one function: +// 1. create a new OutboundTxParams for the revert +// 2. append the new OutboundTxParams to the current OutboundTxParams +// 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. +func SetRevertOutboundValues(cctx *types.CrossChainTx, gasLimit uint64) { + revertTxParams := &types.OutboundTxParams{ + Receiver: cctx.InboundTxParams.Sender, + ReceiverChainId: cctx.InboundTxParams.SenderChainId, + Amount: cctx.InboundTxParams.Amount, + OutboundTxGasLimit: gasLimit, + TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, + } + // The original outbound has been finalized, the new outbound is pending + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) +} + +// SetOutboundValues sets the required values for the outbound transaction +// Note: It expects the cctx to already have been created, +// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer +func SetOutboundValues(ctx sdk.Context, cctx *types.CrossChainTx, msg types.MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { + if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { + if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { + ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", + msg.ValueReceived, + cctx.GetCurrentOutTxParam().Amount)) + return cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, cctx.GetCurrentOutTxParam().Amount)) + } + } + // Update CCTX values + cctx.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash + cctx.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit + cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight + cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() + + return nil +} + +// FundStabilityPool funds the stability pool with the remaining fees of an outbound tx +// The funds are sent to the gas stability pool associated with the receiver chain +func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) { + // Fund the gas stability pool with the remaining funds + if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutTxParam(), cctx.GetCurrentOutTxParam().ReceiverChainId); err != nil { + ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: CCTX: %s Can't fund the gas stability pool with remaining fees %s", cctx.Index, err.Error())) + } +} + +// FundGasStabilityPoolFromRemainingFees funds the gas stability pool with the remaining fees of an outbound tx +func (k Keeper) FundGasStabilityPoolFromRemainingFees(ctx sdk.Context, outboundTxParams types.OutboundTxParams, chainID int64) error { + gasUsed := outboundTxParams.OutboundTxGasUsed + gasLimit := outboundTxParams.OutboundTxEffectiveGasLimit + gasPrice := math.NewUintFromBigInt(outboundTxParams.OutboundTxEffectiveGasPrice.BigInt()) + + if gasLimit == gasUsed { + return nil + } + + // We skip gas stability pool funding if one of the params is zero + if gasLimit > 0 && gasUsed > 0 && !gasPrice.IsZero() { + if gasLimit > gasUsed { + remainingGas := gasLimit - gasUsed + remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt() + + // We fund the stability pool with a portion of the remaining fees + remainingFees = percentOf(remainingFees, RemainingFeesToStabilityPoolPercent) + // Fund the gas stability pool + if err := k.fungibleKeeper.FundGasStabilityPool(ctx, chainID, remainingFees); err != nil { + return err + } + } else { + return fmt.Errorf("VoteOnObservedOutboundTx: The gas limit %d is less than the gas used %d", gasLimit, gasUsed) + } + } + return nil +} + +// percentOf returns the percentage of a number +func percentOf(n *big.Int, percent int64) *big.Int { + n = n.Mul(n, big.NewInt(percent)) + n = n.Div(n, big.NewInt(100)) + return n +} + +// ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: +// 1. Change the status of the CCTX from PendingRevert to Reverted or from PendingOutbound to OutboundMined +// 2. Set the finalization status of the current outbound tx to executed +// 3. Emit an event for the successful outbound transaction +func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { + oldStatus := cctx.CctxStatus.Status + switch oldStatus { + case types.CctxStatus_PendingRevert: + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") + case types.CctxStatus_PendingOutbound: + cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "") + default: + return + } + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) +} + +// ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: +// 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX +// 2. For other CCTX, it creates a revert tx if the outbound tx is pending. If the status is pending revert, it aborts the CCTX +// 3. Emit an event for the failed outbound transaction +// 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction +func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { + oldStatus := cctx.CctxStatus.Status + if cctx.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { + // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") + } else { + switch oldStatus { + case types.CctxStatus_PendingOutbound: + + gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + if err != nil { + return cosmoserrors.Wrap(err, "GetRevertGasLimit") + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit + } + + // create new OutboundTxParams for the revert + SetRevertOutboundValues(cctx, gasLimit) + + err = k.PayGasAndUpdateCctx( + ctx, + cctx.InboundTxParams.SenderChainId, + cctx, + cctx.OutboundTxParams[0].Amount, + false, + ) + if err != nil { + return err + } + err = k.UpdateNonce(ctx, cctx.InboundTxParams.SenderChainId, cctx) + if err != nil { + return err + } + // Not setting the finalization status here, the required changes have been mad while creating the revert tx + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") + case types.CctxStatus_PendingRevert: + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") + } + } + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) + return nil +} + +// ProcessOutbound processes the finalization of an outbound transaction based on the ballot status +// The state is committed only if the individual steps are successful +func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotStatus observertypes.BallotStatus, valueReceived string) error { + tmpCtx, commit := ctx.CacheContext() + err := func() error { + switch ballotStatus { + case observertypes.BallotStatus_BallotFinalized_SuccessObservation: + k.ProcessSuccessfulOutbound(tmpCtx, cctx, valueReceived) + case observertypes.BallotStatus_BallotFinalized_FailureObservation: + err := k.ProcessFailedOutbound(tmpCtx, cctx, valueReceived) + if err != nil { + return err + } + } + return nil + }() + if err != nil { + return err + } + commit() + return nil +} + +// SaveFailedOutBound saves a failed outbound transaction. +// It does the following things in one function: +// 1. Change the status of the CCTX to Aborted +// 2. Save the outbound +func (k Keeper) SaveFailedOutBound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) + ctx.Logger().Error(errMessage) + + k.SaveOutbound(ctx, cctx, ballotIndex) +} + +// SaveSuccessfulOutBound saves a successful outbound transaction. +func (k Keeper) SaveSuccessfulOutBound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { + k.SaveOutbound(ctx, cctx, ballotIndex) +} + +// SaveOutbound saves the outbound transaction.It does the following things in one function: +// 1. Set the ballot index for the outbound vote to the cctx +// 2. Remove the nonce from the pending nonces +// 3. Remove the outbound tx tracker +// 4. Set the cctx and nonce to cctx and inTxHash to cctx +func (k Keeper) SaveOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { + receiverChain := cctx.GetCurrentOutTxParam().ReceiverChainId + tssPubkey := cctx.GetCurrentOutTxParam().TssPubkey + outTxTssNonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce + + cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex + // #nosec G701 always in range + k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tssPubkey, receiverChain, int64(outTxTssNonce)) + k.RemoveOutTxTracker(ctx, receiverChain, outTxTssNonce) + ctx.Logger().Info(fmt.Sprintf("Remove tracker %s: , Block Height : %d ", getOutTrackerIndex(receiverChain, outTxTssNonce), ctx.BlockHeight())) + // This should set nonce to cctx only if a new revert is created. + k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) +} + +func (k Keeper) ValidateOutboundMessage(ctx sdk.Context, msg types.MsgVoteOnObservedOutboundTx) (types.CrossChainTx, error) { + // check if CCTX exists and if the nonce matches + cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash) + if !found { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) + } + if cctx.GetCurrentOutTxParam().OutboundTxTssNonce != msg.OutTxTssNonce { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + } + // do not process an outbound vote if TSS is not found + _, found = k.zetaObserverKeeper.GetTSS(ctx) + if !found { + return types.CrossChainTx{}, types.ErrCannotFindTSSKeys + } + if cctx.GetCurrentOutTxParam().ReceiverChainId != msg.OutTxChain { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", msg.OutTxChain, cctx.GetCurrentOutTxParam().ReceiverChainId)) + } + return cctx, nil +} diff --git a/x/crosschain/keeper/cctx_utils_outbound_test.go b/x/crosschain/keeper/cctx_utils_outbound_test.go new file mode 100644 index 0000000000..78636c18c9 --- /dev/null +++ b/x/crosschain/keeper/cctx_utils_outbound_test.go @@ -0,0 +1,490 @@ +package keeper_test + +import ( + "fmt" + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_GetOutbound(t *testing.T) { + t.Run("successfully get outbound tx", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("successfully get outbound tx for failed ballot without amount check", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_FailureObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("failed to get outbound tx if amount does not match value received", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: sdkmath.NewUint(100), + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + }) +} + +func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + // transition to reverted if pending revert + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Reverted) + // transition to outbound mined if pending outbound + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + // do nothing if it's in any other state + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) +} + +func TestKeeper_ProcessFailedOutbound(t *testing.T) { + t.Run("successfully process failed outbound set to aborted for type cmd", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CoinType = common.CoinType_Cmd + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to aborted for withdraw tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.SenderChainId = common.ZetaChainMainnet().ChainId + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to pending revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + // Remove the first outbound tx param to make the scenario realistic + oldParams := cctx.OutboundTxParams + cctx.OutboundTxParams = make([]*types.OutboundTxParams, 1) + cctx.OutboundTxParams[0] = oldParams[1] + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) + + }) + + t.Run("unable to process revert when update nonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock failed UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrCannotFindReceiverNonce) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, observertypes.ErrSupportedChains) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when GetRevertGasLimit fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) +} + +func TestKeeper_ProcessOutbound(t *testing.T) { + t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + }) + + t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.CoinType = common.CoinType_Cmd + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("do not process outbound on error, no new outbound created", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + // New outbound not added and the old outbound is not finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + }) + + t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + // New outbound added for revert and the old outbound is finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen+1) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + require.Equal(t, cctx.OutboundTxParams[oldOutTxParamsLen-1].TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) +} + +func TestKeeper_SaveFailedOutBound(t *testing.T) { + t.Run("successfully save failed outbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SaveFailedOutBound(ctx, cctx, sample.String(), sample.ZetaIndex(t)) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + }) +} + +func TestKeeper_SaveSuccessfulOutBound(t *testing.T) { + t.Run("successfully save successful outbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SaveSuccessfulOutBound(ctx, cctx, sample.String()) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, sample.String()) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + }) +} + +func TestKeeper_SaveOutbound(t *testing.T) { + t.Run("successfully save outbound", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // setup state for crosschain and observer modules + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + ballotIndex := sample.String() + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + + zk.ObserverKeeper.SetPendingNonces(ctx, observertypes.PendingNonces{ + NonceLow: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - 1, + NonceHigh: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + 1, + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Tss: cctx.GetCurrentOutTxParam().TssPubkey, + }) + zk.ObserverKeeper.SetTSS(ctx, observertypes.TSS{ + TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, + }) + + // Save outbound and assert all values are successfully saved + k.SaveOutbound(ctx, cctx, ballotIndex) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, ballotIndex) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + pn, found := zk.ObserverKeeper.GetPendingNonces(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.True(t, found) + require.Equal(t, pn.NonceLow, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) + require.Equal(t, pn.NonceHigh, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) + _, found = k.GetInTxHashToCctx(ctx, cctx.InboundTxParams.InboundTxObservedHash) + require.True(t, found) + _, found = zk.ObserverKeeper.GetNonceToCctx(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + require.True(t, found) + }) +} + +func Test_SetRevertOutboundValues(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.OutboundTxParams = cctx.OutboundTxParams[:1] + keeper.SetRevertOutboundValues(cctx, 100) + require.Len(t, cctx.OutboundTxParams, 2) + require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) + require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) +} + +func TestKeeper_ValidateOutboundMessage(t *testing.T) { + t.Run("successfully validate outbound message", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + }) + require.NoError(t, err) + }) + + t.Run("failed to validate outbound message if cctx not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + msg := types.MsgVoteOnObservedOutboundTx{ + CctxHash: sample.String(), + OutTxTssNonce: 1, + } + _, err := k.ValidateOutboundMessage(ctx, msg) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) + }) + + t.Run("failed to validate outbound message if nonce does not match", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + msg := types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: 2, + } + _, err := k.ValidateOutboundMessage(ctx, msg) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + }) + + t.Run("failed to validate outbound message if tss not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + }) + require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) + }) + + t.Run("failed to validate outbound message if chain does not match", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: 2, + }) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", 2, cctx.GetCurrentOutTxParam().ReceiverChainId)) + }) +} diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index b23709e058..f0255214a8 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -614,12 +614,14 @@ func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.C cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId cctx.GetCurrentOutTxParam().ReceiverChainId = senderChain.ChainId cctx.CoinType = common.CoinType_ERC20 cctx.RelayedMessage = "" cctx.GetInboundTxParams().Asset = asset cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetCurrentOutTxParam().OutboundTxTssNonce = 42 + cctx.GetCurrentOutTxParam().OutboundTxGasUsed = 100 + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = 100 return cctx } diff --git a/x/crosschain/keeper/events.go b/x/crosschain/keeper/events.go index 2f6a88908c..fbcf46b5d9 100644 --- a/x/crosschain/keeper/events.go +++ b/x/crosschain/keeper/events.go @@ -59,11 +59,11 @@ func EmitZetaWithdrawCreated(ctx sdk.Context, cctx types.CrossChainTx) { } -func EmitOutboundSuccess(ctx sdk.Context, msg *types.MsgVoteOnObservedOutboundTx, oldStatus string, newStatus string, cctx types.CrossChainTx) { +func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctx types.CrossChainTx) { err := ctx.EventManager().EmitTypedEvents(&types.EventOutboundSuccess{ MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteOnObservedOutboundTx{}), CctxIndex: cctx.Index, - ValueReceived: msg.ValueReceived.String(), + ValueReceived: valueReceived, OldStatus: oldStatus, NewStatus: newStatus, }) @@ -73,11 +73,11 @@ func EmitOutboundSuccess(ctx sdk.Context, msg *types.MsgVoteOnObservedOutboundTx } -func EmitOutboundFailure(ctx sdk.Context, msg *types.MsgVoteOnObservedOutboundTx, oldStatus string, newStatus string, cctx types.CrossChainTx) { +func EmitOutboundFailure(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctx types.CrossChainTx) { err := ctx.EventManager().EmitTypedEvents(&types.EventOutboundFailure{ MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteOnObservedOutboundTx{}), CctxIndex: cctx.Index, - ValueReceived: msg.ValueReceived.String(), + ValueReceived: valueReceived, OldStatus: oldStatus, NewStatus: newStatus, }) diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 4450280501..1602d86b25 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -2,20 +2,10 @@ package keeper import ( "context" - "errors" - "fmt" - "math/big" - - cosmoserrors "cosmossdk.io/errors" - "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/rs/zerolog/log" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) // VoteOnObservedOutboundTx casts a vote on an outbound transaction observed on a connected chain (after @@ -62,20 +52,15 @@ import ( func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.MsgVoteOnObservedOutboundTx) (*types.MsgVoteOnObservedOutboundTxResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // check if CCTX exists and if the nonce matches - cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash) - if !found { - return nil, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) - } - if cctx.GetCurrentOutTxParam().OutboundTxTssNonce != msg.OutTxTssNonce { - return nil, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + // Validate the message params to verify it against an existing cctx + cctx, err := k.ValidateOutboundMessage(ctx, *msg) + if err != nil { + return nil, err } - // get ballot index ballotIndex := msg.Digest() - // vote on outbound ballot - isFinalized, isNew, ballot, observationChain, err := k.zetaObserverKeeper.VoteOnOutboundBallot( + isFinalizingVote, isNew, ballot, observationChain, err := k.zetaObserverKeeper.VoteOnOutboundBallot( ctx, ballotIndex, msg.OutTxChain, @@ -84,168 +69,32 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms if err != nil { return nil, err } - // if the ballot is new, set the index to the CCTX if isNew { observerkeeper.EmitEventBallotCreated(ctx, ballot, msg.ObservedOutTxHash, observationChain) - // Set this the first time when the ballot is created - // The ballot might change if there are more votes in a different outbound ballot for this cctx hash - cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex } - // if not finalized commit state here - if !isFinalized { + if !isFinalizingVote { return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } // if ballot successful, the value received should be the out tx amount - if ballot.BallotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { - if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { - log.Error().Msgf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", - msg.ValueReceived, - cctx.GetCurrentOutTxParam().Amount) - return nil, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, cctx.GetCurrentOutTxParam().Amount)) - } + err = SetOutboundValues(ctx, &cctx, *msg, ballot.BallotStatus) + if err != nil { + return nil, err } - - // Update CCTX values - cctx.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash - cctx.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit - cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() - // Fund the gas stability pool with the remaining funds - if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutTxParam(), msg.OutTxChain); err != nil { - log.Error().Msgf( - "VoteOnObservedOutboundTx: CCTX: %s Can't fund the gas stability pool with remaining fees %s", cctx.Index, err.Error(), - ) - } - - tss, found := k.zetaObserverKeeper.GetTSS(ctx) - if !found { - return nil, types.ErrCannotFindTSSKeys - } - - tmpCtx, commit := ctx.CacheContext() - err = func() error { //err = FinalizeOutbound(k, ctx, &cctx, msg, ballot.BallotStatus) - cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight - oldStatus := cctx.CctxStatus.Status - switch ballot.BallotStatus { - case observertypes.BallotStatus_BallotFinalized_SuccessObservation: - switch oldStatus { - case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") - case types.CctxStatus_PendingOutbound: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "") - } - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundSuccess(tmpCtx, msg, oldStatus.String(), newStatus, cctx) - case observertypes.BallotStatus_BallotFinalized_FailureObservation: - if msg.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { - // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") - } else { - switch oldStatus { - case types.CctxStatus_PendingOutbound: + k.FundStabilityPool(ctx, &cctx) - gasLimit, err := k.GetRevertGasLimit(ctx, &cctx) - if err != nil { - return errors.New("can't get revert tx gas limit" + err.Error()) - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit - } - - // create new OutboundTxParams for the revert - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - OutboundTxGasLimit: gasLimit, - } - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) - - err = k.PayGasAndUpdateCctx( - tmpCtx, - cctx.InboundTxParams.SenderChainId, - &cctx, - cctx.OutboundTxParams[0].Amount, - false, - ) - if err != nil { - return err - } - err = k.UpdateNonce(tmpCtx, cctx.InboundTxParams.SenderChainId, &cctx) - if err != nil { - return err - } - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") - case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") - } - } - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundFailure(ctx, msg, oldStatus.String(), newStatus, cctx) - } - return nil - }() + err = k.ProcessOutbound(ctx, &cctx, ballot.BallotStatus, msg.ValueReceived.String()) if err != nil { - // do not commit tmpCtx - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - ctx.Logger().Error(err.Error()) - // #nosec G701 always in range - k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tss.TssPubkey, msg.OutTxChain, int64(msg.OutTxTssNonce)) - k.RemoveOutTxTracker(ctx, msg.OutTxChain, msg.OutTxTssNonce) - k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) + k.SaveFailedOutBound(ctx, &cctx, err.Error(), ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } - commit() - // Set the ballot index to the finalized ballot - cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - // #nosec G701 always in range - k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tss.TssPubkey, msg.OutTxChain, int64(msg.OutTxTssNonce)) - k.RemoveOutTxTracker(ctx, msg.OutTxChain, msg.OutTxTssNonce) - ctx.Logger().Info(fmt.Sprintf("Remove tracker %s: , Block Height : %d ", getOutTrackerIndex(msg.OutTxChain, msg.OutTxTssNonce), ctx.BlockHeight())) - k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) - return &types.MsgVoteOnObservedOutboundTxResponse{}, nil -} - -func percentOf(n *big.Int, percent int64) *big.Int { - n = n.Mul(n, big.NewInt(percent)) - n = n.Div(n, big.NewInt(100)) - return n -} - -// FundGasStabilityPoolFromRemainingFees funds the gas stability pool with the remaining fees of an outbound tx -func (k Keeper) FundGasStabilityPoolFromRemainingFees(ctx sdk.Context, outboundTxParams types.OutboundTxParams, chainID int64) error { - gasUsed := outboundTxParams.OutboundTxGasUsed - gasLimit := outboundTxParams.OutboundTxEffectiveGasLimit - gasPrice := math.NewUintFromBigInt(outboundTxParams.OutboundTxEffectiveGasPrice.BigInt()) - - if gasLimit == gasUsed { - return nil - } - - // We skip gas stability pool funding if one of the params is zero - if gasLimit > 0 && gasUsed > 0 && !gasPrice.IsZero() { - if gasLimit > gasUsed { - remainingGas := gasLimit - gasUsed - remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt() - - // We fund the stability pool with a portion of the remaining fees - remainingFees = percentOf(remainingFees, RemainingFeesToStabilityPoolPercent) - - // Fund the gas stability pool - if err := k.fungibleKeeper.FundGasStabilityPool(ctx, chainID, remainingFees); err != nil { - return err - } - } else { - return fmt.Errorf("VoteOnObservedOutboundTx: The gas limit %d is less than the gas used %d", gasLimit, gasUsed) - } + err = cctx.Validate() + if err != nil { + return nil, err } - return nil + k.SaveSuccessfulOutBound(ctx, &cctx, ballotIndex) + return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index b5ad6ab78d..1875389328 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -7,10 +7,15 @@ import ( "testing" "cosmossdk.io/math" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - testkeeper "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/keeper" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func TestKeeper_FundGasStabilityPoolFromRemainingFees(t *testing.T) { @@ -85,8 +90,8 @@ func TestKeeper_FundGasStabilityPoolFromRemainingFees(t *testing.T) { for _, tc := range tt { tc := tc t.Run(tc.name, func(t *testing.T) { - k, ctx := testkeeper.CrosschainKeeperAllMocks(t) - fungibleMock := testkeeper.GetCrosschainFungibleMock(t, k) + k, ctx := keepertest.CrosschainKeeperAllMocks(t) + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) // OutboundTxParams outbound := sample.OutboundTxParams(r) @@ -111,3 +116,325 @@ func TestKeeper_FundGasStabilityPoolFromRemainingFees(t *testing.T) { }) } } + +func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { + t.Run("successfully vote on outbound tx with status pending outbound ,vote-type success", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseObserverMock: true, + }) + + // Setup mock data + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + observer := sample.AccAddress() + tss := sample.Tss() + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() + + // Successfully mock VoteOnOutboundBallot + keepertest.MockVoteOnOutboundSuccessBallot(observerMock, ctx, cctx, *senderChain, observer) + + // Successfully mock GetOutBound + keepertest.MockGetOutBound(observerMock, ctx) + + // Successfully mock SaveSuccessfulOutBound + keepertest.MockSaveOutBound(observerMock, ctx, cctx, tss) + + msgServer := keeper.NewMsgServerImpl(*k) + _, err := msgServer.VoteOnObservedOutboundTx(ctx, &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Success, + Creator: observer, + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + }) + require.NoError(t, err) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.Equal(t, types.CctxStatus_OutboundMined, c.CctxStatus.Status) + }) + + t.Run("successfully vote on outbound tx, vote-type failed", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseObserverMock: true, + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + observer := sample.AccAddress() + tss := sample.Tss() + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() + + // Successfully mock VoteOnOutboundBallot + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + + // Successfully mock GetOutBound + keepertest.MockGetOutBound(observerMock, ctx) + + // Successfully mock ProcessOutbound + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + //Successfully mock SaveOutBound + keepertest.MockSaveOutBoundNewRevertCreated(observerMock, ctx, cctx, tss) + oldParamsLen := len(cctx.OutboundTxParams) + msgServer := keeper.NewMsgServerImpl(*k) + _, err := msgServer.VoteOnObservedOutboundTx(ctx, &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Failed, + Creator: observer, + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + }) + require.NoError(t, err) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.Equal(t, types.CctxStatus_PendingRevert, c.CctxStatus.Status) + require.Equal(t, oldParamsLen+1, len(c.OutboundTxParams)) + require.Equal(t, types.TxFinalizationStatus_Executed, c.OutboundTxParams[oldParamsLen-1].TxFinalizationStatus) + require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) + }) + + t.Run("unsuccessfully vote on outbound tx, vote-type failed", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseObserverMock: true, + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + observer := sample.AccAddress() + tss := sample.Tss() + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() + + // Successfully mock VoteOnOutboundBallot + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + + // Successfully mock GetOutBound + keepertest.MockGetOutBound(observerMock, ctx) + + // Mock Failed ProcessOutbound + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + //Successfully mock SaveOutBound + keepertest.MockSaveOutBound(observerMock, ctx, cctx, tss) + oldParamsLen := len(cctx.OutboundTxParams) + msgServer := keeper.NewMsgServerImpl(*k) + _, err := msgServer.VoteOnObservedOutboundTx(ctx, &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Failed, + Creator: observer, + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + }) + require.NoError(t, err) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.Equal(t, types.CctxStatus_Aborted, c.CctxStatus.Status) + require.Equal(t, oldParamsLen+1, len(c.OutboundTxParams)) + // The message processing fails during the creation of the revert tx + // So the original outbound tx is executed and the revert tx is not finalized. + // The cctx status is Aborted + require.Equal(t, types.TxFinalizationStatus_NotFinalized, c.GetCurrentOutTxParam().TxFinalizationStatus) + require.Equal(t, types.TxFinalizationStatus_Executed, c.OutboundTxParams[oldParamsLen-1].TxFinalizationStatus) + }) + + t.Run("failure in processing outbound tx", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseObserverMock: true, + UseFungibleMock: true, + }) + + // Setup mock data + observerMock := keepertest.GetCrosschainObserverMock(t, k) + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + observer := sample.AccAddress() + tss := sample.Tss() + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{observer}}) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + + // Successfully mock GetTSS + observerMock.On("GetTSS", ctx).Return(observertypes.TSS{}, true).Once() + + // Successfully mock VoteOnOutboundBallot + keepertest.MockVoteOnOutboundFailedBallot(observerMock, ctx, cctx, *senderChain, observer) + + // Successfully mock GetOutBound + keepertest.MockGetOutBound(observerMock, ctx) + + // Fail ProcessOutbound so that changes are not committed to the state + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, mock.Anything, mock.Anything).Return(fungibletypes.ForeignCoins{}, false) + + //Successfully mock SaveFailedOutBound + keepertest.MockSaveOutBound(observerMock, ctx, cctx, tss) + + msgServer := keeper.NewMsgServerImpl(*k) + _, err := msgServer.VoteOnObservedOutboundTx(ctx, &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Failed, + Creator: observer, + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + }) + require.NoError(t, err) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + // Status would be CctxStatus_PendingRevert if process outbound did not fail + require.Equal(t, types.CctxStatus_Aborted, c.CctxStatus.Status) + }) + + t.Run("fail to finalize outbound if not a finalizing vote", func(t *testing.T) { + k, ctx, sk, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{}) + + // Setup mock data + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + r := rand.New(rand.NewSource(42)) + validator := sample.Validator(t, r) + tss := sample.Tss() + + // set state to successfully vote on outbound tx + accAddress, err := observertypes.GetAccAddressFromOperatorAddress(validator.OperatorAddress) + require.NoError(t, err) + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{accAddress.String(), sample.AccAddress(), sample.AccAddress()}}) + sk.StakingKeeper.SetValidator(ctx, validator) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetTSS(ctx, tss) + + msgServer := keeper.NewMsgServerImpl(*k) + msg := &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Success, + Creator: accAddress.String(), + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + } + _, err = msgServer.VoteOnObservedOutboundTx(ctx, msg) + require.NoError(t, err) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.Equal(t, types.CctxStatus_PendingOutbound, c.CctxStatus.Status) + ballot, found := zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) + require.True(t, found) + require.True(t, ballot.HasVoted(accAddress.String())) + }) + + t.Run("unable to add vote if tss is not present", func(t *testing.T) { + k, ctx, sk, zk := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{}) + + // Setup mock data + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + r := rand.New(rand.NewSource(42)) + validator := sample.Validator(t, r) + tss := sample.Tss() + + // set state to successfully vote on outbound tx + accAddress, err := observertypes.GetAccAddressFromOperatorAddress(validator.OperatorAddress) + require.NoError(t, err) + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ObserverList: []string{accAddress.String()}}) + sk.StakingKeeper.SetValidator(ctx, validator) + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.GetCurrentOutTxParam().TssPubkey = tss.TssPubkey + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SetCrossChainTx(ctx, *cctx) + + msgServer := keeper.NewMsgServerImpl(*k) + msg := &types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + Status: common.ReceiveStatus_Success, + Creator: accAddress.String(), + ObservedOutTxHash: sample.Hash().String(), + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxBlockHeight: 10, + ObservedOutTxEffectiveGasPrice: math.NewInt(21), + ObservedOutTxGasUsed: 21, + CoinType: cctx.CoinType, + } + _, err = msgServer.VoteOnObservedOutboundTx(ctx, msg) + require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) + c, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + require.Equal(t, types.CctxStatus_PendingOutbound, c.CctxStatus.Status) + _, found = zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) + require.False(t, found) + }) +} From 69e3f33fab17ceff95f679a55354f2a7d4052628 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 18 Mar 2024 16:40:47 -0400 Subject: [PATCH 23/36] remove changes to cctx struct --- docs/openapi/openapi.swagger.yaml | 9 +- proto/crosschain/cross_chain_tx.proto | 4 +- proto/crosschain/cross_chain_tx_v14.proto | 65 - testutil/sample/crosschain.go | 4 +- testutil/sample/crosschain_legacy.go | 56 - typescript/crosschain/cross_chain_tx_pb.d.ts | 20 +- .../crosschain/cross_chain_tx_v14_pb.d.ts | 243 -- typescript/crosschain/index.d.ts | 1 - x/crosschain/keeper/cctx.go | 2 +- x/crosschain/keeper/cctx_test.go | 4 +- x/crosschain/keeper/cctx_utils.go | 197 +- x/crosschain/keeper/cctx_utils_outbound.go | 249 -- .../keeper/cctx_utils_outbound_test.go | 490 ---- x/crosschain/keeper/cctx_utils_test.go | 438 +--- x/crosschain/keeper/evm_deposit.go | 2 +- x/crosschain/keeper/evm_deposit_test.go | 22 +- x/crosschain/keeper/gas_payment.go | 16 +- x/crosschain/keeper/gas_payment_test.go | 68 +- x/crosschain/keeper/migrator.go | 5 - .../keeper/msg_server_migrate_tss_funds.go | 6 +- .../keeper/msg_server_refund_aborted_tx.go | 2 +- .../msg_server_refund_aborted_tx_test.go | 26 +- .../keeper/msg_server_vote_inbound_tx.go | 199 +- .../keeper/msg_server_vote_inbound_tx_test.go | 439 ++++ .../keeper/msg_server_vote_outbound_tx.go | 242 ++ .../msg_server_vote_outbound_tx_test.go | 481 +++- .../keeper/msg_server_whitelist_erc20.go | 12 +- x/crosschain/keeper/refund.go | 4 +- x/crosschain/keeper/refund_test.go | 44 +- x/crosschain/migrations/v4/migrate.go | 2 +- x/crosschain/migrations/v4/migrate_test.go | 7 +- x/crosschain/migrations/v5/migrate.go | 2 +- x/crosschain/migrations/v5/migrate_test.go | 33 +- x/crosschain/migrations/v6/migrate.go | 93 - x/crosschain/migrations/v6/migrate_test.go | 76 - x/crosschain/module.go | 5 +- x/crosschain/types/cctx_utils.go | 9 +- x/crosschain/types/cross_chain_tx.pb.go | 281 ++- x/crosschain/types/cross_chain_tx_v14.pb.go | 2051 ----------------- x/crosschain/types/errors.go | 2 + zetaclient/bitcoin/bitcoin_signer.go | 3 +- zetaclient/evm/evm_client.go | 2 +- zetaclient/evm/evm_signer.go | 8 +- zetaclient/evm/outbound_transaction_data.go | 2 +- .../supplychecker/zeta_supply_checker.go | 2 +- 45 files changed, 1697 insertions(+), 4231 deletions(-) delete mode 100644 proto/crosschain/cross_chain_tx_v14.proto delete mode 100644 testutil/sample/crosschain_legacy.go delete mode 100644 typescript/crosschain/cross_chain_tx_v14_pb.d.ts delete mode 100644 x/crosschain/keeper/cctx_utils_outbound.go delete mode 100644 x/crosschain/keeper/cctx_utils_outbound_test.go delete mode 100644 x/crosschain/migrations/v6/migrate.go delete mode 100644 x/crosschain/migrations/v6/migrate_test.go delete mode 100644 x/crosschain/types/cross_chain_tx_v14.pb.go diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index e658cefb3b..8e2cb02f21 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -53657,11 +53657,6 @@ definitions: items: type: object $ref: '#/definitions/crosschainOutboundTxParams' - event_index: - type: string - format: uint64 - coin_type: - $ref: '#/definitions/commonCoinType' crosschainGasPrice: type: object properties: @@ -53720,6 +53715,8 @@ definitions: tx_origin: type: string title: this address is the EOA that signs the inbound tx + coin_type: + $ref: '#/definitions/commonCoinType' asset: type: string title: for ERC20 coin type, the asset is an address of the ERC20 contract @@ -53810,6 +53807,8 @@ definitions: receiver_chainId: type: string format: int64 + coin_type: + $ref: '#/definitions/commonCoinType' amount: type: string outbound_tx_tss_nonce: diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 3f6557594e..166803f6b8 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -27,6 +27,7 @@ message InboundTxParams { string sender = 1; // this address is the immediate contract/EOA that calls the Connector.send() int64 sender_chain_id = 2; string tx_origin = 3; // this address is the EOA that signs the inbound tx + common.CoinType coin_type = 4; string asset = 5; // for ERC20 coin type, the asset is an address of the ERC20 contract string amount = 6 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", @@ -50,6 +51,7 @@ message ZetaAccounting { message OutboundTxParams { string receiver = 1; int64 receiver_chainId = 2; + common.CoinType coin_type = 3; string amount = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", (gogoproto.nullable) = false @@ -91,6 +93,4 @@ message CrossChainTx { Status cctx_status = 8; InboundTxParams inbound_tx_params = 9; repeated OutboundTxParams outbound_tx_params = 10; - uint64 event_index = 11; - common.CoinType coin_type = 12; } diff --git a/proto/crosschain/cross_chain_tx_v14.proto b/proto/crosschain/cross_chain_tx_v14.proto deleted file mode 100644 index 255ddb3d42..0000000000 --- a/proto/crosschain/cross_chain_tx_v14.proto +++ /dev/null @@ -1,65 +0,0 @@ -syntax = "proto3"; -package zetachain.zetacore.crosschain; - -import "common/common.proto"; -import "crosschain/cross_chain_tx.proto"; -import "gogoproto/gogo.proto"; - -option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; - -message InboundTxParamsV14 { - string sender = 1; // this address is the immediate contract/EOA that calls the Connector.send() - int64 sender_chain_id = 2; - string tx_origin = 3; // this address is the EOA that signs the inbound tx - common.CoinType coin_type = 4; - string asset = 5; // for ERC20 coin type, the asset is an address of the ERC20 contract - string amount = 6 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", - (gogoproto.nullable) = false - ]; - string inbound_tx_observed_hash = 7; - uint64 inbound_tx_observed_external_height = 8; - string inbound_tx_ballot_index = 9; - uint64 inbound_tx_finalized_zeta_height = 10; - TxFinalizationStatus tx_finalization_status = 11; -} - -message OutboundTxParamsV14 { - string receiver = 1; - int64 receiver_chainId = 2; - common.CoinType coin_type = 3; - string amount = 4 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", - (gogoproto.nullable) = false - ]; - uint64 outbound_tx_tss_nonce = 5; - uint64 outbound_tx_gas_limit = 6; - string outbound_tx_gas_price = 7; - // the above are commands for zetaclients - // the following fields are used when the outbound tx is mined - string outbound_tx_hash = 8; - string outbound_tx_ballot_index = 9; - uint64 outbound_tx_observed_external_height = 10; - uint64 outbound_tx_gas_used = 20; - string outbound_tx_effective_gas_price = 21 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", - (gogoproto.nullable) = false - ]; - uint64 outbound_tx_effective_gas_limit = 22; - string tss_pubkey = 11; - TxFinalizationStatus tx_finalization_status = 12; -} - -message CrossChainTxV14 { - string creator = 1; - string index = 2; - string zeta_fees = 5 [ - (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"zeta_fees\"" - ]; - string relayed_message = 6; // Not used by protocol , just relayed across - Status cctx_status = 8; - InboundTxParamsV14 inbound_tx_params = 9; - repeated OutboundTxParamsV14 outbound_tx_params = 10; -} diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index e705f6cddb..8daa3001c2 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -48,6 +48,7 @@ func InboundTxParams(r *rand.Rand) *types.InboundTxParams { InboundTxObservedExternalHeight: r.Uint64(), InboundTxBallotIndex: StringRandom(r, 32), InboundTxFinalizedZetaHeight: r.Uint64(), + CoinType: common.CoinType(r.Intn(100)), } } @@ -78,6 +79,7 @@ func OutboundTxParams(r *rand.Rand) *types.OutboundTxParams { OutboundTxObservedExternalHeight: r.Uint64(), OutboundTxGasUsed: r.Uint64(), OutboundTxEffectiveGasPrice: math.NewInt(r.Int63()), + CoinType: common.CoinType(r.Intn(100)), } } @@ -117,13 +119,11 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx { return &types.CrossChainTx{ Creator: AccAddress(), Index: GetCctxIndexFromString(index), - CoinType: common.CoinType(r.Intn(100)), ZetaFees: math.NewUint(uint64(r.Int63())), RelayedMessage: StringRandom(r, 32), CctxStatus: Status(t, index), InboundTxParams: InboundTxParams(r), OutboundTxParams: []*types.OutboundTxParams{OutboundTxParams(r), OutboundTxParams(r)}, - EventIndex: r.Uint64(), } } diff --git a/testutil/sample/crosschain_legacy.go b/testutil/sample/crosschain_legacy.go deleted file mode 100644 index f32f7caa58..0000000000 --- a/testutil/sample/crosschain_legacy.go +++ /dev/null @@ -1,56 +0,0 @@ -package sample - -import ( - "math/rand" - "testing" - - "cosmossdk.io/math" - "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/x/crosschain/types" -) - -func CrossChainTxV14(t *testing.T, index string) *types.CrossChainTxV14 { - r := newRandFromStringSeed(t, index) - cointType := common.CoinType(r.Intn(100)) - return &types.CrossChainTxV14{ - Creator: AccAddress(), - Index: GetCctxIndexFromString(index), - ZetaFees: math.NewUint(uint64(r.Int63())), - RelayedMessage: StringRandom(r, 32), - CctxStatus: Status(t, index), - InboundTxParams: InboundTxParamsV14(r, cointType), - OutboundTxParams: []*types.OutboundTxParamsV14{OutboundTxParamsV14(r, cointType), OutboundTxParamsV14(r, cointType)}, - } -} - -func InboundTxParamsV14(r *rand.Rand, coinType common.CoinType) *types.InboundTxParamsV14 { - return &types.InboundTxParamsV14{ - Sender: EthAddress().String(), - SenderChainId: r.Int63(), - TxOrigin: EthAddress().String(), - Asset: StringRandom(r, 32), - Amount: math.NewUint(uint64(r.Int63())), - InboundTxObservedHash: StringRandom(r, 32), - InboundTxObservedExternalHeight: r.Uint64(), - InboundTxBallotIndex: StringRandom(r, 32), - InboundTxFinalizedZetaHeight: r.Uint64(), - CoinType: coinType, - } -} - -func OutboundTxParamsV14(r *rand.Rand, coinType common.CoinType) *types.OutboundTxParamsV14 { - return &types.OutboundTxParamsV14{ - Receiver: EthAddress().String(), - ReceiverChainId: r.Int63(), - Amount: math.NewUint(uint64(r.Int63())), - OutboundTxTssNonce: r.Uint64(), - OutboundTxGasLimit: r.Uint64(), - OutboundTxGasPrice: math.NewUint(uint64(r.Int63())).String(), - OutboundTxHash: StringRandom(r, 32), - OutboundTxBallotIndex: StringRandom(r, 32), - OutboundTxObservedExternalHeight: r.Uint64(), - OutboundTxGasUsed: r.Uint64(), - OutboundTxEffectiveGasPrice: math.NewInt(r.Int63()), - CoinType: coinType, - } -} diff --git a/typescript/crosschain/cross_chain_tx_pb.d.ts b/typescript/crosschain/cross_chain_tx_pb.d.ts index a370b8a079..0157548d54 100644 --- a/typescript/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/crosschain/cross_chain_tx_pb.d.ts @@ -103,6 +103,11 @@ export declare class InboundTxParams extends Message { */ txOrigin: string; + /** + * @generated from field: common.CoinType coin_type = 4; + */ + coinType: CoinType; + /** * for ERC20 coin type, the asset is an address of the ERC20 contract * @@ -195,6 +200,11 @@ export declare class OutboundTxParams extends Message { */ receiverChainId: bigint; + /** + * @generated from field: common.CoinType coin_type = 3; + */ + coinType: CoinType; + /** * @generated from field: string amount = 4; */ @@ -353,16 +363,6 @@ export declare class CrossChainTx extends Message { */ outboundTxParams: OutboundTxParams[]; - /** - * @generated from field: uint64 event_index = 11; - */ - eventIndex: bigint; - - /** - * @generated from field: common.CoinType coin_type = 12; - */ - coinType: CoinType; - constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/crosschain/cross_chain_tx_v14_pb.d.ts b/typescript/crosschain/cross_chain_tx_v14_pb.d.ts deleted file mode 100644 index 7f47395c89..0000000000 --- a/typescript/crosschain/cross_chain_tx_v14_pb.d.ts +++ /dev/null @@ -1,243 +0,0 @@ -// @generated by protoc-gen-es v1.3.0 with parameter "target=dts" -// @generated from file crosschain/cross_chain_tx_v14.proto (package zetachain.zetacore.crosschain, syntax proto3) -/* eslint-disable */ -// @ts-nocheck - -import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; -import { Message, proto3 } from "@bufbuild/protobuf"; -import type { CoinType } from "../common/common_pb.js"; -import type { Status, TxFinalizationStatus } from "./cross_chain_tx_pb.js"; - -/** - * @generated from message zetachain.zetacore.crosschain.InboundTxParamsV14 - */ -export declare class InboundTxParamsV14 extends Message { - /** - * this address is the immediate contract/EOA that calls the Connector.send() - * - * @generated from field: string sender = 1; - */ - sender: string; - - /** - * @generated from field: int64 sender_chain_id = 2; - */ - senderChainId: bigint; - - /** - * this address is the EOA that signs the inbound tx - * - * @generated from field: string tx_origin = 3; - */ - txOrigin: string; - - /** - * @generated from field: common.CoinType coin_type = 4; - */ - coinType: CoinType; - - /** - * for ERC20 coin type, the asset is an address of the ERC20 contract - * - * @generated from field: string asset = 5; - */ - asset: string; - - /** - * @generated from field: string amount = 6; - */ - amount: string; - - /** - * @generated from field: string inbound_tx_observed_hash = 7; - */ - inboundTxObservedHash: string; - - /** - * @generated from field: uint64 inbound_tx_observed_external_height = 8; - */ - inboundTxObservedExternalHeight: bigint; - - /** - * @generated from field: string inbound_tx_ballot_index = 9; - */ - inboundTxBallotIndex: string; - - /** - * @generated from field: uint64 inbound_tx_finalized_zeta_height = 10; - */ - inboundTxFinalizedZetaHeight: bigint; - - /** - * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 11; - */ - txFinalizationStatus: TxFinalizationStatus; - - constructor(data?: PartialMessage); - - static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.InboundTxParamsV14"; - static readonly fields: FieldList; - - static fromBinary(bytes: Uint8Array, options?: Partial): InboundTxParamsV14; - - static fromJson(jsonValue: JsonValue, options?: Partial): InboundTxParamsV14; - - static fromJsonString(jsonString: string, options?: Partial): InboundTxParamsV14; - - static equals(a: InboundTxParamsV14 | PlainMessage | undefined, b: InboundTxParamsV14 | PlainMessage | undefined): boolean; -} - -/** - * @generated from message zetachain.zetacore.crosschain.OutboundTxParamsV14 - */ -export declare class OutboundTxParamsV14 extends Message { - /** - * @generated from field: string receiver = 1; - */ - receiver: string; - - /** - * @generated from field: int64 receiver_chainId = 2; - */ - receiverChainId: bigint; - - /** - * @generated from field: common.CoinType coin_type = 3; - */ - coinType: CoinType; - - /** - * @generated from field: string amount = 4; - */ - amount: string; - - /** - * @generated from field: uint64 outbound_tx_tss_nonce = 5; - */ - outboundTxTssNonce: bigint; - - /** - * @generated from field: uint64 outbound_tx_gas_limit = 6; - */ - outboundTxGasLimit: bigint; - - /** - * @generated from field: string outbound_tx_gas_price = 7; - */ - outboundTxGasPrice: string; - - /** - * the above are commands for zetaclients - * the following fields are used when the outbound tx is mined - * - * @generated from field: string outbound_tx_hash = 8; - */ - outboundTxHash: string; - - /** - * @generated from field: string outbound_tx_ballot_index = 9; - */ - outboundTxBallotIndex: string; - - /** - * @generated from field: uint64 outbound_tx_observed_external_height = 10; - */ - outboundTxObservedExternalHeight: bigint; - - /** - * @generated from field: uint64 outbound_tx_gas_used = 20; - */ - outboundTxGasUsed: bigint; - - /** - * @generated from field: string outbound_tx_effective_gas_price = 21; - */ - outboundTxEffectiveGasPrice: string; - - /** - * @generated from field: uint64 outbound_tx_effective_gas_limit = 22; - */ - outboundTxEffectiveGasLimit: bigint; - - /** - * @generated from field: string tss_pubkey = 11; - */ - tssPubkey: string; - - /** - * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 12; - */ - txFinalizationStatus: TxFinalizationStatus; - - constructor(data?: PartialMessage); - - static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.OutboundTxParamsV14"; - static readonly fields: FieldList; - - static fromBinary(bytes: Uint8Array, options?: Partial): OutboundTxParamsV14; - - static fromJson(jsonValue: JsonValue, options?: Partial): OutboundTxParamsV14; - - static fromJsonString(jsonString: string, options?: Partial): OutboundTxParamsV14; - - static equals(a: OutboundTxParamsV14 | PlainMessage | undefined, b: OutboundTxParamsV14 | PlainMessage | undefined): boolean; -} - -/** - * @generated from message zetachain.zetacore.crosschain.CrossChainTxV14 - */ -export declare class CrossChainTxV14 extends Message { - /** - * @generated from field: string creator = 1; - */ - creator: string; - - /** - * @generated from field: string index = 2; - */ - index: string; - - /** - * @generated from field: string zeta_fees = 5; - */ - zetaFees: string; - - /** - * Not used by protocol , just relayed across - * - * @generated from field: string relayed_message = 6; - */ - relayedMessage: string; - - /** - * @generated from field: zetachain.zetacore.crosschain.Status cctx_status = 8; - */ - cctxStatus?: Status; - - /** - * @generated from field: zetachain.zetacore.crosschain.InboundTxParamsV14 inbound_tx_params = 9; - */ - inboundTxParams?: InboundTxParamsV14; - - /** - * @generated from field: repeated zetachain.zetacore.crosschain.OutboundTxParamsV14 outbound_tx_params = 10; - */ - outboundTxParams: OutboundTxParamsV14[]; - - constructor(data?: PartialMessage); - - static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.CrossChainTxV14"; - static readonly fields: FieldList; - - static fromBinary(bytes: Uint8Array, options?: Partial): CrossChainTxV14; - - static fromJson(jsonValue: JsonValue, options?: Partial): CrossChainTxV14; - - static fromJsonString(jsonString: string, options?: Partial): CrossChainTxV14; - - static equals(a: CrossChainTxV14 | PlainMessage | undefined, b: CrossChainTxV14 | PlainMessage | undefined): boolean; -} - diff --git a/typescript/crosschain/index.d.ts b/typescript/crosschain/index.d.ts index f5fb4873df..4c073541bc 100644 --- a/typescript/crosschain/index.d.ts +++ b/typescript/crosschain/index.d.ts @@ -1,5 +1,4 @@ export * from "./cross_chain_tx_pb"; -export * from "./cross_chain_tx_v14_pb"; export * from "./events_pb"; export * from "./gas_price_pb"; export * from "./genesis_pb"; diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index 7411d787fd..29fda96f00 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -47,7 +47,7 @@ func (k Keeper) SetCctxAndNonceToCctxAndInTxHashToCctx(ctx sdk.Context, cctx typ Tss: tss.TssPubkey, }) } - if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.CoinType == common.CoinType_Zeta { + if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.InboundTxParams.CoinType == common.CoinType_Zeta { k.AddZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) } } diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index bf98fc1d30..5e057cb833 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -51,6 +51,7 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha InboundTxObservedHash: fmt.Sprintf("%d", i), InboundTxObservedExternalHeight: uint64(i), InboundTxFinalizedZetaHeight: uint64(i), + CoinType: common.CoinType_Zeta, } items[i].OutboundTxParams = []*types.OutboundTxParams{{ Receiver: fmt.Sprintf("%d", i), @@ -61,6 +62,7 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha OutboundTxGasPrice: fmt.Sprintf("%d", i), OutboundTxBallotIndex: fmt.Sprintf("%d", i), OutboundTxObservedExternalHeight: uint64(i), + CoinType: common.CoinType_Zeta, }} items[i].CctxStatus = &types.Status{ Status: types.CctxStatus_PendingInbound, @@ -71,7 +73,7 @@ func createNCctx(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.CrossCha items[i].ZetaFees = math.OneUint() items[i].Index = fmt.Sprintf("%d", i) - items[i].CoinType = common.CoinType_Zeta + keeper.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, items[i]) } return items diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 381b7a9b7e..190574dcfb 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -15,73 +15,6 @@ import ( zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types" ) -func (k Keeper) GetInbound(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx) types.CrossChainTx { - - // get the latest TSS to set the TSS public key in the CCTX - tssPub := "" - tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) - if tssFound { - tssPub = tss.TssPubkey - } - return CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) -} - -func CreateNewCCTX( - ctx sdk.Context, - msg *types.MsgVoteOnObservedInboundTx, - index string, - tssPubkey string, - s types.CctxStatus, - senderChainID, - receiverChainID int64, -) types.CrossChainTx { - if msg.TxOrigin == "" { - msg.TxOrigin = msg.Sender - } - inboundParams := &types.InboundTxParams{ - Sender: msg.Sender, - SenderChainId: senderChainID, - TxOrigin: msg.TxOrigin, - Asset: msg.Asset, - Amount: msg.Amount, - InboundTxObservedHash: msg.InTxHash, - InboundTxObservedExternalHeight: msg.InBlockHeight, - InboundTxFinalizedZetaHeight: 0, - InboundTxBallotIndex: index, - } - - outBoundParams := &types.OutboundTxParams{ - Receiver: msg.Receiver, - ReceiverChainId: receiverChainID, - OutboundTxHash: "", - OutboundTxTssNonce: 0, - OutboundTxGasLimit: msg.GasLimit, - OutboundTxGasPrice: "", - OutboundTxBallotIndex: "", - OutboundTxObservedExternalHeight: 0, - Amount: sdkmath.ZeroUint(), - TssPubkey: tssPubkey, - } - status := &types.Status{ - Status: s, - StatusMessage: "", - LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), - IsAbortRefunded: false, - } - newCctx := types.CrossChainTx{ - Creator: msg.Creator, - Index: index, - ZetaFees: sdkmath.ZeroUint(), - RelayedMessage: msg.Message, - CctxStatus: status, - InboundTxParams: inboundParams, - OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, - EventIndex: msg.EventIndex, - CoinType: msg.CoinType, - } - return newCctx -} - // UpdateNonce sets the CCTX outbound nonce to the next nonce, and updates the nonce of blockchain state. // It also updates the PendingNonces that is used to track the unfulfilled outbound txs. func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error { @@ -126,7 +59,7 @@ func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (ui return 0, nil } - if cctx.CoinType == common.CoinType_Gas { + if cctx.InboundTxParams.CoinType == common.CoinType_Gas { // get the gas limit of the gas token fc, found := k.fungibleKeeper.GetGasCoinForForeignCoin(ctx, cctx.InboundTxParams.SenderChainId) if !found { @@ -137,7 +70,7 @@ func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (ui return 0, errors.Wrap(fungibletypes.ErrContractCall, err.Error()) } return gasLimit.Uint64(), nil - } else if cctx.CoinType == common.CoinType_ERC20 { + } else if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { // get the gas limit of the associated asset fc, found := k.fungibleKeeper.GetForeignCoinFromAsset(ctx, cctx.InboundTxParams.Asset, cctx.InboundTxParams.SenderChainId) if !found { @@ -172,129 +105,3 @@ func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { return sdkmath.ZeroUint() } - -// ProcessInbound processes the inbound CCTX. -// It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. -func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { - if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { - k.ProcessZEVMDeposit(ctx, cctx) - } else { - k.ProcessCrosschainMsgPassing(ctx, cctx) - } -} - -// ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain. -// If the deposit is successful, the CCTX status is changed to OutboundMined. -// If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. -// If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. -// If the creation of revert tx also fails it changes the status to Aborted. -// Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. -// We do not return an error from this function , as all changes need to be persisted to the state. -// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. -func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { - tmpCtx, commit := ctx.CacheContext() - isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) - - if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) - return - } else if err != nil && isContractReverted { // contract call reverted; should refund - revertMessage := err.Error() - senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) - if senderChain == nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") - return - } - - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) - if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("can't get revert tx gas limit,%s", err.Error())) - return - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit - } - - // create new OutboundTxParams for the revert - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - OutboundTxGasLimit: gasLimit, - } - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) - - // we create a new cached context, and we don't commit the previous one with EVM deposit - tmpCtxRevert, commitRevert := ctx.CacheContext() - err = func() error { - err := k.PayGasAndUpdateCctx( - tmpCtxRevert, - senderChain.ChainId, - cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - // Update nonce using senderchain id as this is a revert tx and would go back to the original sender - return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) - }() - if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) - return - } - commitRevert() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) - return - } - // successful HandleEVMDeposit; - commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "Remote omnichain contract call completed") - return -} - -// ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain. -// If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. -// If the crosschain message passing returns an error, the CCTX status is changed to Aborted. -// We do not return an error from this function , as all changes need to be persisted to the state. -// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. -func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { - tmpCtx, commit := ctx.CacheContext() - outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId - err := func() error { - err := k.PayGasAndUpdateCctx( - tmpCtx, - outboundReceiverChainID, - cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - return k.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx) - }() - if err != nil { - // do not commit anything here as the CCTX should be aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) - return - } - commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingOutbound, "") - return -} - -func (k Keeper) SaveInbound(ctx sdk.Context, cctx *types.CrossChainTx) { - EmitEventInboundFinalized(ctx, cctx) - k.AddFinalizedInbound(ctx, - cctx.GetInboundTxParams().InboundTxObservedHash, - cctx.GetInboundTxParams().SenderChainId, - cctx.EventIndex) - // #nosec G701 always positive - cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) - cctx.InboundTxParams.TxFinalizationStatus = types.TxFinalizationStatus_Executed - k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) - k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) -} diff --git a/x/crosschain/keeper/cctx_utils_outbound.go b/x/crosschain/keeper/cctx_utils_outbound.go deleted file mode 100644 index 7ba5e291ee..0000000000 --- a/x/crosschain/keeper/cctx_utils_outbound.go +++ /dev/null @@ -1,249 +0,0 @@ -package keeper - -import ( - "fmt" - "math/big" - - cosmoserrors "cosmossdk.io/errors" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/x/crosschain/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -// SetRevertOutboundValues does the following things in one function: -// 1. create a new OutboundTxParams for the revert -// 2. append the new OutboundTxParams to the current OutboundTxParams -// 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. -func SetRevertOutboundValues(cctx *types.CrossChainTx, gasLimit uint64) { - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - OutboundTxGasLimit: gasLimit, - TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, - } - // The original outbound has been finalized, the new outbound is pending - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) -} - -// SetOutboundValues sets the required values for the outbound transaction -// Note: It expects the cctx to already have been created, -// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer -func SetOutboundValues(ctx sdk.Context, cctx *types.CrossChainTx, msg types.MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { - if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { - if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { - ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", - msg.ValueReceived, - cctx.GetCurrentOutTxParam().Amount)) - return cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, cctx.GetCurrentOutTxParam().Amount)) - } - } - // Update CCTX values - cctx.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash - cctx.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit - cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight - cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() - - return nil -} - -// FundStabilityPool funds the stability pool with the remaining fees of an outbound tx -// The funds are sent to the gas stability pool associated with the receiver chain -func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) { - // Fund the gas stability pool with the remaining funds - if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutTxParam(), cctx.GetCurrentOutTxParam().ReceiverChainId); err != nil { - ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: CCTX: %s Can't fund the gas stability pool with remaining fees %s", cctx.Index, err.Error())) - } -} - -// FundGasStabilityPoolFromRemainingFees funds the gas stability pool with the remaining fees of an outbound tx -func (k Keeper) FundGasStabilityPoolFromRemainingFees(ctx sdk.Context, outboundTxParams types.OutboundTxParams, chainID int64) error { - gasUsed := outboundTxParams.OutboundTxGasUsed - gasLimit := outboundTxParams.OutboundTxEffectiveGasLimit - gasPrice := math.NewUintFromBigInt(outboundTxParams.OutboundTxEffectiveGasPrice.BigInt()) - - if gasLimit == gasUsed { - return nil - } - - // We skip gas stability pool funding if one of the params is zero - if gasLimit > 0 && gasUsed > 0 && !gasPrice.IsZero() { - if gasLimit > gasUsed { - remainingGas := gasLimit - gasUsed - remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt() - - // We fund the stability pool with a portion of the remaining fees - remainingFees = percentOf(remainingFees, RemainingFeesToStabilityPoolPercent) - // Fund the gas stability pool - if err := k.fungibleKeeper.FundGasStabilityPool(ctx, chainID, remainingFees); err != nil { - return err - } - } else { - return fmt.Errorf("VoteOnObservedOutboundTx: The gas limit %d is less than the gas used %d", gasLimit, gasUsed) - } - } - return nil -} - -// percentOf returns the percentage of a number -func percentOf(n *big.Int, percent int64) *big.Int { - n = n.Mul(n, big.NewInt(percent)) - n = n.Div(n, big.NewInt(100)) - return n -} - -// ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: -// 1. Change the status of the CCTX from PendingRevert to Reverted or from PendingOutbound to OutboundMined -// 2. Set the finalization status of the current outbound tx to executed -// 3. Emit an event for the successful outbound transaction -func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { - oldStatus := cctx.CctxStatus.Status - switch oldStatus { - case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") - case types.CctxStatus_PendingOutbound: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "") - default: - return - } - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) -} - -// ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: -// 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX -// 2. For other CCTX, it creates a revert tx if the outbound tx is pending. If the status is pending revert, it aborts the CCTX -// 3. Emit an event for the failed outbound transaction -// 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction -func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { - oldStatus := cctx.CctxStatus.Status - if cctx.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { - // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") - } else { - switch oldStatus { - case types.CctxStatus_PendingOutbound: - - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) - if err != nil { - return cosmoserrors.Wrap(err, "GetRevertGasLimit") - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit - } - - // create new OutboundTxParams for the revert - SetRevertOutboundValues(cctx, gasLimit) - - err = k.PayGasAndUpdateCctx( - ctx, - cctx.InboundTxParams.SenderChainId, - cctx, - cctx.OutboundTxParams[0].Amount, - false, - ) - if err != nil { - return err - } - err = k.UpdateNonce(ctx, cctx.InboundTxParams.SenderChainId, cctx) - if err != nil { - return err - } - // Not setting the finalization status here, the required changes have been mad while creating the revert tx - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") - case types.CctxStatus_PendingRevert: - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") - } - } - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) - return nil -} - -// ProcessOutbound processes the finalization of an outbound transaction based on the ballot status -// The state is committed only if the individual steps are successful -func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotStatus observertypes.BallotStatus, valueReceived string) error { - tmpCtx, commit := ctx.CacheContext() - err := func() error { - switch ballotStatus { - case observertypes.BallotStatus_BallotFinalized_SuccessObservation: - k.ProcessSuccessfulOutbound(tmpCtx, cctx, valueReceived) - case observertypes.BallotStatus_BallotFinalized_FailureObservation: - err := k.ProcessFailedOutbound(tmpCtx, cctx, valueReceived) - if err != nil { - return err - } - } - return nil - }() - if err != nil { - return err - } - commit() - return nil -} - -// SaveFailedOutBound saves a failed outbound transaction. -// It does the following things in one function: -// 1. Change the status of the CCTX to Aborted -// 2. Save the outbound -func (k Keeper) SaveFailedOutBound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) - ctx.Logger().Error(errMessage) - - k.SaveOutbound(ctx, cctx, ballotIndex) -} - -// SaveSuccessfulOutBound saves a successful outbound transaction. -func (k Keeper) SaveSuccessfulOutBound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { - k.SaveOutbound(ctx, cctx, ballotIndex) -} - -// SaveOutbound saves the outbound transaction.It does the following things in one function: -// 1. Set the ballot index for the outbound vote to the cctx -// 2. Remove the nonce from the pending nonces -// 3. Remove the outbound tx tracker -// 4. Set the cctx and nonce to cctx and inTxHash to cctx -func (k Keeper) SaveOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { - receiverChain := cctx.GetCurrentOutTxParam().ReceiverChainId - tssPubkey := cctx.GetCurrentOutTxParam().TssPubkey - outTxTssNonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce - - cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex - // #nosec G701 always in range - k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tssPubkey, receiverChain, int64(outTxTssNonce)) - k.RemoveOutTxTracker(ctx, receiverChain, outTxTssNonce) - ctx.Logger().Info(fmt.Sprintf("Remove tracker %s: , Block Height : %d ", getOutTrackerIndex(receiverChain, outTxTssNonce), ctx.BlockHeight())) - // This should set nonce to cctx only if a new revert is created. - k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) -} - -func (k Keeper) ValidateOutboundMessage(ctx sdk.Context, msg types.MsgVoteOnObservedOutboundTx) (types.CrossChainTx, error) { - // check if CCTX exists and if the nonce matches - cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash) - if !found { - return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) - } - if cctx.GetCurrentOutTxParam().OutboundTxTssNonce != msg.OutTxTssNonce { - return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) - } - // do not process an outbound vote if TSS is not found - _, found = k.zetaObserverKeeper.GetTSS(ctx) - if !found { - return types.CrossChainTx{}, types.ErrCannotFindTSSKeys - } - if cctx.GetCurrentOutTxParam().ReceiverChainId != msg.OutTxChain { - return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", msg.OutTxChain, cctx.GetCurrentOutTxParam().ReceiverChainId)) - } - return cctx, nil -} diff --git a/x/crosschain/keeper/cctx_utils_outbound_test.go b/x/crosschain/keeper/cctx_utils_outbound_test.go deleted file mode 100644 index 78636c18c9..0000000000 --- a/x/crosschain/keeper/cctx_utils_outbound_test.go +++ /dev/null @@ -1,490 +0,0 @@ -package keeper_test - -import ( - "fmt" - "math/big" - "testing" - - sdkmath "cosmossdk.io/math" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/zeta-chain/zetacore/common" - keepertest "github.com/zeta-chain/zetacore/testutil/keeper" - "github.com/zeta-chain/zetacore/testutil/sample" - "github.com/zeta-chain/zetacore/x/crosschain/keeper" - "github.com/zeta-chain/zetacore/x/crosschain/types" - fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -func TestKeeper_GetOutbound(t *testing.T) { - t.Run("successfully get outbound tx", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ValueReceived: cctx.GetCurrentOutTxParam().Amount, - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) - require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) - }) - - t.Run("successfully get outbound tx for failed ballot without amount check", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_FailureObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) - require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) - }) - - t.Run("failed to get outbound tx if amount does not match value received", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ValueReceived: sdkmath.NewUint(100), - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - }) -} - -func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - // transition to reverted if pending revert - cctx.CctxStatus.Status = types.CctxStatus_PendingRevert - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Reverted) - // transition to outbound mined if pending outbound - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) - // do nothing if it's in any other state - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) -} - -func TestKeeper_ProcessFailedOutbound(t *testing.T) { - t.Run("successfully process failed outbound set to aborted for type cmd", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.CoinType = common.CoinType_Cmd - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process failed outbound set to aborted for withdraw tx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.InboundTxParams.SenderChainId = common.ZetaChainMainnet().ChainId - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process failed outbound set to pending revert", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - // Remove the first outbound tx param to make the scenario realistic - oldParams := cctx.OutboundTxParams - cctx.OutboundTxParams = make([]*types.OutboundTxParams, 1) - cctx.OutboundTxParams[0] = oldParams[1] - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) - require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) - - }) - - t.Run("unable to process revert when update nonce fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock failed UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, types.ErrCannotFindReceiverNonce) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) - - t.Run("unable to process revert when PayGasAndUpdateCctx fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, observertypes.ErrSupportedChains) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) - - t.Run("unable to process revert when GetRevertGasLimit fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock failed GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, false).Once() - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, types.ErrForeignCoinNotFound) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) -} - -func TestKeeper_ProcessOutbound(t *testing.T) { - t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) - }) - - t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus.Status = types.CctxStatus_PendingRevert - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - cctx.CoinType = common.CoinType_Cmd - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("do not process outbound on error, no new outbound created", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - oldOutTxParamsLen := len(cctx.OutboundTxParams) - // mock failed GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, false).Once() - - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.ErrorIs(t, err, types.ErrForeignCoinNotFound) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - // New outbound not added and the old outbound is not finalized - require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) - }) - - t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - oldOutTxParamsLen := len(cctx.OutboundTxParams) - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) - - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) - // New outbound added for revert and the old outbound is finalized - require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen+1) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) - require.Equal(t, cctx.OutboundTxParams[oldOutTxParamsLen-1].TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) -} - -func TestKeeper_SaveFailedOutBound(t *testing.T) { - t.Run("successfully save failed outbound", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetOutTxTracker(ctx, types.OutTxTracker{ - Index: "", - ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, - Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - HashList: nil, - }) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.SaveFailedOutBound(ctx, cctx, sample.String(), sample.ZetaIndex(t)) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.False(t, found) - }) -} - -func TestKeeper_SaveSuccessfulOutBound(t *testing.T) { - t.Run("successfully save successful outbound", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetOutTxTracker(ctx, types.OutTxTracker{ - Index: "", - ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, - Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - HashList: nil, - }) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.SaveSuccessfulOutBound(ctx, cctx, sample.String()) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, sample.String()) - _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.False(t, found) - }) -} - -func TestKeeper_SaveOutbound(t *testing.T) { - t.Run("successfully save outbound", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - - // setup state for crosschain and observer modules - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - ballotIndex := sample.String() - k.SetOutTxTracker(ctx, types.OutTxTracker{ - Index: "", - ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, - Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - HashList: nil, - }) - - zk.ObserverKeeper.SetPendingNonces(ctx, observertypes.PendingNonces{ - NonceLow: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - 1, - NonceHigh: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + 1, - ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, - Tss: cctx.GetCurrentOutTxParam().TssPubkey, - }) - zk.ObserverKeeper.SetTSS(ctx, observertypes.TSS{ - TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, - }) - - // Save outbound and assert all values are successfully saved - k.SaveOutbound(ctx, cctx, ballotIndex) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, ballotIndex) - _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.False(t, found) - pn, found := zk.ObserverKeeper.GetPendingNonces(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId) - require.True(t, found) - require.Equal(t, pn.NonceLow, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) - require.Equal(t, pn.NonceHigh, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) - _, found = k.GetInTxHashToCctx(ctx, cctx.InboundTxParams.InboundTxObservedHash) - require.True(t, found) - _, found = zk.ObserverKeeper.GetNonceToCctx(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) - require.True(t, found) - }) -} - -func Test_SetRevertOutboundValues(t *testing.T) { - cctx := sample.CrossChainTx(t, "test") - cctx.OutboundTxParams = cctx.OutboundTxParams[:1] - keeper.SetRevertOutboundValues(cctx, 100) - require.Len(t, cctx.OutboundTxParams, 2) - require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) - require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) - require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) -} - -func TestKeeper_ValidateOutboundMessage(t *testing.T) { - t.Run("successfully validate outbound message", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetCrossChainTx(ctx, *cctx) - zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) - _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ - CctxHash: cctx.Index, - OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, - }) - require.NoError(t, err) - }) - - t.Run("failed to validate outbound message if cctx not found", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - msg := types.MsgVoteOnObservedOutboundTx{ - CctxHash: sample.String(), - OutTxTssNonce: 1, - } - _, err := k.ValidateOutboundMessage(ctx, msg) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) - }) - - t.Run("failed to validate outbound message if nonce does not match", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetCrossChainTx(ctx, *cctx) - msg := types.MsgVoteOnObservedOutboundTx{ - CctxHash: cctx.Index, - OutTxTssNonce: 2, - } - _, err := k.ValidateOutboundMessage(ctx, msg) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) - }) - - t.Run("failed to validate outbound message if tss not found", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetCrossChainTx(ctx, *cctx) - _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ - CctxHash: cctx.Index, - OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - }) - require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) - }) - - t.Run("failed to validate outbound message if chain does not match", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - k.SetCrossChainTx(ctx, *cctx) - zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) - _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ - CctxHash: cctx.Index, - OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, - OutTxChain: 2, - }) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - require.ErrorContains(t, err, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", 2, cctx.GetCurrentOutTxParam().ReceiverChainId)) - }) -} diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index f0255214a8..00bf4db518 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -6,8 +6,6 @@ import ( "testing" sdkmath "cosmossdk.io/math" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -15,7 +13,6 @@ import ( crosschainkeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) func TestGetRevertGasLimit(t *testing.T) { @@ -31,7 +28,10 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_Zeta}) + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + }, + }) require.NoError(t, err) require.Equal(t, uint64(0), gasLimit) }) @@ -48,9 +48,10 @@ func TestGetRevertGasLimit(t *testing.T) { require.NoError(t, err) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, + CoinType: common.CoinType_Gas, }}) require.NoError(t, err) require.Equal(t, uint64(42), gasLimit) @@ -78,10 +79,11 @@ func TestGetRevertGasLimit(t *testing.T) { require.NoError(t, err) gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Asset: asset, + CoinType: common.CoinType_ERC20, }}) require.NoError(t, err) require.Equal(t, uint64(42), gasLimit) @@ -91,9 +93,10 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ SenderChainId: 999999, + CoinType: common.CoinType_Gas, }}) require.ErrorIs(t, err, types.ErrForeignCoinNotFound) }) @@ -112,9 +115,10 @@ func TestGetRevertGasLimit(t *testing.T) { // no contract deployed therefore will fail _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, + CoinType: common.CoinType_Gas, }}) require.ErrorIs(t, err, fungibletypes.ErrContractCall) }) @@ -123,9 +127,10 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: 999999, + CoinType: common.CoinType_ERC20, }}) require.ErrorIs(t, err, types.ErrForeignCoinNotFound) }) @@ -146,10 +151,10 @@ func TestGetRevertGasLimit(t *testing.T) { // no contract deployed therefore will fail _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ - CoinType: common.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Asset: asset, + CoinType: common.CoinType_ERC20, }}) require.ErrorIs(t, err, fungibletypes.ErrContractCall) }) @@ -194,365 +199,6 @@ func TestGetAbortedAmount(t *testing.T) { }) } -func TestKeeper_ProcessZEVMDeposit(t *testing.T) { - t.Run("process zevm deposit successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - - // expect DepositCoinZeta to be called - fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). - Return(nil) - - // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = 0 - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit returns err without reverting", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - - // mock unsuccessful HandleEVMDeposit which does not revert - fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). - Return(fmt.Errorf("deposit error"), false) - - // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = 0 - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at GetSupportedChainFromChainID", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // mock unsuccessful GetSupportedChainFromChainID - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, "invalid sender chain", cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock unsuccessful GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{}, false) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("can't get revert tx gas limit,%s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // Setup expected calls - errDeposit := fmt.Errorf("deposit failed") - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - observerMock := keepertest.GetCrosschainObserverMock(t, k) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock unsuccessful PayGasInERC20AndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at UpdateNonce", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // Mock unsuccessful UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) - require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) - require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - }) -} - -func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { - t.Run("process crosschain msg passing successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") - - // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) - require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - }) - - t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock unsuccessful PayGasAndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). - Return(nil).Once() - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") - - // mock unsuccessful UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") - }) -} - -func TestKeeper_GetInbound(t *testing.T) { - t.Run("should return a cctx with correct values", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - senderChain := getValidEthChain(t) - sender := sample.EthAddress() - receiverChain := getValidEthChain(t) - receiver := sample.EthAddress() - creator := sample.AccAddress() - amount := sdkmath.NewUint(42) - message := "test" - intxBlockHeight := uint64(420) - intxHash := sample.Hash() - gasLimit := uint64(100) - asset := "test-asset" - eventIndex := uint64(1) - cointType := common.CoinType_ERC20 - tss := sample.Tss() - msg := types.MsgVoteOnObservedInboundTx{ - Creator: creator, - Sender: sender.String(), - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InTxHash: intxHash.String(), - InBlockHeight: intxBlockHeight, - GasLimit: gasLimit, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, - } - zk.ObserverKeeper.SetTSS(ctx, tss) - cctx := k.GetInbound(ctx, &msg) - require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) - require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) - require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) - require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) - require.Equal(t, amount, cctx.GetInboundTxParams().Amount) - require.Equal(t, message, cctx.RelayedMessage) - require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) - require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) - require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) - require.Equal(t, asset, cctx.GetInboundTxParams().Asset) - require.Equal(t, eventIndex, cctx.EventIndex) - require.Equal(t, cointType, cctx.CoinType) - require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) - require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) - require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) - }) -} - func Test_IsPending(t *testing.T) { tt := []struct { status types.CctxStatus @@ -571,57 +217,3 @@ func Test_IsPending(t *testing.T) { }) } } - -func TestKeeper_SaveInbound(t *testing.T) { - t.Run("should save the cctx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) - k.SaveInbound(ctx, cctx) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) - require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, cctx.EventIndex)) - _, found := k.GetCrossChainTx(ctx, cctx.Index) - require.True(t, found) - }) - - t.Run("should save the cctx and remove tracker", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) - hash := sample.Hash() - cctx.InboundTxParams.InboundTxObservedHash = hash.String() - k.SetInTxTracker(ctx, types.InTxTracker{ - ChainId: senderChain.ChainId, - TxHash: hash.String(), - CoinType: 0, - }) - k.SaveInbound(ctx, cctx) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) - require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, cctx.EventIndex)) - _, found := k.GetCrossChainTx(ctx, cctx.Index) - require.True(t, found) - _, found = k.GetInTxTracker(ctx, senderChain.ChainId, hash.String()) - require.False(t, found) - }) -} - -func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.Chain, asset string, amount *big.Int) *types.CrossChainTx { - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId - cctx.GetCurrentOutTxParam().ReceiverChainId = senderChain.ChainId - cctx.CoinType = common.CoinType_ERC20 - cctx.RelayedMessage = "" - cctx.GetInboundTxParams().Asset = asset - cctx.GetInboundTxParams().Sender = sample.EthAddress().String() - cctx.GetCurrentOutTxParam().OutboundTxTssNonce = 42 - cctx.GetCurrentOutTxParam().OutboundTxGasUsed = 100 - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = 100 - return cctx -} diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index b65974d419..ed528a4268 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -24,7 +24,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo inboundAmount := cctx.GetInboundTxParams().Amount.BigInt() inboundSender := cctx.GetInboundTxParams().Sender inboundSenderChainID := cctx.GetInboundTxParams().SenderChainId - inboundCoinType := cctx.CoinType + inboundCoinType := cctx.InboundTxParams.CoinType if len(ctx.TxBytes()) > 0 { // add event for tendermint transaction hash format hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index 26bc2d1039..b3daede09a 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -34,7 +34,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, @@ -63,7 +63,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().CoinType = common.CoinType_Zeta cctx.GetInboundTxParams().SenderChainId = 0 reverted, err := k.HandleEVMDeposit( ctx, @@ -103,7 +103,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -147,7 +147,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -191,7 +191,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.InboundTxParams.CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -234,7 +234,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -277,7 +277,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -318,7 +318,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "" @@ -341,7 +341,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() cctx.GetInboundTxParams().Amount = math.NewUint(42) - cctx.CoinType = common.CoinType_Gas + cctx.GetInboundTxParams().CoinType = common.CoinType_Gas cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "not_hex" @@ -381,7 +381,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = receiver.Hex()[2:] + "DEADBEEF" @@ -423,7 +423,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = receiver.String() cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount) - cctx.CoinType = common.CoinType_ERC20 + cctx.GetInboundTxParams().CoinType = common.CoinType_ERC20 cctx.GetInboundTxParams().Sender = sample.EthAddress().String() cctx.GetInboundTxParams().SenderChainId = senderChain cctx.RelayedMessage = "DEADBEEF" diff --git a/x/crosschain/keeper/gas_payment.go b/x/crosschain/keeper/gas_payment.go index a7d99dea3d..a085e9cc7d 100644 --- a/x/crosschain/keeper/gas_payment.go +++ b/x/crosschain/keeper/gas_payment.go @@ -28,7 +28,7 @@ func (k Keeper) PayGasAndUpdateCctx( noEthereumTxEvent bool, ) error { // Dispatch to the correct function based on the coin type - switch cctx.CoinType { + switch cctx.InboundTxParams.CoinType { case common.CoinType_Zeta: return k.PayGasInZetaAndUpdateCctx(ctx, chainID, cctx, inputAmount, noEthereumTxEvent) case common.CoinType_Gas: @@ -37,7 +37,7 @@ func (k Keeper) PayGasAndUpdateCctx( return k.PayGasInERC20AndUpdateCctx(ctx, chainID, cctx, inputAmount, noEthereumTxEvent) default: // can't pay gas with coin type - return fmt.Errorf("can't pay gas with coin type %s", cctx.CoinType.String()) + return fmt.Errorf("can't pay gas with coin type %s", cctx.InboundTxParams.CoinType.String()) } } @@ -90,8 +90,8 @@ func (k Keeper) PayGasNativeAndUpdateCctx( inputAmount math.Uint, ) error { // preliminary checks - if cctx.CoinType != common.CoinType_Gas { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in native gas with %s", cctx.CoinType.String()) + if cctx.InboundTxParams.CoinType != common.CoinType_Gas { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in native gas with %s", cctx.InboundTxParams.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { return observertypes.ErrSupportedChains @@ -137,8 +137,8 @@ func (k Keeper) PayGasInERC20AndUpdateCctx( noEthereumTxEvent bool, ) error { // preliminary checks - if cctx.CoinType != common.CoinType_ERC20 { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in erc20 with %s", cctx.CoinType.String()) + if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in erc20 with %s", cctx.InboundTxParams.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { @@ -262,8 +262,8 @@ func (k Keeper) PayGasInZetaAndUpdateCctx( noEthereumTxEvent bool, ) error { // preliminary checks - if cctx.CoinType != common.CoinType_Zeta { - return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in zeta with %s", cctx.CoinType.String()) + if cctx.InboundTxParams.CoinType != common.CoinType_Zeta { + return cosmoserrors.Wrapf(types.ErrInvalidCoinType, "can't pay gas in zeta with %s", cctx.InboundTxParams.CoinType.String()) } if chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, chainID); chain == nil { diff --git a/x/crosschain/keeper/gas_payment_test.go b/x/crosschain/keeper/gas_payment_test.go index e51c75566c..3de3f08a50 100644 --- a/x/crosschain/keeper/gas_payment_test.go +++ b/x/crosschain/keeper/gas_payment_test.go @@ -46,10 +46,13 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Gas, + }, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, + CoinType: zetacommon.CoinType_Gas, }, { ReceiverChainId: chainID, @@ -70,7 +73,9 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Zeta, + }, } err := k.PayGasNativeAndUpdateCctx(ctx, chainID, &cctx, math.NewUint(inputAmount)) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -79,7 +84,9 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Gas, + }, } err := k.PayGasNativeAndUpdateCctx(ctx, 999999, &cctx, math.NewUint(inputAmount)) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -97,7 +104,9 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Gas, + }, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, @@ -132,10 +141,10 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { }) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sample.EthAddress().String(), + CoinType: zetacommon.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -195,9 +204,10 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ - Asset: assetAddress, + Asset: assetAddress, + CoinType: zetacommon.CoinType_ERC20, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -227,7 +237,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Zeta, + }, } err := k.PayGasInERC20AndUpdateCctx(ctx, chainID, &cctx, math.NewUint(inputAmount), false) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -236,7 +248,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_ERC20, + }, } err := k.PayGasInERC20AndUpdateCctx(ctx, 999999, &cctx, math.NewUint(inputAmount), false) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -254,7 +268,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_ERC20, + }, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: zetacommon.ZetaPrivnetChain().ChainId, @@ -293,9 +309,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - Asset: assetAddress, + Asset: assetAddress, + CoinType: zetacommon.CoinType_ERC20, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -345,9 +361,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - Asset: assetAddress, + Asset: assetAddress, + CoinType: zetacommon.CoinType_ERC20, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -403,9 +419,9 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_ERC20, InboundTxParams: &types.InboundTxParams{ - Asset: assetAddress, + Asset: assetAddress, + CoinType: zetacommon.CoinType_ERC20, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -448,7 +464,9 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Zeta, + }, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: chainID, @@ -472,7 +490,9 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // can call with undefined zeta fees cctx = types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Zeta, + }, OutboundTxParams: []*types.OutboundTxParams{ { ReceiverChainId: chainID, @@ -495,7 +515,9 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) chainID := getValidEthChainID(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Gas, + }, } err := k.PayGasInZetaAndUpdateCctx(ctx, chainID, &cctx, math.NewUint(100000), false) require.ErrorIs(t, err, types.ErrInvalidCoinType) @@ -504,7 +526,9 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { t.Run("should fail if chain is not supported", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ + CoinType: zetacommon.CoinType_Zeta, + }, } err := k.PayGasInZetaAndUpdateCctx(ctx, 999999, &cctx, math.NewUint(100000), false) require.ErrorIs(t, err, observertypes.ErrSupportedChains) @@ -524,10 +548,10 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sample.EthAddress().String(), + CoinType: zetacommon.CoinType_Zeta, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -558,10 +582,10 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { // create a cctx reverted from zeta cctx := types.CrossChainTx{ - CoinType: zetacommon.CoinType_Zeta, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sample.EthAddress().String(), + CoinType: zetacommon.CoinType_Zeta, }, OutboundTxParams: []*types.OutboundTxParams{ { diff --git a/x/crosschain/keeper/migrator.go b/x/crosschain/keeper/migrator.go index 51fe3a8f7d..4de64140c8 100644 --- a/x/crosschain/keeper/migrator.go +++ b/x/crosschain/keeper/migrator.go @@ -6,7 +6,6 @@ import ( v3 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v3" v4 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v4" v5 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v5" - v6 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v6" ) // Migrator is a struct for handling in-place store migrations. @@ -40,7 +39,3 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error { func (m Migrator) Migrate4to5(ctx sdk.Context) error { return v5.MigrateStore(ctx, m.crossChainKeeper, m.crossChainKeeper.zetaObserverKeeper) } - -func (m Migrator) Migrate5to6(ctx sdk.Context) error { - return v6.MigrateStore(ctx, m.crossChainKeeper) -} diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index afdb656331..3a76462b4f 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -78,9 +78,11 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() + + // TODO : Use the `CreateNewCctx` function to create the cctx + // https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: "", - CoinType: common.CoinType_Cmd, Index: index, ZetaFees: sdkmath.Uint{}, RelayedMessage: fmt.Sprintf("%s:%s", common.CmdMigrateTssFunds, "Funds Migrator Admin Cmd"), @@ -99,6 +101,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s InboundTxObservedExternalHeight: 0, InboundTxBallotIndex: "", InboundTxFinalizedZetaHeight: 0, + CoinType: common.CoinType_Cmd, }, OutboundTxParams: []*types.OutboundTxParams{{ Receiver: "", @@ -114,6 +117,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s OutboundTxEffectiveGasPrice: sdkmath.Int{}, OutboundTxEffectiveGasLimit: 0, TssPubkey: currentTss.TssPubkey, + CoinType: common.CoinType_Cmd, }}} // Set the sender and receiver addresses for EVM chain if common.IsEVMChain(chainID) { diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx.go b/x/crosschain/keeper/msg_server_refund_aborted_tx.go index c79c6d81ff..fc651ec249 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx.go @@ -43,7 +43,7 @@ func (k msgServer) RefundAbortedCCTX(goCtx context.Context, msg *types.MsgRefund } // Check if aborted amount is available to maintain zeta accounting - if cctx.CoinType == common.CoinType_Zeta { + if cctx.InboundTxParams.CoinType == common.CoinType_Zeta { err := k.RemoveZetaAbortedAmount(ctx, GetAbortedAmount(cctx)) // if the zeta accounting is not found, it means the zeta accounting is not set yet and the refund should not be processed if errors.Is(err, types.ErrUnableToFindZetaAccounting) { diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index 3331bc1e6d..1c6f7da680 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -55,7 +55,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -94,7 +94,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -133,7 +133,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta cctx.OutboundTxParams = nil k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.GetCurrentOutTxParam().Amount}) @@ -173,7 +173,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -212,7 +212,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.Status = crosschaintypes.CctxStatus_Aborted cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_ERC20 + cctx.InboundTxParams.CoinType = common.CoinType_ERC20 cctx.InboundTxParams.Asset = asset k.SetCrossChainTx(ctx, *cctx) // deploy zrc20 @@ -262,7 +262,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -301,7 +301,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -332,7 +332,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) k.SetZetaAccounting(ctx, crosschaintypes.ZetaAccounting{AbortedZetaAmount: cctx.InboundTxParams.Amount}) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -363,7 +363,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -396,7 +396,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _, err := msgServer.RefundAbortedCCTX(ctx, &crosschaintypes.MsgRefundAbortedCCTX{ @@ -425,7 +425,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") @@ -456,7 +456,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Zeta + cctx.InboundTxParams.CoinType = common.CoinType_Zeta k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -486,7 +486,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { cctx.CctxStatus.IsAbortRefunded = false cctx.InboundTxParams.TxOrigin = cctx.InboundTxParams.Sender cctx.InboundTxParams.SenderChainId = chainID - cctx.CoinType = common.CoinType_Gas + cctx.InboundTxParams.CoinType = common.CoinType_Gas k.SetCrossChainTx(ctx, *cctx) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, cctx.InboundTxParams.SenderChainId, "foobar", "foobar") diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index b59b538517..6a78d66844 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -5,7 +5,9 @@ import ( "fmt" cosmoserrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -95,6 +97,201 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg return nil, err } k.ProcessInbound(ctx, &inboundCctx) - k.SaveInbound(ctx, &inboundCctx) + k.SaveInbound(ctx, &inboundCctx, msg.EventIndex) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } + +// GetInbound returns a new CCTX from a given inbound message. +func (k Keeper) GetInbound(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx) types.CrossChainTx { + + // get the latest TSS to set the TSS public key in the CCTX + tssPub := "" + tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) + if tssFound { + tssPub = tss.TssPubkey + } + return CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) +} + +// CreateNewCCTX creates a new CCTX with the given parameters. +func CreateNewCCTX( + ctx sdk.Context, + msg *types.MsgVoteOnObservedInboundTx, + index string, + tssPubkey string, + s types.CctxStatus, + senderChainID, + receiverChainID int64, +) types.CrossChainTx { + if msg.TxOrigin == "" { + msg.TxOrigin = msg.Sender + } + inboundParams := &types.InboundTxParams{ + Sender: msg.Sender, + SenderChainId: senderChainID, + TxOrigin: msg.TxOrigin, + Asset: msg.Asset, + Amount: msg.Amount, + InboundTxObservedHash: msg.InTxHash, + InboundTxObservedExternalHeight: msg.InBlockHeight, + InboundTxFinalizedZetaHeight: 0, + InboundTxBallotIndex: index, + CoinType: msg.CoinType, + } + + outBoundParams := &types.OutboundTxParams{ + Receiver: msg.Receiver, + ReceiverChainId: receiverChainID, + OutboundTxHash: "", + OutboundTxTssNonce: 0, + OutboundTxGasLimit: msg.GasLimit, + OutboundTxGasPrice: "", + OutboundTxBallotIndex: "", + OutboundTxObservedExternalHeight: 0, + Amount: sdkmath.ZeroUint(), + TssPubkey: tssPubkey, + CoinType: msg.CoinType, + } + status := &types.Status{ + Status: s, + StatusMessage: "", + LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), + IsAbortRefunded: false, + } + newCctx := types.CrossChainTx{ + Creator: msg.Creator, + Index: index, + ZetaFees: sdkmath.ZeroUint(), + RelayedMessage: msg.Message, + CctxStatus: status, + InboundTxParams: inboundParams, + OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, + } + return newCctx +} + +// ProcessInbound processes the inbound CCTX. +// It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. +func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { + if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { + k.ProcessZEVMDeposit(ctx, cctx) + } else { + k.ProcessCrosschainMsgPassing(ctx, cctx) + } +} + +// ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain. +// If the deposit is successful, the CCTX status is changed to OutboundMined. +// If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. +// If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. +// If the creation of revert tx also fails it changes the status to Aborted. +// Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. +// We do not return an error from this function , as all changes need to be persisted to the state. +// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. +func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) + + if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + return + } else if err != nil && isContractReverted { // contract call reverted; should refund + revertMessage := err.Error() + senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) + if senderChain == nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") + return + } + + gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + if err != nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("can't get revert tx gas limit,%s", err.Error())) + return + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit + } + + // create new OutboundTxParams for the revert + revertTxParams := &types.OutboundTxParams{ + Receiver: cctx.InboundTxParams.Sender, + ReceiverChainId: cctx.InboundTxParams.SenderChainId, + Amount: cctx.InboundTxParams.Amount, + OutboundTxGasLimit: gasLimit, + } + cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) + + // we create a new cached context, and we don't commit the previous one with EVM deposit + tmpCtxRevert, commitRevert := ctx.CacheContext() + err = func() error { + err := k.PayGasAndUpdateCctx( + tmpCtxRevert, + senderChain.ChainId, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + // Update nonce using senderchain id as this is a revert tx and would go back to the original sender + return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) + }() + if err != nil { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) + return + } + commitRevert() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) + return + } + // successful HandleEVMDeposit; + commit() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "Remote omnichain contract call completed") + return +} + +// ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain. +// If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. +// If the crosschain message passing returns an error, the CCTX status is changed to Aborted. +// We do not return an error from this function , as all changes need to be persisted to the state. +// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. +func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId + err := func() error { + err := k.PayGasAndUpdateCctx( + tmpCtx, + outboundReceiverChainID, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + return k.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx) + }() + if err != nil { + // do not commit anything here as the CCTX should be aborted + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + return + } + commit() + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingOutbound, "") + return +} + +func (k Keeper) SaveInbound(ctx sdk.Context, cctx *types.CrossChainTx, eventIndex uint64) { + EmitEventInboundFinalized(ctx, cctx) + k.AddFinalizedInbound(ctx, + cctx.GetInboundTxParams().InboundTxObservedHash, + cctx.GetInboundTxParams().SenderChainId, + eventIndex) + // #nosec G701 always positive + cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) + cctx.InboundTxParams.TxFinalizationStatus = types.TxFinalizationStatus_Executed + k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) + k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) +} diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 803de84576..3b27ebb1a0 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -2,16 +2,21 @@ package keeper_test import ( "encoding/hex" + "fmt" + "math/big" "testing" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -199,3 +204,437 @@ func TestStatus_ChangeStatus(t *testing.T) { }) } } + +func TestKeeper_ProcessZEVMDeposit(t *testing.T) { + t.Run("process zevm deposit successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + // expect DepositCoinZeta to be called + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(nil) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit returns err without reverting", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + // mock unsuccessful HandleEVMDeposit which does not revert + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(fmt.Errorf("deposit error"), false) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at GetSupportedChainFromChainID", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // mock unsuccessful GetSupportedChainFromChainID + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "invalid sender chain", cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock unsuccessful GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{}, false) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("can't get revert tx gas limit,%s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock unsuccessful PayGasInERC20AndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at UpdateNonce", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // Mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) + require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + }) +} + +func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { + t.Run("process crosschain msg passing successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + }) + + t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock unsuccessful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). + Return(nil).Once() + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + }) +} + +func TestKeeper_GetInbound(t *testing.T) { + t.Run("should return a cctx with correct values", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + senderChain := getValidEthChain(t) + sender := sample.EthAddress() + receiverChain := getValidEthChain(t) + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + intxBlockHeight := uint64(420) + intxHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := common.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteOnObservedInboundTx{ + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InTxHash: intxHash.String(), + InBlockHeight: intxBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + zk.ObserverKeeper.SetTSS(ctx, tss) + cctx := k.GetInbound(ctx, &msg) + require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) + require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) + require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) + require.Equal(t, amount, cctx.GetInboundTxParams().Amount) + require.Equal(t, message, cctx.RelayedMessage) + require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) + require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) + require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) + require.Equal(t, asset, cctx.GetInboundTxParams().Asset) + require.Equal(t, cointType, cctx.InboundTxParams.CoinType) + require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) + require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) + require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + }) +} + +func TestKeeper_SaveInbound(t *testing.T) { + t.Run("should save the cctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + eventIndex := sample.Uint64InRange(1, 100) + k.SaveInbound(ctx, cctx, eventIndex) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) + require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, eventIndex)) + _, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + }) + + t.Run("should save the cctx and remove tracker", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + hash := sample.Hash() + cctx.InboundTxParams.InboundTxObservedHash = hash.String() + k.SetInTxTracker(ctx, types.InTxTracker{ + ChainId: senderChain.ChainId, + TxHash: hash.String(), + CoinType: 0, + }) + eventIndex := sample.Uint64InRange(1, 100) + + k.SaveInbound(ctx, cctx, eventIndex) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.InboundTxParams.TxFinalizationStatus) + require.True(t, k.IsFinalizedInbound(ctx, cctx.GetInboundTxParams().InboundTxObservedHash, cctx.GetInboundTxParams().SenderChainId, eventIndex)) + _, found := k.GetCrossChainTx(ctx, cctx.Index) + require.True(t, found) + _, found = k.GetInTxTracker(ctx, senderChain.ChainId, hash.String()) + require.False(t, found) + }) +} + +// GetERC20Cctx returns a sample CrossChainTx with ERC20 params. This is used for testing Inbound and Outbound voting transactions +func GetERC20Cctx(t *testing.T, receiver ethcommon.Address, senderChain common.Chain, asset string, amount *big.Int) *types.CrossChainTx { + r := sample.Rand() + cctx := &types.CrossChainTx{ + Creator: sample.AccAddress(), + Index: sample.ZetaIndex(t), + ZetaFees: sample.UintInRange(0, 100), + RelayedMessage: "", + CctxStatus: &types.Status{Status: types.CctxStatus_PendingInbound}, + InboundTxParams: sample.InboundTxParams(r), + OutboundTxParams: []*types.OutboundTxParams{sample.OutboundTxParams(r)}, + } + + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.GetInboundTxParams().SenderChainId = senderChain.ChainId + cctx.GetInboundTxParams().InboundTxObservedHash = sample.Hash().String() + cctx.GetInboundTxParams().InboundTxBallotIndex = sample.ZetaIndex(t) + + cctx.GetCurrentOutTxParam().ReceiverChainId = senderChain.ChainId + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetCurrentOutTxParam().OutboundTxHash = sample.Hash().String() + cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = sample.ZetaIndex(t) + + cctx.InboundTxParams.CoinType = common.CoinType_ERC20 + for _, outboundTxParam := range cctx.OutboundTxParams { + outboundTxParam.CoinType = common.CoinType_ERC20 + } + + cctx.GetInboundTxParams().Asset = asset + cctx.GetInboundTxParams().Sender = sample.EthAddress().String() + cctx.GetCurrentOutTxParam().OutboundTxTssNonce = 42 + cctx.GetCurrentOutTxParam().OutboundTxGasUsed = 100 + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = 100 + return cctx +} diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 1602d86b25..09c2cd2cfc 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -2,10 +2,17 @@ package keeper import ( "context" + "fmt" + "math/big" + cosmoserrors "cosmossdk.io/errors" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) // VoteOnObservedOutboundTx casts a vote on an outbound transaction observed on a connected chain (after @@ -98,3 +105,238 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms k.SaveSuccessfulOutBound(ctx, &cctx, ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } + +// SetRevertOutboundValues does the following things in one function: +// 1. create a new OutboundTxParams for the revert +// 2. append the new OutboundTxParams to the current OutboundTxParams +// 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. +func SetRevertOutboundValues(cctx *types.CrossChainTx, gasLimit uint64) { + revertTxParams := &types.OutboundTxParams{ + Receiver: cctx.InboundTxParams.Sender, + ReceiverChainId: cctx.InboundTxParams.SenderChainId, + Amount: cctx.InboundTxParams.Amount, + OutboundTxGasLimit: gasLimit, + TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, + } + // The original outbound has been finalized, the new outbound is pending + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) +} + +// SetOutboundValues sets the required values for the outbound transaction +// Note: It expects the cctx to already have been created, +// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer +func SetOutboundValues(ctx sdk.Context, cctx *types.CrossChainTx, msg types.MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { + if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { + if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { + ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", + msg.ValueReceived, + cctx.GetCurrentOutTxParam().Amount)) + return cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, cctx.GetCurrentOutTxParam().Amount)) + } + } + // Update CCTX values + cctx.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash + cctx.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice + cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit + cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight + cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() + + return nil +} + +// FundStabilityPool funds the stability pool with the remaining fees of an outbound tx +// The funds are sent to the gas stability pool associated with the receiver chain +func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) { + // Fund the gas stability pool with the remaining funds + if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutTxParam(), cctx.GetCurrentOutTxParam().ReceiverChainId); err != nil { + ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: CCTX: %s Can't fund the gas stability pool with remaining fees %s", cctx.Index, err.Error())) + } +} + +// FundGasStabilityPoolFromRemainingFees funds the gas stability pool with the remaining fees of an outbound tx +func (k Keeper) FundGasStabilityPoolFromRemainingFees(ctx sdk.Context, outboundTxParams types.OutboundTxParams, chainID int64) error { + gasUsed := outboundTxParams.OutboundTxGasUsed + gasLimit := outboundTxParams.OutboundTxEffectiveGasLimit + gasPrice := math.NewUintFromBigInt(outboundTxParams.OutboundTxEffectiveGasPrice.BigInt()) + + if gasLimit == gasUsed { + return nil + } + + // We skip gas stability pool funding if one of the params is zero + if gasLimit > 0 && gasUsed > 0 && !gasPrice.IsZero() { + if gasLimit > gasUsed { + remainingGas := gasLimit - gasUsed + remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt() + + // We fund the stability pool with a portion of the remaining fees + remainingFees = percentOf(remainingFees, RemainingFeesToStabilityPoolPercent) + // Fund the gas stability pool + if err := k.fungibleKeeper.FundGasStabilityPool(ctx, chainID, remainingFees); err != nil { + return err + } + } else { + return fmt.Errorf("VoteOnObservedOutboundTx: The gas limit %d is less than the gas used %d", gasLimit, gasUsed) + } + } + return nil +} + +// percentOf returns the percentage of a number +func percentOf(n *big.Int, percent int64) *big.Int { + n = n.Mul(n, big.NewInt(percent)) + n = n.Div(n, big.NewInt(100)) + return n +} + +// ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: +// 1. Change the status of the CCTX from PendingRevert to Reverted or from PendingOutbound to OutboundMined +// 2. Set the finalization status of the current outbound tx to executed +// 3. Emit an event for the successful outbound transaction +func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { + oldStatus := cctx.CctxStatus.Status + switch oldStatus { + case types.CctxStatus_PendingRevert: + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") + case types.CctxStatus_PendingOutbound: + cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "") + default: + return + } + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) +} + +// ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: +// 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX +// 2. For other CCTX, it creates a revert tx if the outbound tx is pending. If the status is pending revert, it aborts the CCTX +// 3. Emit an event for the failed outbound transaction +// 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction +func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { + oldStatus := cctx.CctxStatus.Status + if cctx.InboundTxParams.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { + // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") + } else { + switch oldStatus { + case types.CctxStatus_PendingOutbound: + + gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + if err != nil { + return cosmoserrors.Wrap(err, "GetRevertGasLimit") + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit + } + + // create new OutboundTxParams for the revert + SetRevertOutboundValues(cctx, gasLimit) + + err = k.PayGasAndUpdateCctx( + ctx, + cctx.InboundTxParams.SenderChainId, + cctx, + cctx.OutboundTxParams[0].Amount, + false, + ) + if err != nil { + return err + } + err = k.UpdateNonce(ctx, cctx.InboundTxParams.SenderChainId, cctx) + if err != nil { + return err + } + // Not setting the finalization status here, the required changes have been mad while creating the revert tx + cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") + case types.CctxStatus_PendingRevert: + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") + } + } + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) + return nil +} + +// ProcessOutbound processes the finalization of an outbound transaction based on the ballot status +// The state is committed only if the individual steps are successful +func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotStatus observertypes.BallotStatus, valueReceived string) error { + tmpCtx, commit := ctx.CacheContext() + err := func() error { + switch ballotStatus { + case observertypes.BallotStatus_BallotFinalized_SuccessObservation: + k.ProcessSuccessfulOutbound(tmpCtx, cctx, valueReceived) + case observertypes.BallotStatus_BallotFinalized_FailureObservation: + err := k.ProcessFailedOutbound(tmpCtx, cctx, valueReceived) + if err != nil { + return err + } + } + return nil + }() + if err != nil { + return err + } + commit() + return nil +} + +// SaveFailedOutBound saves a failed outbound transaction. +// It does the following things in one function: +// 1. Change the status of the CCTX to Aborted +// 2. Save the outbound +func (k Keeper) SaveFailedOutBound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) + ctx.Logger().Error(errMessage) + + k.SaveOutbound(ctx, cctx, ballotIndex) +} + +// SaveSuccessfulOutBound saves a successful outbound transaction. +func (k Keeper) SaveSuccessfulOutBound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { + k.SaveOutbound(ctx, cctx, ballotIndex) +} + +// SaveOutbound saves the outbound transaction.It does the following things in one function: +// 1. Set the ballot index for the outbound vote to the cctx +// 2. Remove the nonce from the pending nonces +// 3. Remove the outbound tx tracker +// 4. Set the cctx and nonce to cctx and inTxHash to cctx +func (k Keeper) SaveOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { + receiverChain := cctx.GetCurrentOutTxParam().ReceiverChainId + tssPubkey := cctx.GetCurrentOutTxParam().TssPubkey + outTxTssNonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce + + cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex + // #nosec G701 always in range + k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tssPubkey, receiverChain, int64(outTxTssNonce)) + k.RemoveOutTxTracker(ctx, receiverChain, outTxTssNonce) + ctx.Logger().Info(fmt.Sprintf("Remove tracker %s: , Block Height : %d ", getOutTrackerIndex(receiverChain, outTxTssNonce), ctx.BlockHeight())) + // This should set nonce to cctx only if a new revert is created. + k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *cctx) +} + +func (k Keeper) ValidateOutboundMessage(ctx sdk.Context, msg types.MsgVoteOnObservedOutboundTx) (types.CrossChainTx, error) { + // check if CCTX exists and if the nonce matches + cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash) + if !found { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) + } + if cctx.GetCurrentOutTxParam().OutboundTxTssNonce != msg.OutTxTssNonce { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + } + // do not process an outbound vote if TSS is not found + _, found = k.zetaObserverKeeper.GetTSS(ctx) + if !found { + return types.CrossChainTx{}, types.ErrCannotFindTSSKeys + } + if cctx.GetCurrentOutTxParam().ReceiverChainId != msg.OutTxChain { + return types.CrossChainTx{}, cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", msg.OutTxChain, cctx.GetCurrentOutTxParam().ReceiverChainId)) + } + return cctx, nil +} diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 1875389328..1b35b832a6 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -2,11 +2,13 @@ package keeper_test import ( "errors" + "fmt" "math/big" "math/rand" "testing" "cosmossdk.io/math" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" @@ -159,7 +161,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, }) require.NoError(t, err) c, found := k.GetCrossChainTx(ctx, cctx.Index) @@ -215,7 +217,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, }) require.NoError(t, err) c, found := k.GetCrossChainTx(ctx, cctx.Index) @@ -275,7 +277,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, }) require.NoError(t, err) c, found := k.GetCrossChainTx(ctx, cctx.Index) @@ -337,7 +339,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, }) require.NoError(t, err) c, found := k.GetCrossChainTx(ctx, cctx.Index) @@ -381,7 +383,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, } _, err = msgServer.VoteOnObservedOutboundTx(ctx, msg) require.NoError(t, err) @@ -427,7 +429,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { ObservedOutTxBlockHeight: 10, ObservedOutTxEffectiveGasPrice: math.NewInt(21), ObservedOutTxGasUsed: 21, - CoinType: cctx.CoinType, + CoinType: cctx.InboundTxParams.CoinType, } _, err = msgServer.VoteOnObservedOutboundTx(ctx, msg) require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) @@ -438,3 +440,470 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { require.False(t, found) }) } + +func TestKeeper_GetOutbound(t *testing.T) { + t.Run("successfully get outbound tx", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: math.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, math.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("successfully get outbound tx for failed ballot without amount check", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: math.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_FailureObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, math.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("failed to get outbound tx if amount does not match value received", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: math.NewUint(100), + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: math.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + }) +} + +func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + // transition to reverted if pending revert + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Reverted) + // transition to outbound mined if pending outbound + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + // do nothing if it's in any other state + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) +} + +func TestKeeper_ProcessFailedOutbound(t *testing.T) { + t.Run("successfully process failed outbound set to aborted for type cmd", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.CoinType = common.CoinType_Cmd + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to aborted for withdraw tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.SenderChainId = common.ZetaChainMainnet().ChainId + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to pending revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) + + }) + + t.Run("unable to process revert when update nonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock failed UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrCannotFindReceiverNonce) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, observertypes.ErrSupportedChains) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when GetRevertGasLimit fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) +} + +func TestKeeper_ProcessOutbound(t *testing.T) { + t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + }) + + t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.InboundTxParams.CoinType = common.CoinType_Cmd + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("do not process outbound on error, no new outbound created", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + // New outbound not added and the old outbound is not finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + }) + + t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + // New outbound added for revert and the old outbound is finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen+1) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + require.Equal(t, cctx.OutboundTxParams[oldOutTxParamsLen-1].TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) +} + +func TestKeeper_SaveFailedOutBound(t *testing.T) { + t.Run("successfully save failed outbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SaveFailedOutBound(ctx, cctx, sample.String(), sample.ZetaIndex(t)) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + }) +} + +func TestKeeper_SaveSuccessfulOutBound(t *testing.T) { + t.Run("successfully save successful outbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.SaveSuccessfulOutBound(ctx, cctx, sample.String()) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, sample.String()) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + }) +} + +func TestKeeper_SaveOutbound(t *testing.T) { + t.Run("successfully save outbound", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // setup state for crosschain and observer modules + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + ballotIndex := sample.String() + k.SetOutTxTracker(ctx, types.OutTxTracker{ + Index: "", + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Nonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + HashList: nil, + }) + + zk.ObserverKeeper.SetPendingNonces(ctx, observertypes.PendingNonces{ + NonceLow: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - 1, + NonceHigh: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + 1, + ChainId: cctx.GetCurrentOutTxParam().ReceiverChainId, + Tss: cctx.GetCurrentOutTxParam().TssPubkey, + }) + zk.ObserverKeeper.SetTSS(ctx, observertypes.TSS{ + TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, + }) + + // Save outbound and assert all values are successfully saved + k.SaveOutbound(ctx, cctx, ballotIndex) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, ballotIndex) + _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.False(t, found) + pn, found := zk.ObserverKeeper.GetPendingNonces(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.True(t, found) + require.Equal(t, pn.NonceLow, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) + require.Equal(t, pn.NonceHigh, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)+1) + _, found = k.GetInTxHashToCctx(ctx, cctx.InboundTxParams.InboundTxObservedHash) + require.True(t, found) + _, found = zk.ObserverKeeper.GetNonceToCctx(ctx, cctx.GetCurrentOutTxParam().TssPubkey, cctx.GetCurrentOutTxParam().ReceiverChainId, int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + require.True(t, found) + }) +} + +func Test_SetRevertOutboundValues(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.OutboundTxParams = cctx.OutboundTxParams[:1] + keeper.SetRevertOutboundValues(cctx, 100) + require.Len(t, cctx.OutboundTxParams, 2) + require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) + require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) +} + +func TestKeeper_ValidateOutboundMessage(t *testing.T) { + t.Run("successfully validate outbound message", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: cctx.GetCurrentOutTxParam().ReceiverChainId, + }) + require.NoError(t, err) + }) + + t.Run("failed to validate outbound message if cctx not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + msg := types.MsgVoteOnObservedOutboundTx{ + CctxHash: sample.String(), + OutTxTssNonce: 1, + } + _, err := k.ValidateOutboundMessage(ctx, msg) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) + }) + + t.Run("failed to validate outbound message if nonce does not match", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + msg := types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: 2, + } + _, err := k.ValidateOutboundMessage(ctx, msg) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) + }) + + t.Run("failed to validate outbound message if tss not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + }) + require.ErrorIs(t, err, types.ErrCannotFindTSSKeys) + }) + + t.Run("failed to validate outbound message if chain does not match", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + _, err := k.ValidateOutboundMessage(ctx, types.MsgVoteOnObservedOutboundTx{ + CctxHash: cctx.Index, + OutTxTssNonce: cctx.GetCurrentOutTxParam().OutboundTxTssNonce, + OutTxChain: 2, + }) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + require.ErrorContains(t, err, fmt.Sprintf("OutTxChain %d does not match CCTX OutTxChain %d", 2, cctx.GetCurrentOutTxParam().ReceiverChainId)) + }) +} diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index e690da980b..efd79e7f28 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -111,9 +111,10 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist index := hash.Hex() // create a cmd cctx to whitelist the erc20 on the external chain + // TODO : refactor this to use the `CreateNewCCTX` function instead. + //https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: msg.Creator, - CoinType: common.CoinType_Cmd, Index: index, ZetaFees: sdk.NewUint(0), RelayedMessage: fmt.Sprintf("%s:%s", common.CmdWhitelistERC20, msg.Erc20Address), @@ -123,16 +124,16 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist LastUpdateTimestamp: 0, }, InboundTxParams: &types.InboundTxParams{ - Sender: "", - SenderChainId: 0, - TxOrigin: "", - + Sender: "", + SenderChainId: 0, + TxOrigin: "", Asset: "", Amount: math.Uint{}, InboundTxObservedHash: hash.String(), // all Upper case Cosmos TX HEX, with no 0x prefix InboundTxObservedExternalHeight: 0, InboundTxBallotIndex: "", InboundTxFinalizedZetaHeight: 0, + CoinType: common.CoinType_Cmd, }, OutboundTxParams: []*types.OutboundTxParams{ { @@ -146,6 +147,7 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist OutboundTxBallotIndex: "", OutboundTxObservedExternalHeight: 0, TssPubkey: tss.TssPubkey, + CoinType: common.CoinType_Cmd, }, }, } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index b29de2097e..9d10b7ce13 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -12,7 +12,7 @@ import ( ) func (k Keeper) RefundAbortedAmountOnZetaChain(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { - coinType := cctx.CoinType + coinType := cctx.InboundTxParams.CoinType switch coinType { case common.CoinType_Gas: return k.RefundAmountOnZetaChainGas(ctx, cctx, refundAddress) @@ -75,7 +75,7 @@ func (k Keeper) RefundAmountOnZetaChainZeta(ctx sdk.Context, cctx types.CrossCha func (k Keeper) RefundAmountOnZetaChainERC20(ctx sdk.Context, cctx types.CrossChainTx, refundAddress ethcommon.Address) error { refundAmount := GetAbortedAmount(cctx) // preliminary checks - if cctx.CoinType != common.CoinType_ERC20 { + if cctx.InboundTxParams.CoinType != common.CoinType_ERC20 { return errors.New("unsupported coin type for refund on ZetaChain") } if !common.IsEVMChain(cctx.InboundTxParams.SenderChainId) { diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index 55cb674574..bf18530fc0 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -25,12 +25,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.NewUint(20), + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.NewUint(42), @@ -52,12 +52,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.NewUint(20), + CoinType: common.CoinType_Gas, }, }, sender, @@ -74,12 +74,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { chainID := getValidEthChainID(t) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.NewUint(20), + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.NewUint(42), @@ -99,12 +99,12 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.ZeroUint(), @@ -125,12 +125,12 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.NewUint(20), + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.NewUint(42), @@ -150,12 +150,12 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.NewUint(20), + CoinType: common.CoinType_Gas, }, }, sender, @@ -171,12 +171,13 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { chainID := getValidEthChainID(t) err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), TxOrigin: sender.String(), Amount: math.ZeroUint(), + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.ZeroUint(), @@ -210,12 +211,13 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { ) err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), Asset: asset, Amount: math.NewUint(42), + CoinType: common.CoinType_ERC20, }, OutboundTxParams: []*types.OutboundTxParams{{ Amount: math.NewUint(42), @@ -232,12 +234,13 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { // can refund again err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Sender: sender.String(), Asset: asset, Amount: math.NewUint(42), + CoinType: common.CoinType_ERC20, }}, sender, ) @@ -251,47 +254,55 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Zeta, + InboundTxParams: &types.InboundTxParams{ - Amount: math.NewUint(42), + Amount: math.NewUint(42), + CoinType: common.CoinType_Zeta, }}, + sample.EthAddress(), ) require.ErrorContains(t, err, "unsupported coin type") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_Gas}, + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + }, + }, sample.EthAddress(), ) require.ErrorContains(t, err, "unsupported coin type") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: 999999, Amount: math.NewUint(42), + CoinType: common.CoinType_ERC20, }}, sample.EthAddress(), ) require.ErrorContains(t, err, "only EVM chains are supported") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Amount: math.Uint{}, + CoinType: common.CoinType_ERC20, }}, sample.EthAddress(), ) require.ErrorContains(t, err, "no amount to refund") err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Amount: math.ZeroUint(), + CoinType: common.CoinType_ERC20, }}, sample.EthAddress(), ) @@ -299,12 +310,13 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { // the foreign coin has not been set err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - CoinType: common.CoinType_ERC20, + InboundTxParams: &types.InboundTxParams{ SenderChainId: getValidEthChainID(t), Sender: sample.EthAddress().String(), Asset: sample.EthAddress().String(), Amount: math.NewUint(42), + CoinType: common.CoinType_ERC20, }}, sample.EthAddress(), ) diff --git a/x/crosschain/migrations/v4/migrate.go b/x/crosschain/migrations/v4/migrate.go index 5a421c9d55..6b9ee6ffb8 100644 --- a/x/crosschain/migrations/v4/migrate.go +++ b/x/crosschain/migrations/v4/migrate.go @@ -54,7 +54,7 @@ func SetZetaAccounting( for ; iterator.Valid(); iterator.Next() { var val types.CrossChainTx cdc.MustUnmarshal(iterator.Value(), &val) - if val.CctxStatus.Status == types.CctxStatus_Aborted && val.CoinType == common.CoinType_Zeta { + if val.CctxStatus.Status == types.CctxStatus_Aborted && val.InboundTxParams.CoinType == common.CoinType_Zeta { abortedAmountZeta = abortedAmountZeta.Add(val.GetCurrentOutTxParam().Amount) } } diff --git a/x/crosschain/migrations/v4/migrate_test.go b/x/crosschain/migrations/v4/migrate_test.go index 67113b9c0a..b2d88a1add 100644 --- a/x/crosschain/migrations/v4/migrate_test.go +++ b/x/crosschain/migrations/v4/migrate_test.go @@ -167,10 +167,13 @@ func SetRandomCctx(ctx sdk.Context, k keeper.Keeper) sdkmath.Uint { amount := sdkmath.NewUint(uint64(r.Uint32())) k.SetCrossChainTx(ctx, types.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_Zeta, CctxStatus: &types.Status{Status: types.CctxStatus_Aborted}, + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + }, OutboundTxParams: []*types.OutboundTxParams{{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_Zeta, }}, }) totalZeta = totalZeta.Add(amount) diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index cc29a265e6..27ceba92cc 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -93,7 +93,7 @@ func SetZetaAccounting( for _, cctx := range ccctxList { if cctx.CctxStatus.Status == types.CctxStatus_Aborted { - switch cctx.CoinType { + switch cctx.InboundTxParams.CoinType { case common.CoinType_ERC20: { receiverChain := observerKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) diff --git a/x/crosschain/migrations/v5/migrate_test.go b/x/crosschain/migrations/v5/migrate_test.go index 884777d626..4c3e3a735e 100644 --- a/x/crosschain/migrations/v5/migrate_test.go +++ b/x/crosschain/migrations/v5/migrate_test.go @@ -24,7 +24,7 @@ func TestMigrateStore(t *testing.T) { v4ZetaAccountingAmount := math.ZeroUint() for _, cctx := range cctxList { k.SetCrossChainTx(ctx, cctx) - if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.CoinType != common.CoinType_Zeta { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_Aborted || cctx.InboundTxParams.CoinType != common.CoinType_Zeta { continue } v5ZetaAccountingAmount = v5ZetaAccountingAmount.Add(crosschainkeeper.GetAbortedAmount(cctx)) @@ -44,7 +44,7 @@ func TestMigrateStore(t *testing.T) { cctxListUpdated := k.GetAllCrossChainTx(ctx) // Check refund status of the cctx for _, cctx := range cctxListUpdated { - switch cctx.CoinType { + switch cctx.InboundTxParams.CoinType { case common.CoinType_ERC20: receiverChain := zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId) require.NotNil(t, receiverChain) @@ -180,37 +180,40 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_Zeta, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount.Add(math.NewUint(uint64(r.Uint32()))), + Amount: amount.Add(math.NewUint(uint64(r.Uint32()))), + CoinType: common.CoinType_Zeta, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_Zeta, }}, } for ; i < count; i++ { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_Zeta, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_Zeta, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ - Amount: math.ZeroUint(), + Amount: math.ZeroUint(), + CoinType: common.CoinType_Zeta, }}, } } for ; i < count+20; i++ { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ - Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_ERC20, + Index: fmt.Sprintf("%d", i), + CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_ERC20, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ Amount: math.ZeroUint(), @@ -222,10 +225,10 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_ERC20, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_ERC20, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ Amount: math.ZeroUint(), @@ -237,10 +240,10 @@ func CrossChainTxList(count int) []crosschaintypes.CrossChainTx { amount := math.NewUint(uint64(r.Uint32())) cctxList[i] = crosschaintypes.CrossChainTx{ Index: fmt.Sprintf("%d", i), - CoinType: common.CoinType_Gas, CctxStatus: &crosschaintypes.Status{Status: crosschaintypes.CctxStatus_Aborted}, InboundTxParams: &crosschaintypes.InboundTxParams{ - Amount: amount, + Amount: amount, + CoinType: common.CoinType_Gas, }, OutboundTxParams: []*crosschaintypes.OutboundTxParams{{ Amount: amount, diff --git a/x/crosschain/migrations/v6/migrate.go b/x/crosschain/migrations/v6/migrate.go deleted file mode 100644 index fb00ff2574..0000000000 --- a/x/crosschain/migrations/v6/migrate.go +++ /dev/null @@ -1,93 +0,0 @@ -package v6 - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" - storetypes "github.com/cosmos/cosmos-sdk/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/x/crosschain/types" -) - -// crosschainKeeper is an interface to prevent cyclic dependency -type crosschainKeeper interface { - GetStoreKey() storetypes.StoreKey - GetCodec() codec.Codec - GetAllCrossChainTx(ctx sdk.Context) []types.CrossChainTx - - SetCrossChainTx(ctx sdk.Context, cctx types.CrossChainTx) - AddFinalizedInbound(ctx sdk.Context, inboundTxHash string, senderChainID int64, height uint64) - - SetZetaAccounting(ctx sdk.Context, accounting types.ZetaAccounting) -} - -// MigrateStore migrates the x/crosschain module state from the consensus version 4 to 5 -// It resets the aborted zeta amount to use the inbound tx amount instead in situations where the outbound cctx is never created. -func MigrateStore(ctx sdk.Context, crosschainKeeper crosschainKeeper) error { - tmpctx, commit := ctx.CacheContext() - cctxListV14 := GetV14CCTX(tmpctx, crosschainKeeper) - for _, cctx := range cctxListV14 { - OutBoundParamsV15 := make([]*types.OutboundTxParams, len(cctx.OutboundTxParams)) - for j, outBoundParams := range cctx.OutboundTxParams { - OutBoundParamsV15[j] = &types.OutboundTxParams{ - Receiver: outBoundParams.Receiver, - ReceiverChainId: outBoundParams.ReceiverChainId, - Amount: outBoundParams.Amount, - OutboundTxTssNonce: outBoundParams.OutboundTxTssNonce, - OutboundTxGasLimit: outBoundParams.OutboundTxGasLimit, - OutboundTxGasPrice: outBoundParams.OutboundTxGasPrice, - OutboundTxHash: outBoundParams.OutboundTxHash, - OutboundTxBallotIndex: outBoundParams.OutboundTxBallotIndex, - OutboundTxObservedExternalHeight: outBoundParams.OutboundTxObservedExternalHeight, - OutboundTxGasUsed: outBoundParams.OutboundTxGasUsed, - OutboundTxEffectiveGasPrice: outBoundParams.OutboundTxEffectiveGasPrice, - OutboundTxEffectiveGasLimit: outBoundParams.OutboundTxEffectiveGasLimit, - TssPubkey: outBoundParams.TssPubkey, - TxFinalizationStatus: outBoundParams.TxFinalizationStatus, - } - } - - cctxV15 := types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - Sender: cctx.InboundTxParams.Sender, - SenderChainId: cctx.InboundTxParams.SenderChainId, - TxOrigin: cctx.InboundTxParams.TxOrigin, - Asset: cctx.InboundTxParams.Asset, - Amount: cctx.InboundTxParams.Amount, - InboundTxObservedHash: cctx.InboundTxParams.InboundTxObservedHash, - InboundTxObservedExternalHeight: cctx.InboundTxParams.InboundTxObservedExternalHeight, - InboundTxBallotIndex: cctx.InboundTxParams.InboundTxBallotIndex, - InboundTxFinalizedZetaHeight: cctx.InboundTxParams.InboundTxFinalizedZetaHeight, - TxFinalizationStatus: cctx.InboundTxParams.TxFinalizationStatus, - }, - Index: cctx.Index, - Creator: cctx.Creator, - OutboundTxParams: OutBoundParamsV15, - CctxStatus: cctx.CctxStatus, - CoinType: cctx.InboundTxParams.CoinType, - ZetaFees: cctx.ZetaFees, - RelayedMessage: cctx.RelayedMessage, - EventIndex: 1, // We don't have this information in the old version - } - crosschainKeeper.SetCrossChainTx(tmpctx, cctxV15) - } - commit() - return nil -} - -func GetV14CCTX(ctx sdk.Context, crosschainKeeper crosschainKeeper) (list []types.CrossChainTxV14) { - p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) - store := prefix.NewStore(ctx.KVStore(crosschainKeeper.GetStoreKey()), p) - - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - var val types.CrossChainTxV14 - crosschainKeeper.GetCodec().MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - return list -} diff --git a/x/crosschain/migrations/v6/migrate_test.go b/x/crosschain/migrations/v6/migrate_test.go deleted file mode 100644 index a6bb9eed8f..0000000000 --- a/x/crosschain/migrations/v6/migrate_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package v6_test - -import ( - "fmt" - "sort" - "testing" - - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - keepertest "github.com/zeta-chain/zetacore/testutil/keeper" - "github.com/zeta-chain/zetacore/testutil/sample" - "github.com/zeta-chain/zetacore/x/crosschain/keeper" - v6 "github.com/zeta-chain/zetacore/x/crosschain/migrations/v6" - "github.com/zeta-chain/zetacore/x/crosschain/types" -) - -func TestMigrateStore(t *testing.T) { - t.Run("successful migrate cctx from v14 to v15", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - v14cctxList := make([]*types.CrossChainTxV14, 10) - for i := 0; i < 10; i++ { - v14cctxList[i] = sample.CrossChainTxV14(t, fmt.Sprintf("%d-%s", i, "v14")) - SetCrossChainTxV14(ctx, *v14cctxList[i], k) - } - err := v6.MigrateStore(ctx, k) - require.NoError(t, err) - cctxListv15 := k.GetAllCrossChainTx(ctx) - require.Len(t, cctxListv15, 10) - sort.Slice(cctxListv15, func(i, j int) bool { - return cctxListv15[i].Index < cctxListv15[j].Index - }) - sort.Slice(v14cctxList, func(i, j int) bool { - return v14cctxList[i].Index < v14cctxList[j].Index - }) - for i := 0; i < 10; i++ { - require.Equal(t, v14cctxList[i].Index, cctxListv15[i].Index) - require.Equal(t, v14cctxList[i].Creator, cctxListv15[i].Creator) - require.Equal(t, v14cctxList[i].ZetaFees, cctxListv15[i].ZetaFees) - require.Equal(t, v14cctxList[i].RelayedMessage, cctxListv15[i].RelayedMessage) - require.Equal(t, v14cctxList[i].CctxStatus, cctxListv15[i].CctxStatus) - require.Equal(t, v14cctxList[i].InboundTxParams.Sender, cctxListv15[i].InboundTxParams.Sender) - require.Equal(t, v14cctxList[i].InboundTxParams.SenderChainId, cctxListv15[i].InboundTxParams.SenderChainId) - require.Equal(t, v14cctxList[i].InboundTxParams.TxOrigin, cctxListv15[i].InboundTxParams.TxOrigin) - require.Equal(t, v14cctxList[i].InboundTxParams.Asset, cctxListv15[i].InboundTxParams.Asset) - require.Equal(t, v14cctxList[i].InboundTxParams.Amount, cctxListv15[i].InboundTxParams.Amount) - require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxObservedHash, cctxListv15[i].InboundTxParams.InboundTxObservedHash) - require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxObservedExternalHeight, cctxListv15[i].InboundTxParams.InboundTxObservedExternalHeight) - require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxBallotIndex, cctxListv15[i].InboundTxParams.InboundTxBallotIndex) - require.Equal(t, v14cctxList[i].InboundTxParams.InboundTxFinalizedZetaHeight, cctxListv15[i].InboundTxParams.InboundTxFinalizedZetaHeight) - require.Equal(t, v14cctxList[i].InboundTxParams.CoinType, cctxListv15[i].CoinType) - require.Len(t, v14cctxList[i].OutboundTxParams, len(cctxListv15[i].OutboundTxParams)) - for j := 0; j < len(cctxListv15[i].OutboundTxParams); j++ { - require.Equal(t, v14cctxList[i].OutboundTxParams[j].Receiver, cctxListv15[i].OutboundTxParams[j].Receiver) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].ReceiverChainId, cctxListv15[i].OutboundTxParams[j].ReceiverChainId) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].Amount, cctxListv15[i].OutboundTxParams[j].Amount) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxTssNonce, cctxListv15[i].OutboundTxParams[j].OutboundTxTssNonce) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasLimit, cctxListv15[i].OutboundTxParams[j].OutboundTxGasLimit) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasPrice, cctxListv15[i].OutboundTxParams[j].OutboundTxGasPrice) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxHash, cctxListv15[i].OutboundTxParams[j].OutboundTxHash) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxBallotIndex, cctxListv15[i].OutboundTxParams[j].OutboundTxBallotIndex) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxObservedExternalHeight, cctxListv15[i].OutboundTxParams[j].OutboundTxObservedExternalHeight) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxGasUsed, cctxListv15[i].OutboundTxParams[j].OutboundTxGasUsed) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].OutboundTxEffectiveGasPrice, cctxListv15[i].OutboundTxParams[j].OutboundTxEffectiveGasPrice) - require.Equal(t, v14cctxList[i].OutboundTxParams[j].CoinType, cctxListv15[i].CoinType) - } - } - }) -} - -func SetCrossChainTxV14(ctx sdk.Context, cctx types.CrossChainTxV14, k *keeper.Keeper) { - p := types.KeyPrefix(fmt.Sprintf("%s", types.SendKey)) - store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), p) - b := k.GetCodec().MustMarshal(&cctx) - store.Set(types.KeyPrefix(cctx.Index), b) -} diff --git a/x/crosschain/module.go b/x/crosschain/module.go index 197ecb2564..45d23053da 100644 --- a/x/crosschain/module.go +++ b/x/crosschain/module.go @@ -154,9 +154,6 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(types.ModuleName, 4, m.Migrate4to5); err != nil { panic(err) } - if err := cfg.RegisterMigration(types.ModuleName, 5, m.Migrate5to6); err != nil { - panic(err) - } } @@ -185,7 +182,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements AppModule/ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 6 } +func (AppModule) ConsensusVersion() uint64 { return 5 } // BeginBlock executes all ABCI BeginBlock logic respective to the crosschain module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go index 695cb152f3..144acc379c 100644 --- a/x/crosschain/types/cctx_utils.go +++ b/x/crosschain/types/cctx_utils.go @@ -5,6 +5,7 @@ import ( "regexp" "strconv" + "cosmossdk.io/errors" "github.com/btcsuite/btcutil" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -106,12 +107,12 @@ func (m InboundTxParams) Validate() error { } err = ValidateHashForChain(m.InboundTxObservedHash, m.SenderChainId) if err != nil { - return err + return errors.Wrap(err, "invalid inbound tx observed hash") } if m.InboundTxBallotIndex != "" { err = ValidateZetaIndex(m.InboundTxBallotIndex) if err != nil { - return err + return errors.Wrap(err, "invalid inbound tx ballot index") } } return nil @@ -134,13 +135,13 @@ func (m OutboundTxParams) Validate() error { if m.OutboundTxBallotIndex != "" { err = ValidateZetaIndex(m.OutboundTxBallotIndex) if err != nil { - return err + return errors.Wrap(err, "invalid outbound tx ballot index") } } if m.OutboundTxHash != "" { err = ValidateHashForChain(m.OutboundTxHash, m.ReceiverChainId) if err != nil { - return err + return errors.Wrap(err, "invalid outbound tx hash") } } return nil diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index c0a76dba6a..94f34e6e46 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -95,6 +95,7 @@ type InboundTxParams struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` SenderChainId int64 `protobuf:"varint,2,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` TxOrigin string `protobuf:"bytes,3,opt,name=tx_origin,json=txOrigin,proto3" json:"tx_origin,omitempty"` + CoinType common.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` Asset string `protobuf:"bytes,5,opt,name=asset,proto3" json:"asset,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` InboundTxObservedHash string `protobuf:"bytes,7,opt,name=inbound_tx_observed_hash,json=inboundTxObservedHash,proto3" json:"inbound_tx_observed_hash,omitempty"` @@ -158,6 +159,13 @@ func (m *InboundTxParams) GetTxOrigin() string { return "" } +func (m *InboundTxParams) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + func (m *InboundTxParams) GetAsset() string { if m != nil { return m.Asset @@ -241,6 +249,7 @@ var xxx_messageInfo_ZetaAccounting proto.InternalMessageInfo type OutboundTxParams struct { Receiver string `protobuf:"bytes,1,opt,name=receiver,proto3" json:"receiver,omitempty"` ReceiverChainId int64 `protobuf:"varint,2,opt,name=receiver_chainId,json=receiverChainId,proto3" json:"receiver_chainId,omitempty"` + CoinType common.CoinType `protobuf:"varint,3,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,4,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` OutboundTxTssNonce uint64 `protobuf:"varint,5,opt,name=outbound_tx_tss_nonce,json=outboundTxTssNonce,proto3" json:"outbound_tx_tss_nonce,omitempty"` OutboundTxGasLimit uint64 `protobuf:"varint,6,opt,name=outbound_tx_gas_limit,json=outboundTxGasLimit,proto3" json:"outbound_tx_gas_limit,omitempty"` @@ -304,6 +313,13 @@ func (m *OutboundTxParams) GetReceiverChainId() int64 { return 0 } +func (m *OutboundTxParams) GetCoinType() common.CoinType { + if m != nil { + return m.CoinType + } + return common.CoinType_Zeta +} + func (m *OutboundTxParams) GetOutboundTxTssNonce() uint64 { if m != nil { return m.OutboundTxTssNonce @@ -450,8 +466,6 @@ type CrossChainTx struct { CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` InboundTxParams *InboundTxParams `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` OutboundTxParams []*OutboundTxParams `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` - EventIndex uint64 `protobuf:"varint,11,opt,name=event_index,json=eventIndex,proto3" json:"event_index,omitempty"` - CoinType common.CoinType `protobuf:"varint,12,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` } func (m *CrossChainTx) Reset() { *m = CrossChainTx{} } @@ -529,20 +543,6 @@ func (m *CrossChainTx) GetOutboundTxParams() []*OutboundTxParams { return nil } -func (m *CrossChainTx) GetEventIndex() uint64 { - if m != nil { - return m.EventIndex - } - return 0 -} - -func (m *CrossChainTx) GetCoinType() common.CoinType { - if m != nil { - return m.CoinType - } - return common.CoinType_Zeta -} - func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) @@ -556,78 +556,77 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1132 bytes of a gzipped FileDescriptorProto + // 1120 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, - 0x10, 0xd6, 0xc6, 0x8a, 0x22, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, - 0x12, 0x25, 0x40, 0x24, 0xc4, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0x8d, 0x13, 0x23, 0x89, 0x6d, 0x6c, - 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0x8e, 0x25, 0x22, 0xd2, 0x52, 0x5d, 0x52, 0x86, 0x14, 0xf4, - 0x21, 0xfa, 0x00, 0x3d, 0xf6, 0xd0, 0xa7, 0xe8, 0x39, 0xb7, 0xe6, 0x58, 0xf4, 0x60, 0x14, 0x36, - 0xfa, 0x02, 0x7d, 0x82, 0x62, 0x49, 0xae, 0xb4, 0x56, 0xfd, 0xd3, 0xbf, 0xd3, 0x0e, 0x87, 0xfc, - 0x86, 0xb3, 0x9c, 0xef, 0x1b, 0x12, 0xaa, 0x7e, 0xc4, 0x85, 0xf0, 0xbb, 0x94, 0x85, 0x2d, 0x65, - 0x7a, 0xca, 0xf6, 0xe4, 0xa8, 0x39, 0x88, 0xb8, 0xe4, 0xe4, 0xee, 0x3b, 0x94, 0x54, 0xf9, 0x9a, - 0xca, 0xe2, 0x11, 0x36, 0xa7, 0x98, 0xd5, 0x65, 0x9f, 0xf7, 0xfb, 0x3c, 0x6c, 0xe9, 0x8f, 0xc6, - 0xac, 0x96, 0x3b, 0xbc, 0xc3, 0x95, 0xd9, 0x8a, 0x2d, 0xed, 0xad, 0xff, 0x94, 0x85, 0xd2, 0x76, - 0xd8, 0xe6, 0xc3, 0x30, 0xd8, 0x1f, 0xed, 0xd1, 0x88, 0xf6, 0x05, 0xb9, 0x0d, 0x39, 0x81, 0x61, - 0x80, 0x91, 0x63, 0xd5, 0xac, 0x46, 0xc1, 0x35, 0x23, 0x72, 0x1f, 0x4a, 0xda, 0x32, 0xe9, 0xb0, - 0xc0, 0xb9, 0x51, 0xb3, 0x1a, 0x73, 0xee, 0x82, 0x76, 0x6f, 0xc6, 0xde, 0xed, 0x80, 0xdc, 0x81, - 0x82, 0x1c, 0x79, 0x3c, 0x62, 0x1d, 0x16, 0x3a, 0x73, 0x2a, 0x44, 0x5e, 0x8e, 0x76, 0xd5, 0x98, - 0x94, 0xe1, 0x26, 0x15, 0x02, 0xa5, 0x73, 0x53, 0x4d, 0xe8, 0x01, 0x79, 0x01, 0x39, 0xda, 0xe7, - 0xc3, 0x50, 0x3a, 0xb9, 0xd8, 0xbd, 0xd1, 0x7a, 0x7f, 0x52, 0xcd, 0xfc, 0x7a, 0x52, 0x7d, 0xd0, - 0x61, 0xb2, 0x3b, 0x6c, 0x37, 0x7d, 0xde, 0x6f, 0xf9, 0x5c, 0xf4, 0xb9, 0x30, 0x9f, 0xc7, 0x22, - 0x78, 0xdb, 0x92, 0xe3, 0x01, 0x8a, 0xe6, 0x01, 0x0b, 0xa5, 0x6b, 0xe0, 0xe4, 0x19, 0x38, 0x4c, - 0xff, 0x8e, 0x17, 0xe7, 0xd0, 0x16, 0x18, 0x1d, 0x63, 0xe0, 0x75, 0xa9, 0xe8, 0x3a, 0xb7, 0xd4, - 0x8e, 0x2b, 0x2c, 0xf9, 0xdd, 0x5d, 0x33, 0xfb, 0x92, 0x8a, 0x2e, 0x79, 0x0d, 0x9f, 0x5c, 0x04, - 0xc4, 0x91, 0xc4, 0x28, 0xa4, 0x3d, 0xaf, 0x8b, 0xac, 0xd3, 0x95, 0x4e, 0xbe, 0x66, 0x35, 0xb2, - 0x6e, 0xf5, 0x2f, 0x31, 0x9e, 0x9b, 0x75, 0x2f, 0xd5, 0x32, 0xf2, 0x19, 0x7c, 0x94, 0x8a, 0xd6, - 0xa6, 0xbd, 0x1e, 0x97, 0x1e, 0x0b, 0x03, 0x1c, 0x39, 0x05, 0x95, 0x45, 0x79, 0x12, 0x61, 0x43, - 0x4d, 0x6e, 0xc7, 0x73, 0x64, 0x0b, 0x6a, 0x29, 0xd8, 0x11, 0x0b, 0x69, 0x8f, 0xbd, 0xc3, 0xc0, - 0x8b, 0x8b, 0x9c, 0x64, 0x00, 0x2a, 0x83, 0x8f, 0x27, 0xf8, 0xad, 0x64, 0xd5, 0x21, 0x4a, 0x6a, - 0xb6, 0x67, 0x70, 0x7b, 0x8a, 0xa7, 0x92, 0xf1, 0xd0, 0x13, 0x92, 0xca, 0xa1, 0x70, 0x8a, 0x35, - 0xab, 0xb1, 0xb8, 0xf6, 0xb4, 0x79, 0x25, 0x81, 0x9a, 0x93, 0xa8, 0x0a, 0xfb, 0xa5, 0x82, 0xba, - 0x65, 0x79, 0x81, 0xb7, 0xfe, 0x0d, 0x2c, 0xc6, 0x1b, 0xaf, 0xfb, 0x7e, 0x7c, 0xfe, 0x2c, 0xec, - 0x10, 0x0f, 0x96, 0x69, 0x9b, 0x47, 0x32, 0xc9, 0xdb, 0x14, 0xd6, 0xfa, 0x77, 0x85, 0x5d, 0x32, - 0xb1, 0xd4, 0x26, 0x2a, 0x52, 0xfd, 0xf7, 0x1c, 0xd8, 0xbb, 0x43, 0x79, 0x9e, 0xb4, 0xab, 0x90, - 0x8f, 0xd0, 0x47, 0x76, 0x3c, 0xa1, 0xed, 0x64, 0x4c, 0x1e, 0x82, 0x9d, 0xd8, 0x9a, 0xba, 0xdb, - 0x09, 0x73, 0x4b, 0x89, 0x3f, 0xe1, 0xee, 0x94, 0x88, 0xd9, 0xff, 0x46, 0xc4, 0x27, 0xb0, 0xc2, - 0x4d, 0x8e, 0x71, 0x2d, 0xa5, 0x10, 0x5e, 0xc8, 0x43, 0x1f, 0x15, 0xef, 0xb3, 0x2e, 0xe1, 0x93, - 0x1f, 0xd8, 0x17, 0x62, 0x27, 0x9e, 0x99, 0x85, 0x74, 0xa8, 0xf0, 0x7a, 0xac, 0xcf, 0xb4, 0x26, - 0xce, 0x41, 0x5e, 0x50, 0xf1, 0x3a, 0x9e, 0xb9, 0x08, 0x32, 0x88, 0x98, 0x8f, 0x86, 0xeb, 0xe7, - 0x21, 0x7b, 0xf1, 0x0c, 0x69, 0x80, 0x9d, 0x86, 0x28, 0x65, 0xe4, 0xd5, 0xea, 0xc5, 0xe9, 0x6a, - 0x25, 0x89, 0x67, 0xe0, 0xa4, 0x57, 0x5e, 0xc0, 0xe2, 0x95, 0x29, 0x22, 0x4d, 0xe3, 0x1d, 0xf8, - 0x34, 0x0d, 0xbc, 0x54, 0x4c, 0x9a, 0xca, 0xb5, 0x69, 0x90, 0x4b, 0xd4, 0xd4, 0x82, 0xf2, 0xec, - 0x5f, 0x0e, 0x05, 0x06, 0x4e, 0x59, 0xe1, 0x97, 0xce, 0xfd, 0xe4, 0x81, 0xc0, 0x80, 0x48, 0xa8, - 0xa6, 0x01, 0x78, 0x74, 0x84, 0xbe, 0x64, 0xc7, 0x98, 0x3a, 0xa0, 0x15, 0x55, 0xde, 0xa6, 0x29, - 0xef, 0xfd, 0xbf, 0x51, 0xde, 0xed, 0x50, 0xba, 0x77, 0xa6, 0x7b, 0x3d, 0x4f, 0x82, 0x4e, 0x4e, - 0xf6, 0x8b, 0xab, 0x76, 0xd5, 0x95, 0xbc, 0xad, 0x32, 0xbe, 0x24, 0x8a, 0x2e, 0xe9, 0x5d, 0x80, - 0x98, 0x2c, 0x83, 0x61, 0xfb, 0x2d, 0x8e, 0x95, 0x5e, 0x0b, 0x6e, 0x41, 0x0a, 0xb1, 0xa7, 0x1c, - 0x57, 0x48, 0x7b, 0xfe, 0xff, 0x96, 0xf6, 0xcf, 0x16, 0xe4, 0xb4, 0x49, 0xd6, 0x21, 0x67, 0x76, - 0xb1, 0xd4, 0x2e, 0x0f, 0xaf, 0xd9, 0x65, 0xd3, 0x97, 0x23, 0x13, 0xdb, 0x00, 0xc9, 0x3d, 0x58, - 0xd4, 0x96, 0xd7, 0x47, 0x21, 0x68, 0x07, 0x95, 0x04, 0x0b, 0xee, 0x82, 0xf6, 0xbe, 0xd1, 0x4e, - 0xf2, 0x04, 0xca, 0x3d, 0x2a, 0xe4, 0xc1, 0x20, 0xa0, 0x12, 0x3d, 0xc9, 0xfa, 0x28, 0x24, 0xed, - 0x0f, 0xd4, 0x3d, 0x32, 0xe7, 0x2e, 0x4f, 0xe7, 0xf6, 0x93, 0x29, 0xd2, 0x80, 0x12, 0x13, 0xeb, - 0x71, 0x9b, 0x70, 0xf1, 0x68, 0x18, 0x06, 0x18, 0x28, 0xf1, 0xe6, 0xdd, 0x59, 0x77, 0xfd, 0xfb, - 0x2c, 0xcc, 0x6f, 0xc6, 0x59, 0x2a, 0xb9, 0xef, 0x8f, 0x88, 0x03, 0xb7, 0xfc, 0x08, 0xa9, 0xe4, - 0x49, 0xd3, 0x48, 0x86, 0xf1, 0x3d, 0xa5, 0x99, 0xae, 0xb3, 0xd4, 0x03, 0xf2, 0x35, 0x14, 0x54, - 0x4f, 0x3b, 0x42, 0x14, 0xfa, 0x06, 0xdb, 0xd8, 0xfc, 0x87, 0x1d, 0xe2, 0x8f, 0x93, 0xaa, 0x3d, - 0xa6, 0xfd, 0xde, 0xe7, 0xf5, 0x49, 0xa4, 0xba, 0x9b, 0x8f, 0xed, 0x2d, 0x44, 0x41, 0x1e, 0x40, - 0x29, 0xc2, 0x1e, 0x1d, 0x63, 0x30, 0x39, 0xa7, 0x9c, 0x56, 0xa7, 0x71, 0x27, 0x07, 0xb5, 0x05, - 0x45, 0xdf, 0x97, 0xa3, 0xa4, 0xfa, 0xb1, 0x84, 0x8b, 0x6b, 0xf7, 0xae, 0xa9, 0x8b, 0xa9, 0x09, - 0xf8, 0x93, 0xfa, 0x90, 0x43, 0x58, 0x4a, 0xdd, 0x39, 0x03, 0xd5, 0x4d, 0x95, 0xbc, 0x8b, 0x6b, - 0xcd, 0x6b, 0xa2, 0xcd, 0x3c, 0x1c, 0xdc, 0x12, 0x9b, 0x79, 0x49, 0x7c, 0x05, 0x24, 0xad, 0x08, - 0x13, 0x1c, 0x6a, 0x73, 0x8d, 0xe2, 0x5a, 0xeb, 0x9a, 0xe0, 0xb3, 0x1d, 0xde, 0xb5, 0xf9, 0x6c, - 0xcf, 0xaf, 0x42, 0x11, 0x8f, 0x31, 0x4c, 0x7a, 0x52, 0x51, 0x89, 0x0b, 0x94, 0x4b, 0x37, 0xa2, - 0xc7, 0x50, 0xf0, 0x79, 0xfc, 0x70, 0x1a, 0x0f, 0xd0, 0xe8, 0xc3, 0x6e, 0x9a, 0x57, 0xd1, 0x26, - 0x67, 0xe1, 0xfe, 0x78, 0x80, 0x6e, 0xde, 0x37, 0xd6, 0xa3, 0x6f, 0x01, 0xa6, 0xc4, 0x25, 0x04, - 0x16, 0xf7, 0x30, 0x0c, 0x58, 0xd8, 0x31, 0xff, 0x69, 0x67, 0xc8, 0x32, 0x94, 0x8c, 0x2f, 0x49, - 0xcf, 0xb6, 0xc8, 0x12, 0x2c, 0x24, 0xa3, 0x37, 0x2c, 0xc4, 0xc0, 0x9e, 0x8b, 0x5d, 0x66, 0x9d, - 0x8b, 0xc7, 0x18, 0x49, 0x3b, 0x4b, 0xe6, 0x21, 0xaf, 0x6d, 0x0c, 0xec, 0x9b, 0xa4, 0x08, 0xb7, - 0xd6, 0xf5, 0xc5, 0x66, 0xe7, 0x56, 0xb3, 0x3f, 0xfe, 0x50, 0xb1, 0x1e, 0xbd, 0x82, 0xf2, 0x45, - 0xe2, 0x24, 0x36, 0xcc, 0xef, 0x70, 0x39, 0xb9, 0xe6, 0xed, 0x0c, 0x59, 0x80, 0xc2, 0x74, 0x68, - 0xc5, 0x91, 0x9f, 0x8f, 0xd0, 0x1f, 0xc6, 0xc1, 0x6e, 0xe8, 0x60, 0x1b, 0xaf, 0xde, 0x9f, 0x56, - 0xac, 0x0f, 0xa7, 0x15, 0xeb, 0xb7, 0xd3, 0x8a, 0xf5, 0xdd, 0x59, 0x25, 0xf3, 0xe1, 0xac, 0x92, - 0xf9, 0xe5, 0xac, 0x92, 0x39, 0x7c, 0x92, 0xe2, 0x69, 0x7c, 0xee, 0x8f, 0xf5, 0x3b, 0x33, 0x29, - 0x41, 0x6b, 0xd4, 0x4a, 0xbd, 0x3e, 0x15, 0x6d, 0xdb, 0x39, 0xf5, 0x56, 0x7c, 0xfa, 0x67, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x55, 0xcf, 0x88, 0x02, 0x98, 0x0a, 0x00, 0x00, + 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, + 0x12, 0x25, 0x80, 0x25, 0xd8, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0xb5, 0x13, 0x23, 0x89, 0x6d, 0x6c, + 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0xd2, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, + 0x10, 0x3d, 0xf4, 0x11, 0x7a, 0xe8, 0xa3, 0xe4, 0x50, 0xa0, 0x39, 0x16, 0x3d, 0x18, 0x85, 0x7d, + 0xee, 0xa5, 0x4f, 0x50, 0xf0, 0x67, 0x57, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, + 0x9b, 0x21, 0xe7, 0x1b, 0x72, 0xa1, 0xe6, 0x47, 0x8c, 0x73, 0xbf, 0x87, 0x69, 0xd8, 0x56, 0xa6, + 0xa7, 0x6c, 0x4f, 0x8c, 0x5b, 0xc3, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, 0x4b, + 0x59, 0x2c, 0x22, 0xad, 0x09, 0x66, 0x79, 0xd1, 0x67, 0x83, 0x01, 0x0b, 0xdb, 0xfa, 0xa3, 0x31, + 0xcb, 0x95, 0x2e, 0xeb, 0x32, 0x65, 0xb6, 0xa5, 0xa5, 0xbd, 0x8d, 0xdf, 0x73, 0x50, 0xde, 0x09, + 0x3b, 0x6c, 0x14, 0x06, 0x07, 0xe3, 0x7d, 0x1c, 0xe1, 0x01, 0x47, 0xf7, 0x20, 0xcf, 0x49, 0x18, + 0x90, 0xc8, 0xb1, 0xea, 0x56, 0xb3, 0xe8, 0x9a, 0x11, 0x7a, 0x04, 0x65, 0x6d, 0x99, 0x74, 0x68, + 0xe0, 0xdc, 0xa9, 0x5b, 0xcd, 0xac, 0x3b, 0xa7, 0xdd, 0x9b, 0xd2, 0xbb, 0x13, 0xa0, 0xfb, 0x50, + 0x14, 0x63, 0x8f, 0x45, 0xb4, 0x4b, 0x43, 0x27, 0xab, 0x28, 0x0a, 0x62, 0xbc, 0xa7, 0xc6, 0x68, + 0x05, 0x8a, 0x3e, 0x93, 0x7b, 0x39, 0x1d, 0x12, 0x27, 0x57, 0xb7, 0x9a, 0xf3, 0x6b, 0x76, 0xcb, + 0x24, 0xba, 0xc9, 0x68, 0x78, 0x70, 0x3a, 0x24, 0x6e, 0xc1, 0x37, 0x16, 0xaa, 0xc0, 0x5d, 0xcc, + 0x39, 0x11, 0xce, 0x5d, 0xc5, 0xa3, 0x07, 0xe8, 0x05, 0xe4, 0xf1, 0x80, 0x8d, 0x42, 0xe1, 0xe4, + 0xa5, 0x7b, 0xa3, 0xfd, 0xfe, 0xac, 0x96, 0xf9, 0xf5, 0xac, 0xf6, 0xb8, 0x4b, 0x45, 0x6f, 0xd4, + 0x91, 0x7c, 0x6d, 0x9f, 0xf1, 0x01, 0xe3, 0xe6, 0xb3, 0xc2, 0x83, 0xb7, 0x6d, 0x19, 0x92, 0xb7, + 0x0e, 0x69, 0x28, 0x5c, 0x03, 0x47, 0xcf, 0xc1, 0xa1, 0x7a, 0xf7, 0x9e, 0x4c, 0xb9, 0xc3, 0x49, + 0x74, 0x42, 0x02, 0xaf, 0x87, 0x79, 0xcf, 0x99, 0x51, 0x11, 0x97, 0x68, 0x7c, 0x3a, 0x7b, 0x66, + 0xf6, 0x25, 0xe6, 0x3d, 0xf4, 0x1a, 0x3e, 0xb9, 0x0a, 0x48, 0xc6, 0x82, 0x44, 0x21, 0xee, 0x7b, + 0x3d, 0x42, 0xbb, 0x3d, 0xe1, 0x14, 0xea, 0x56, 0x33, 0xe7, 0xd6, 0xfe, 0xc2, 0xb1, 0x65, 0xd6, + 0xbd, 0x54, 0xcb, 0xd0, 0x67, 0xf0, 0x51, 0x8a, 0xad, 0x83, 0xfb, 0x7d, 0x26, 0x3c, 0x1a, 0x06, + 0x64, 0xec, 0x14, 0x55, 0x16, 0x95, 0x84, 0x61, 0x43, 0x4d, 0xee, 0xc8, 0x39, 0xb4, 0x0d, 0xf5, + 0x14, 0xec, 0x98, 0x86, 0xb8, 0x4f, 0xdf, 0x91, 0xc0, 0x93, 0x9a, 0x88, 0x33, 0x00, 0x95, 0xc1, + 0xc7, 0x09, 0x7e, 0x3b, 0x5e, 0x75, 0x44, 0x04, 0x36, 0xe1, 0x29, 0xdc, 0x9b, 0xe0, 0xb1, 0xa0, + 0x2c, 0xf4, 0xb8, 0xc0, 0x62, 0xc4, 0x9d, 0x92, 0x2a, 0xd0, 0xb3, 0xd6, 0x8d, 0x7a, 0x6b, 0x25, + 0xac, 0x0a, 0xfb, 0xa5, 0x82, 0xba, 0x15, 0x71, 0x85, 0xb7, 0xf1, 0x0d, 0xcc, 0xcb, 0xc0, 0xeb, + 0xbe, 0x2f, 0xcf, 0x9f, 0x86, 0x5d, 0xe4, 0xc1, 0x22, 0xee, 0xb0, 0x48, 0xc4, 0x79, 0x9b, 0xc2, + 0x5a, 0xff, 0xae, 0xb0, 0x0b, 0x86, 0x4b, 0x05, 0x51, 0x4c, 0x8d, 0xef, 0x67, 0xc0, 0xde, 0x1b, + 0x89, 0xcb, 0x1a, 0x5f, 0x86, 0x42, 0x44, 0x7c, 0x42, 0x4f, 0x12, 0x95, 0x27, 0x63, 0xf4, 0x04, + 0xec, 0xd8, 0xd6, 0x4a, 0xdf, 0x89, 0x85, 0x5e, 0x8e, 0xfd, 0xb1, 0xd4, 0x2f, 0xa9, 0x39, 0x7b, + 0xab, 0x9a, 0x27, 0xba, 0xcd, 0xfd, 0x37, 0xdd, 0xae, 0xc2, 0x12, 0x33, 0x5b, 0x92, 0xa5, 0x17, + 0x9c, 0x7b, 0x21, 0x0b, 0x7d, 0xa2, 0xda, 0x24, 0xe7, 0x22, 0x96, 0xec, 0xf7, 0x80, 0xf3, 0x5d, + 0x39, 0x33, 0x0d, 0xe9, 0x62, 0xee, 0xf5, 0xe9, 0x80, 0xea, 0x16, 0xba, 0x04, 0x79, 0x81, 0xf9, + 0x6b, 0x39, 0x73, 0x15, 0x64, 0x18, 0x51, 0x9f, 0x98, 0xd6, 0xb8, 0x0c, 0xd9, 0x97, 0x33, 0xa8, + 0x09, 0x76, 0x1a, 0xa2, 0x1a, 0xa9, 0xa0, 0x56, 0xcf, 0x4f, 0x56, 0xab, 0x0e, 0x7a, 0x0e, 0x4e, + 0x7a, 0xe5, 0x15, 0xa2, 0x5f, 0x9a, 0x20, 0xd2, 0xaa, 0xdf, 0x85, 0x4f, 0xd3, 0xc0, 0x6b, 0x7b, + 0x4f, 0x2b, 0xbf, 0x3e, 0x21, 0xb9, 0xa6, 0xf9, 0xda, 0x50, 0x99, 0xde, 0xe5, 0x88, 0x93, 0xc0, + 0xa9, 0x28, 0xfc, 0xc2, 0xa5, 0x4d, 0x1e, 0x72, 0x12, 0x20, 0x01, 0xb5, 0x34, 0x80, 0x1c, 0x1f, + 0x13, 0x5f, 0xd0, 0x13, 0x92, 0x3a, 0xa0, 0x25, 0x55, 0xde, 0x96, 0x29, 0xef, 0xa3, 0xbf, 0x51, + 0xde, 0x9d, 0x50, 0xb8, 0xf7, 0x27, 0xb1, 0xb6, 0x62, 0xd2, 0xe4, 0x64, 0xbf, 0xb8, 0x29, 0xaa, + 0xae, 0xe4, 0x3d, 0x95, 0xf1, 0x35, 0x2c, 0xba, 0xa4, 0x0f, 0x00, 0xa4, 0x58, 0x86, 0xa3, 0xce, + 0x5b, 0x72, 0xaa, 0xda, 0xbb, 0xe8, 0x16, 0x05, 0xe7, 0xfb, 0xca, 0x71, 0xc3, 0x4d, 0x30, 0xfb, + 0x7f, 0xdf, 0x04, 0x3f, 0x5b, 0x90, 0xd7, 0x26, 0x5a, 0x87, 0xbc, 0x89, 0x62, 0xa9, 0x28, 0x4f, + 0x6e, 0x89, 0xb2, 0xe9, 0x8b, 0xb1, 0xe1, 0x36, 0x40, 0xf4, 0x10, 0xe6, 0xb5, 0xe5, 0x0d, 0x08, + 0xe7, 0xb8, 0x4b, 0x54, 0xc7, 0x16, 0xdd, 0x39, 0xed, 0x7d, 0xa3, 0x9d, 0x68, 0x15, 0x2a, 0x7d, + 0xcc, 0xc5, 0xe1, 0x30, 0xc0, 0x82, 0x78, 0x82, 0x0e, 0x08, 0x17, 0x78, 0x30, 0x54, 0xad, 0x9b, + 0x75, 0x17, 0x27, 0x73, 0x07, 0xf1, 0x14, 0x6a, 0x42, 0x99, 0xf2, 0x75, 0x79, 0xab, 0xb8, 0xe4, + 0x78, 0x14, 0x06, 0x24, 0x50, 0xcd, 0x5b, 0x70, 0xa7, 0xdd, 0x8d, 0x9f, 0xb2, 0x30, 0xbb, 0x29, + 0xb3, 0x54, 0xb7, 0xc3, 0xc1, 0x18, 0x39, 0x30, 0xe3, 0x47, 0x04, 0x0b, 0x16, 0xdf, 0x31, 0xf1, + 0x50, 0x3e, 0x6b, 0x5a, 0xe9, 0x3a, 0x4b, 0x3d, 0x40, 0x5f, 0x43, 0x51, 0x5d, 0x81, 0xc7, 0x84, + 0x70, 0xfd, 0xe0, 0x6d, 0x6c, 0xfe, 0xc3, 0x1b, 0xe2, 0x8f, 0xb3, 0x9a, 0x7d, 0x8a, 0x07, 0xfd, + 0xcf, 0x1b, 0x09, 0x53, 0xc3, 0x2d, 0x48, 0x7b, 0x9b, 0x10, 0x8e, 0x1e, 0x43, 0x39, 0x22, 0x7d, + 0x7c, 0x4a, 0x82, 0xe4, 0x9c, 0xf2, 0xba, 0x3b, 0x8d, 0x3b, 0x3e, 0xa8, 0x6d, 0x28, 0xf9, 0xbe, + 0x18, 0xc7, 0xd5, 0x97, 0x2d, 0x5c, 0x5a, 0x7b, 0x78, 0x4b, 0x5d, 0x4c, 0x4d, 0xc0, 0x4f, 0xea, + 0x83, 0x8e, 0x60, 0x21, 0xf5, 0x44, 0x0d, 0xd5, 0xe5, 0xab, 0xda, 0xbb, 0xb4, 0xd6, 0xba, 0x85, + 0x6d, 0xea, 0xb7, 0xc4, 0x2d, 0xd3, 0xa9, 0xff, 0x94, 0xaf, 0x00, 0xa5, 0x3b, 0xc2, 0x90, 0x43, + 0x3d, 0xdb, 0x2c, 0xad, 0xb5, 0x6f, 0x21, 0x9f, 0x7e, 0x10, 0x5c, 0x9b, 0x4d, 0x79, 0x9e, 0x7e, + 0x0b, 0x30, 0x11, 0x1a, 0x42, 0x30, 0xbf, 0x4f, 0xc2, 0x80, 0x86, 0x5d, 0x93, 0x97, 0x9d, 0x41, + 0x8b, 0x50, 0x36, 0xbe, 0x98, 0xce, 0xb6, 0xd0, 0x02, 0xcc, 0xc5, 0xa3, 0x37, 0x34, 0x24, 0x81, + 0x9d, 0x95, 0x2e, 0xb3, 0xce, 0x25, 0x27, 0x24, 0x12, 0x76, 0x0e, 0xcd, 0x42, 0x41, 0xdb, 0x24, + 0xb0, 0xef, 0xa2, 0x12, 0xcc, 0xac, 0xeb, 0x77, 0xcb, 0xce, 0x2f, 0xe7, 0x7e, 0xfc, 0xa1, 0x6a, + 0x3d, 0x7d, 0x05, 0x95, 0xab, 0x9a, 0x09, 0xd9, 0x30, 0xbb, 0xcb, 0x44, 0xf2, 0x8a, 0xdb, 0x19, + 0x34, 0x07, 0xc5, 0xc9, 0xd0, 0x92, 0xcc, 0x5b, 0x63, 0xe2, 0x8f, 0x24, 0xd9, 0x1d, 0x4d, 0xb6, + 0xf1, 0xea, 0xfd, 0x79, 0xd5, 0xfa, 0x70, 0x5e, 0xb5, 0x7e, 0x3b, 0xaf, 0x5a, 0xdf, 0x5d, 0x54, + 0x33, 0x1f, 0x2e, 0xaa, 0x99, 0x5f, 0x2e, 0xaa, 0x99, 0xa3, 0xd5, 0x94, 0xae, 0xe4, 0x39, 0xad, + 0xe8, 0xbf, 0xce, 0xf8, 0xc8, 0xda, 0xe3, 0x76, 0xea, 0x5f, 0x54, 0xc9, 0xac, 0x93, 0x57, 0x7f, + 0x8e, 0xcf, 0xfe, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x13, 0xc7, 0x24, 0x8d, 0xa6, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -696,6 +695,11 @@ func (m *InboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x2a } + if m.CoinType != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x20 + } if len(m.TxOrigin) > 0 { i -= len(m.TxOrigin) copy(dAtA[i:], m.TxOrigin) @@ -855,6 +859,11 @@ func (m *OutboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x22 + if m.CoinType != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x18 + } if m.ReceiverChainId != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.ReceiverChainId)) i-- @@ -940,16 +949,6 @@ func (m *CrossChainTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.CoinType != 0 { - i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CoinType)) - i-- - dAtA[i] = 0x60 - } - if m.EventIndex != 0 { - i = encodeVarintCrossChainTx(dAtA, i, uint64(m.EventIndex)) - i-- - dAtA[i] = 0x58 - } if len(m.OutboundTxParams) > 0 { for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { { @@ -1050,6 +1049,9 @@ func (m *InboundTxParams) Size() (n int) { if l > 0 { n += 1 + l + sovCrossChainTx(uint64(l)) } + if m.CoinType != 0 { + n += 1 + sovCrossChainTx(uint64(m.CoinType)) + } l = len(m.Asset) if l > 0 { n += 1 + l + sovCrossChainTx(uint64(l)) @@ -1100,6 +1102,9 @@ func (m *OutboundTxParams) Size() (n int) { if m.ReceiverChainId != 0 { n += 1 + sovCrossChainTx(uint64(m.ReceiverChainId)) } + if m.CoinType != 0 { + n += 1 + sovCrossChainTx(uint64(m.CoinType)) + } l = m.Amount.Size() n += 1 + l + sovCrossChainTx(uint64(l)) if m.OutboundTxTssNonce != 0 { @@ -1197,12 +1202,6 @@ func (m *CrossChainTx) Size() (n int) { n += 1 + l + sovCrossChainTx(uint64(l)) } } - if m.EventIndex != 0 { - n += 1 + sovCrossChainTx(uint64(m.EventIndex)) - } - if m.CoinType != 0 { - n += 1 + sovCrossChainTx(uint64(m.CoinType)) - } return n } @@ -1324,6 +1323,25 @@ func (m *InboundTxParams) Unmarshal(dAtA []byte) error { } m.TxOrigin = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) @@ -1696,6 +1714,25 @@ func (m *OutboundTxParams) Unmarshal(dAtA []byte) error { break } } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= common.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) @@ -2432,44 +2469,6 @@ func (m *CrossChainTx) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field EventIndex", wireType) - } - m.EventIndex = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.EventIndex |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) - } - m.CoinType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CoinType |= common.CoinType(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/crosschain/types/cross_chain_tx_v14.pb.go b/x/crosschain/types/cross_chain_tx_v14.pb.go deleted file mode 100644 index be51a85fd0..0000000000 --- a/x/crosschain/types/cross_chain_tx_v14.pb.go +++ /dev/null @@ -1,2051 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: crosschain/cross_chain_tx_v14.proto - -package types - -import ( - fmt "fmt" - io "io" - math "math" - math_bits "math/bits" - - github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/gogo/protobuf/proto" - common "github.com/zeta-chain/zetacore/common" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type InboundTxParamsV14 struct { - Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` - SenderChainId int64 `protobuf:"varint,2,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` - TxOrigin string `protobuf:"bytes,3,opt,name=tx_origin,json=txOrigin,proto3" json:"tx_origin,omitempty"` - CoinType common.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` - Asset string `protobuf:"bytes,5,opt,name=asset,proto3" json:"asset,omitempty"` - Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` - InboundTxObservedHash string `protobuf:"bytes,7,opt,name=inbound_tx_observed_hash,json=inboundTxObservedHash,proto3" json:"inbound_tx_observed_hash,omitempty"` - InboundTxObservedExternalHeight uint64 `protobuf:"varint,8,opt,name=inbound_tx_observed_external_height,json=inboundTxObservedExternalHeight,proto3" json:"inbound_tx_observed_external_height,omitempty"` - InboundTxBallotIndex string `protobuf:"bytes,9,opt,name=inbound_tx_ballot_index,json=inboundTxBallotIndex,proto3" json:"inbound_tx_ballot_index,omitempty"` - InboundTxFinalizedZetaHeight uint64 `protobuf:"varint,10,opt,name=inbound_tx_finalized_zeta_height,json=inboundTxFinalizedZetaHeight,proto3" json:"inbound_tx_finalized_zeta_height,omitempty"` - TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,11,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` -} - -func (m *InboundTxParamsV14) Reset() { *m = InboundTxParamsV14{} } -func (m *InboundTxParamsV14) String() string { return proto.CompactTextString(m) } -func (*InboundTxParamsV14) ProtoMessage() {} -func (*InboundTxParamsV14) Descriptor() ([]byte, []int) { - return fileDescriptor_9a400eff2bb43434, []int{0} -} -func (m *InboundTxParamsV14) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *InboundTxParamsV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_InboundTxParamsV14.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *InboundTxParamsV14) XXX_Merge(src proto.Message) { - xxx_messageInfo_InboundTxParamsV14.Merge(m, src) -} -func (m *InboundTxParamsV14) XXX_Size() int { - return m.Size() -} -func (m *InboundTxParamsV14) XXX_DiscardUnknown() { - xxx_messageInfo_InboundTxParamsV14.DiscardUnknown(m) -} - -var xxx_messageInfo_InboundTxParamsV14 proto.InternalMessageInfo - -func (m *InboundTxParamsV14) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -func (m *InboundTxParamsV14) GetSenderChainId() int64 { - if m != nil { - return m.SenderChainId - } - return 0 -} - -func (m *InboundTxParamsV14) GetTxOrigin() string { - if m != nil { - return m.TxOrigin - } - return "" -} - -func (m *InboundTxParamsV14) GetCoinType() common.CoinType { - if m != nil { - return m.CoinType - } - return common.CoinType_Zeta -} - -func (m *InboundTxParamsV14) GetAsset() string { - if m != nil { - return m.Asset - } - return "" -} - -func (m *InboundTxParamsV14) GetInboundTxObservedHash() string { - if m != nil { - return m.InboundTxObservedHash - } - return "" -} - -func (m *InboundTxParamsV14) GetInboundTxObservedExternalHeight() uint64 { - if m != nil { - return m.InboundTxObservedExternalHeight - } - return 0 -} - -func (m *InboundTxParamsV14) GetInboundTxBallotIndex() string { - if m != nil { - return m.InboundTxBallotIndex - } - return "" -} - -func (m *InboundTxParamsV14) GetInboundTxFinalizedZetaHeight() uint64 { - if m != nil { - return m.InboundTxFinalizedZetaHeight - } - return 0 -} - -func (m *InboundTxParamsV14) GetTxFinalizationStatus() TxFinalizationStatus { - if m != nil { - return m.TxFinalizationStatus - } - return TxFinalizationStatus_NotFinalized -} - -type OutboundTxParamsV14 struct { - Receiver string `protobuf:"bytes,1,opt,name=receiver,proto3" json:"receiver,omitempty"` - ReceiverChainId int64 `protobuf:"varint,2,opt,name=receiver_chainId,json=receiverChainId,proto3" json:"receiver_chainId,omitempty"` - CoinType common.CoinType `protobuf:"varint,3,opt,name=coin_type,json=coinType,proto3,enum=common.CoinType" json:"coin_type,omitempty"` - Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,4,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` - OutboundTxTssNonce uint64 `protobuf:"varint,5,opt,name=outbound_tx_tss_nonce,json=outboundTxTssNonce,proto3" json:"outbound_tx_tss_nonce,omitempty"` - OutboundTxGasLimit uint64 `protobuf:"varint,6,opt,name=outbound_tx_gas_limit,json=outboundTxGasLimit,proto3" json:"outbound_tx_gas_limit,omitempty"` - OutboundTxGasPrice string `protobuf:"bytes,7,opt,name=outbound_tx_gas_price,json=outboundTxGasPrice,proto3" json:"outbound_tx_gas_price,omitempty"` - // the above are commands for zetaclients - // the following fields are used when the outbound tx is mined - OutboundTxHash string `protobuf:"bytes,8,opt,name=outbound_tx_hash,json=outboundTxHash,proto3" json:"outbound_tx_hash,omitempty"` - OutboundTxBallotIndex string `protobuf:"bytes,9,opt,name=outbound_tx_ballot_index,json=outboundTxBallotIndex,proto3" json:"outbound_tx_ballot_index,omitempty"` - OutboundTxObservedExternalHeight uint64 `protobuf:"varint,10,opt,name=outbound_tx_observed_external_height,json=outboundTxObservedExternalHeight,proto3" json:"outbound_tx_observed_external_height,omitempty"` - OutboundTxGasUsed uint64 `protobuf:"varint,20,opt,name=outbound_tx_gas_used,json=outboundTxGasUsed,proto3" json:"outbound_tx_gas_used,omitempty"` - OutboundTxEffectiveGasPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,21,opt,name=outbound_tx_effective_gas_price,json=outboundTxEffectiveGasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"outbound_tx_effective_gas_price"` - OutboundTxEffectiveGasLimit uint64 `protobuf:"varint,22,opt,name=outbound_tx_effective_gas_limit,json=outboundTxEffectiveGasLimit,proto3" json:"outbound_tx_effective_gas_limit,omitempty"` - TssPubkey string `protobuf:"bytes,11,opt,name=tss_pubkey,json=tssPubkey,proto3" json:"tss_pubkey,omitempty"` - TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,12,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` -} - -func (m *OutboundTxParamsV14) Reset() { *m = OutboundTxParamsV14{} } -func (m *OutboundTxParamsV14) String() string { return proto.CompactTextString(m) } -func (*OutboundTxParamsV14) ProtoMessage() {} -func (*OutboundTxParamsV14) Descriptor() ([]byte, []int) { - return fileDescriptor_9a400eff2bb43434, []int{1} -} -func (m *OutboundTxParamsV14) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *OutboundTxParamsV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_OutboundTxParamsV14.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *OutboundTxParamsV14) XXX_Merge(src proto.Message) { - xxx_messageInfo_OutboundTxParamsV14.Merge(m, src) -} -func (m *OutboundTxParamsV14) XXX_Size() int { - return m.Size() -} -func (m *OutboundTxParamsV14) XXX_DiscardUnknown() { - xxx_messageInfo_OutboundTxParamsV14.DiscardUnknown(m) -} - -var xxx_messageInfo_OutboundTxParamsV14 proto.InternalMessageInfo - -func (m *OutboundTxParamsV14) GetReceiver() string { - if m != nil { - return m.Receiver - } - return "" -} - -func (m *OutboundTxParamsV14) GetReceiverChainId() int64 { - if m != nil { - return m.ReceiverChainId - } - return 0 -} - -func (m *OutboundTxParamsV14) GetCoinType() common.CoinType { - if m != nil { - return m.CoinType - } - return common.CoinType_Zeta -} - -func (m *OutboundTxParamsV14) GetOutboundTxTssNonce() uint64 { - if m != nil { - return m.OutboundTxTssNonce - } - return 0 -} - -func (m *OutboundTxParamsV14) GetOutboundTxGasLimit() uint64 { - if m != nil { - return m.OutboundTxGasLimit - } - return 0 -} - -func (m *OutboundTxParamsV14) GetOutboundTxGasPrice() string { - if m != nil { - return m.OutboundTxGasPrice - } - return "" -} - -func (m *OutboundTxParamsV14) GetOutboundTxHash() string { - if m != nil { - return m.OutboundTxHash - } - return "" -} - -func (m *OutboundTxParamsV14) GetOutboundTxBallotIndex() string { - if m != nil { - return m.OutboundTxBallotIndex - } - return "" -} - -func (m *OutboundTxParamsV14) GetOutboundTxObservedExternalHeight() uint64 { - if m != nil { - return m.OutboundTxObservedExternalHeight - } - return 0 -} - -func (m *OutboundTxParamsV14) GetOutboundTxGasUsed() uint64 { - if m != nil { - return m.OutboundTxGasUsed - } - return 0 -} - -func (m *OutboundTxParamsV14) GetOutboundTxEffectiveGasLimit() uint64 { - if m != nil { - return m.OutboundTxEffectiveGasLimit - } - return 0 -} - -func (m *OutboundTxParamsV14) GetTssPubkey() string { - if m != nil { - return m.TssPubkey - } - return "" -} - -func (m *OutboundTxParamsV14) GetTxFinalizationStatus() TxFinalizationStatus { - if m != nil { - return m.TxFinalizationStatus - } - return TxFinalizationStatus_NotFinalized -} - -type CrossChainTxV14 struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Index string `protobuf:"bytes,2,opt,name=index,proto3" json:"index,omitempty"` - ZetaFees github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,5,opt,name=zeta_fees,json=zetaFees,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"zeta_fees" yaml:"zeta_fees"` - RelayedMessage string `protobuf:"bytes,6,opt,name=relayed_message,json=relayedMessage,proto3" json:"relayed_message,omitempty"` - CctxStatus *Status `protobuf:"bytes,8,opt,name=cctx_status,json=cctxStatus,proto3" json:"cctx_status,omitempty"` - InboundTxParams *InboundTxParamsV14 `protobuf:"bytes,9,opt,name=inbound_tx_params,json=inboundTxParams,proto3" json:"inbound_tx_params,omitempty"` - OutboundTxParams []*OutboundTxParamsV14 `protobuf:"bytes,10,rep,name=outbound_tx_params,json=outboundTxParams,proto3" json:"outbound_tx_params,omitempty"` -} - -func (m *CrossChainTxV14) Reset() { *m = CrossChainTxV14{} } -func (m *CrossChainTxV14) String() string { return proto.CompactTextString(m) } -func (*CrossChainTxV14) ProtoMessage() {} -func (*CrossChainTxV14) Descriptor() ([]byte, []int) { - return fileDescriptor_9a400eff2bb43434, []int{2} -} -func (m *CrossChainTxV14) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *CrossChainTxV14) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_CrossChainTxV14.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *CrossChainTxV14) XXX_Merge(src proto.Message) { - xxx_messageInfo_CrossChainTxV14.Merge(m, src) -} -func (m *CrossChainTxV14) XXX_Size() int { - return m.Size() -} -func (m *CrossChainTxV14) XXX_DiscardUnknown() { - xxx_messageInfo_CrossChainTxV14.DiscardUnknown(m) -} - -var xxx_messageInfo_CrossChainTxV14 proto.InternalMessageInfo - -func (m *CrossChainTxV14) GetCreator() string { - if m != nil { - return m.Creator - } - return "" -} - -func (m *CrossChainTxV14) GetIndex() string { - if m != nil { - return m.Index - } - return "" -} - -func (m *CrossChainTxV14) GetRelayedMessage() string { - if m != nil { - return m.RelayedMessage - } - return "" -} - -func (m *CrossChainTxV14) GetCctxStatus() *Status { - if m != nil { - return m.CctxStatus - } - return nil -} - -func (m *CrossChainTxV14) GetInboundTxParams() *InboundTxParamsV14 { - if m != nil { - return m.InboundTxParams - } - return nil -} - -func (m *CrossChainTxV14) GetOutboundTxParams() []*OutboundTxParamsV14 { - if m != nil { - return m.OutboundTxParams - } - return nil -} - -func init() { - proto.RegisterType((*InboundTxParamsV14)(nil), "zetachain.zetacore.crosschain.InboundTxParamsV14") - proto.RegisterType((*OutboundTxParamsV14)(nil), "zetachain.zetacore.crosschain.OutboundTxParamsV14") - proto.RegisterType((*CrossChainTxV14)(nil), "zetachain.zetacore.crosschain.CrossChainTxV14") -} - -func init() { - proto.RegisterFile("crosschain/cross_chain_tx_v14.proto", fileDescriptor_9a400eff2bb43434) -} - -var fileDescriptor_9a400eff2bb43434 = []byte{ - // 913 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x51, 0x6f, 0x1a, 0x47, - 0x10, 0x36, 0x81, 0xd8, 0x30, 0xb4, 0x86, 0x6c, 0xb0, 0x7b, 0x72, 0x1a, 0x40, 0x4e, 0x9b, 0xd0, - 0x07, 0x73, 0x82, 0xa4, 0x8a, 0xd4, 0x47, 0xbb, 0x71, 0x82, 0x9a, 0xc6, 0xd6, 0xd5, 0xe9, 0x43, - 0xa4, 0xea, 0xb2, 0xdc, 0x8d, 0x61, 0x15, 0xb8, 0x45, 0xb7, 0x8b, 0x75, 0xe4, 0x57, 0xf4, 0xad, - 0x7f, 0x29, 0x8f, 0x79, 0xa9, 0x54, 0xf5, 0xc1, 0xaa, 0xec, 0x3f, 0x50, 0xf5, 0x17, 0x54, 0xbb, - 0x7b, 0x77, 0x1c, 0x36, 0xb6, 0x5b, 0xb5, 0x4f, 0xcc, 0xce, 0xce, 0xf7, 0xed, 0xee, 0xcc, 0x37, - 0xc3, 0xc1, 0x03, 0x2f, 0xe4, 0x42, 0x78, 0x43, 0xca, 0x02, 0x5b, 0x9b, 0xae, 0xb6, 0x5d, 0x19, - 0xb9, 0x27, 0x9d, 0x27, 0xed, 0x49, 0xc8, 0x25, 0x27, 0xf7, 0xdf, 0xa3, 0xa4, 0xda, 0xdf, 0xd6, - 0x16, 0x0f, 0xb1, 0x3d, 0xc7, 0x6d, 0xdd, 0xf5, 0xf8, 0x78, 0xcc, 0x03, 0xdb, 0xfc, 0x18, 0xcc, - 0x56, 0xe3, 0x4a, 0xe2, 0x38, 0xa0, 0x36, 0xe0, 0x03, 0xae, 0x4d, 0x5b, 0x59, 0xc6, 0xbb, 0xfd, - 0x67, 0x01, 0x48, 0x2f, 0xe8, 0xf3, 0x69, 0xe0, 0x1f, 0x45, 0x87, 0x34, 0xa4, 0x63, 0xf1, 0x63, - 0xe7, 0x09, 0xd9, 0x84, 0x55, 0x81, 0x81, 0x8f, 0xa1, 0x95, 0x6b, 0xe6, 0x5a, 0x25, 0x27, 0x5e, - 0x91, 0x87, 0x50, 0x31, 0x56, 0xcc, 0xce, 0x7c, 0xeb, 0x56, 0x33, 0xd7, 0xca, 0x3b, 0x9f, 0x1a, - 0xf7, 0x9e, 0xf2, 0xf6, 0x7c, 0x72, 0x0f, 0x4a, 0x32, 0x72, 0x79, 0xc8, 0x06, 0x2c, 0xb0, 0xf2, - 0x9a, 0xa2, 0x28, 0xa3, 0x03, 0xbd, 0x26, 0x3b, 0x50, 0xf2, 0xb8, 0xba, 0xda, 0x6c, 0x82, 0x56, - 0xa1, 0x99, 0x6b, 0xad, 0x77, 0xab, 0xed, 0xf8, 0x31, 0x7b, 0x9c, 0x05, 0x47, 0xb3, 0x09, 0x3a, - 0x45, 0x2f, 0xb6, 0x48, 0x0d, 0x6e, 0x53, 0x21, 0x50, 0x5a, 0xb7, 0x35, 0x8f, 0x59, 0x90, 0xe7, - 0xb0, 0x4a, 0xc7, 0x7c, 0x1a, 0x48, 0x6b, 0x55, 0xb9, 0x77, 0xed, 0x0f, 0xa7, 0x8d, 0x95, 0xdf, - 0x4f, 0x1b, 0x8f, 0x06, 0x4c, 0x0e, 0xa7, 0x7d, 0xc5, 0x67, 0x7b, 0x5c, 0x8c, 0xb9, 0x88, 0x7f, - 0x76, 0x84, 0xff, 0xce, 0x56, 0x47, 0x8a, 0xf6, 0x6b, 0x16, 0x48, 0x27, 0x86, 0x93, 0xa7, 0x60, - 0x31, 0x93, 0x00, 0x55, 0x04, 0xde, 0x17, 0x18, 0x9e, 0xa0, 0xef, 0x0e, 0xa9, 0x18, 0x5a, 0x6b, - 0xfa, 0xc4, 0x0d, 0x96, 0x24, 0xe8, 0x20, 0xde, 0x7d, 0x41, 0xc5, 0x90, 0xbc, 0x84, 0x07, 0xcb, - 0x80, 0x18, 0x49, 0x0c, 0x03, 0x3a, 0x72, 0x87, 0xc8, 0x06, 0x43, 0x69, 0x15, 0x9b, 0xb9, 0x56, - 0xc1, 0x69, 0x5c, 0xe2, 0x78, 0x16, 0xc7, 0xbd, 0xd0, 0x61, 0xe4, 0x6b, 0xf8, 0x2c, 0xc3, 0xd6, - 0xa7, 0xa3, 0x11, 0x97, 0x2e, 0x0b, 0x7c, 0x8c, 0xac, 0x92, 0xbe, 0x45, 0x2d, 0x65, 0xd8, 0xd5, - 0x9b, 0x3d, 0xb5, 0x47, 0xf6, 0xa1, 0x99, 0x81, 0x1d, 0xb3, 0x80, 0x8e, 0xd8, 0x7b, 0xf4, 0x5d, - 0xa5, 0x9b, 0xe4, 0x06, 0xa0, 0x6f, 0xf0, 0x79, 0x8a, 0xdf, 0x4f, 0xa2, 0xde, 0xa0, 0xa4, 0xf1, - 0xf1, 0x0c, 0x36, 0xe7, 0x78, 0x2a, 0x19, 0x0f, 0x5c, 0x21, 0xa9, 0x9c, 0x0a, 0xab, 0xac, 0x0b, - 0xf4, 0xb8, 0x7d, 0xad, 0x26, 0xdb, 0x29, 0xab, 0xc6, 0xfe, 0xa0, 0xa1, 0x4e, 0x4d, 0x2e, 0xf1, - 0x6e, 0xff, 0xb2, 0x06, 0x77, 0x0f, 0xa6, 0xf2, 0x92, 0xe6, 0xb6, 0xa0, 0x18, 0xa2, 0x87, 0xec, - 0x24, 0x55, 0x5d, 0xba, 0x26, 0x5f, 0x41, 0x35, 0xb1, 0x8d, 0xf2, 0x7a, 0x89, 0xf0, 0x2a, 0x89, - 0x3f, 0x91, 0xde, 0x82, 0xba, 0xf2, 0x37, 0xaa, 0x6b, 0xae, 0xa3, 0xc2, 0x7f, 0xd3, 0x51, 0x07, - 0x36, 0x78, 0xfc, 0x2a, 0x55, 0x0a, 0x29, 0x84, 0x1b, 0xf0, 0xc0, 0x43, 0x2d, 0xdb, 0x82, 0x43, - 0x78, 0xfa, 0xe4, 0x23, 0x21, 0x5e, 0xa9, 0x9d, 0x8b, 0x90, 0x01, 0x15, 0xee, 0x88, 0x8d, 0x99, - 0x91, 0xf4, 0x02, 0xe4, 0x39, 0x15, 0x2f, 0xd5, 0xce, 0x32, 0xc8, 0x24, 0x64, 0x1e, 0xc6, 0x52, - 0x5d, 0x84, 0x1c, 0xaa, 0x1d, 0xd2, 0x82, 0x6a, 0x16, 0xa2, 0x85, 0x5d, 0xd4, 0xd1, 0xeb, 0xf3, - 0x68, 0xad, 0xe8, 0xa7, 0x60, 0x65, 0x23, 0x97, 0x88, 0x70, 0x63, 0x8e, 0xc8, 0xaa, 0xf0, 0x15, - 0x7c, 0x91, 0x05, 0x5e, 0xd9, 0x0b, 0x46, 0x89, 0xcd, 0x39, 0xc9, 0x15, 0xcd, 0x60, 0x43, 0xed, - 0xe2, 0x2b, 0xa7, 0x02, 0x7d, 0xab, 0xa6, 0xf1, 0x77, 0x16, 0x1e, 0xf9, 0x5a, 0xa0, 0x4f, 0x24, - 0x34, 0xb2, 0x00, 0x3c, 0x3e, 0x46, 0x4f, 0xb2, 0x13, 0xcc, 0x24, 0x68, 0x43, 0x97, 0xb7, 0x1d, - 0x97, 0xf7, 0xe1, 0x3f, 0x28, 0x6f, 0x2f, 0x90, 0xce, 0xbd, 0xf9, 0x59, 0xcf, 0x12, 0xd2, 0x34, - 0xb3, 0xdf, 0x5e, 0x77, 0xaa, 0xa9, 0xe4, 0xa6, 0xbe, 0xf1, 0x15, 0x2c, 0xa6, 0xa4, 0xf7, 0x01, - 0x94, 0x58, 0x26, 0xd3, 0xfe, 0x3b, 0x9c, 0xe9, 0x76, 0x2b, 0x39, 0x25, 0x29, 0xc4, 0xa1, 0x76, - 0x5c, 0xd3, 0x99, 0x9f, 0xfc, 0xdf, 0x9d, 0xf9, 0x6b, 0x1e, 0x2a, 0x7b, 0x0a, 0xa9, 0x7b, 0xe9, - 0x28, 0x52, 0x5d, 0x69, 0xc1, 0x9a, 0x17, 0x22, 0x95, 0x3c, 0x69, 0xca, 0x64, 0xa9, 0xe6, 0xb2, - 0x91, 0xc6, 0x2d, 0x33, 0x97, 0xf5, 0x82, 0xbc, 0x85, 0x92, 0x9e, 0x3d, 0xc7, 0x88, 0xc2, 0x4c, - 0xec, 0xdd, 0xbd, 0x7f, 0xd9, 0x52, 0x7f, 0x9d, 0x36, 0xaa, 0x33, 0x3a, 0x1e, 0x7d, 0xb3, 0x9d, - 0x32, 0x6d, 0x3b, 0x45, 0x65, 0xef, 0x23, 0x0a, 0xf2, 0x08, 0x2a, 0x21, 0x8e, 0xe8, 0x0c, 0x7d, - 0x77, 0x8c, 0x42, 0xd0, 0x01, 0x9a, 0xbf, 0x00, 0x67, 0x3d, 0x76, 0x7f, 0x6f, 0xbc, 0x64, 0x1f, - 0xca, 0x9e, 0x27, 0xa3, 0x24, 0x5d, 0x4a, 0xf3, 0xe5, 0xee, 0x97, 0x37, 0xa4, 0x2b, 0x4e, 0x10, - 0x28, 0xa4, 0xb1, 0xc9, 0x4f, 0x70, 0x27, 0x33, 0x63, 0x27, 0x7a, 0x60, 0xe9, 0x7e, 0x28, 0x77, - 0x3b, 0x37, 0xb0, 0x5d, 0xfe, 0x6b, 0x75, 0x2a, 0x6c, 0xd1, 0x47, 0xde, 0x02, 0xc9, 0xaa, 0x28, - 0xe6, 0x87, 0x66, 0xbe, 0x55, 0xee, 0x76, 0x6f, 0xe0, 0x5f, 0x32, 0x47, 0x9d, 0x2a, 0xbf, 0xe0, - 0xdc, 0xfd, 0xee, 0xc3, 0x59, 0x3d, 0xf7, 0xf1, 0xac, 0x9e, 0xfb, 0xe3, 0xac, 0x9e, 0xfb, 0xf9, - 0xbc, 0xbe, 0xf2, 0xf1, 0xbc, 0xbe, 0xf2, 0xdb, 0x79, 0x7d, 0xe5, 0x4d, 0x27, 0x53, 0x12, 0xc5, - 0xbf, 0x63, 0x3e, 0x20, 0x92, 0xa3, 0xec, 0xc8, 0xce, 0x7c, 0x56, 0xe8, 0x0a, 0xf5, 0x57, 0xf5, - 0x87, 0xc3, 0xe3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x77, 0x00, 0xe1, 0x29, 0xca, 0x08, 0x00, - 0x00, -} - -func (m *InboundTxParamsV14) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *InboundTxParamsV14) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *InboundTxParamsV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.TxFinalizationStatus != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.TxFinalizationStatus)) - i-- - dAtA[i] = 0x58 - } - if m.InboundTxFinalizedZetaHeight != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.InboundTxFinalizedZetaHeight)) - i-- - dAtA[i] = 0x50 - } - if len(m.InboundTxBallotIndex) > 0 { - i -= len(m.InboundTxBallotIndex) - copy(dAtA[i:], m.InboundTxBallotIndex) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.InboundTxBallotIndex))) - i-- - dAtA[i] = 0x4a - } - if m.InboundTxObservedExternalHeight != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.InboundTxObservedExternalHeight)) - i-- - dAtA[i] = 0x40 - } - if len(m.InboundTxObservedHash) > 0 { - i -= len(m.InboundTxObservedHash) - copy(dAtA[i:], m.InboundTxObservedHash) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.InboundTxObservedHash))) - i-- - dAtA[i] = 0x3a - } - { - size := m.Amount.Size() - i -= size - if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 - if len(m.Asset) > 0 { - i -= len(m.Asset) - copy(dAtA[i:], m.Asset) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Asset))) - i-- - dAtA[i] = 0x2a - } - if m.CoinType != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.CoinType)) - i-- - dAtA[i] = 0x20 - } - if len(m.TxOrigin) > 0 { - i -= len(m.TxOrigin) - copy(dAtA[i:], m.TxOrigin) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.TxOrigin))) - i-- - dAtA[i] = 0x1a - } - if m.SenderChainId != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.SenderChainId)) - i-- - dAtA[i] = 0x10 - } - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *OutboundTxParamsV14) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *OutboundTxParamsV14) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *OutboundTxParamsV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.OutboundTxEffectiveGasLimit != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxEffectiveGasLimit)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0xb0 - } - { - size := m.OutboundTxEffectiveGasPrice.Size() - i -= size - if _, err := m.OutboundTxEffectiveGasPrice.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0xaa - if m.OutboundTxGasUsed != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxGasUsed)) - i-- - dAtA[i] = 0x1 - i-- - dAtA[i] = 0xa0 - } - if m.TxFinalizationStatus != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.TxFinalizationStatus)) - i-- - dAtA[i] = 0x60 - } - if len(m.TssPubkey) > 0 { - i -= len(m.TssPubkey) - copy(dAtA[i:], m.TssPubkey) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.TssPubkey))) - i-- - dAtA[i] = 0x5a - } - if m.OutboundTxObservedExternalHeight != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxObservedExternalHeight)) - i-- - dAtA[i] = 0x50 - } - if len(m.OutboundTxBallotIndex) > 0 { - i -= len(m.OutboundTxBallotIndex) - copy(dAtA[i:], m.OutboundTxBallotIndex) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxBallotIndex))) - i-- - dAtA[i] = 0x4a - } - if len(m.OutboundTxHash) > 0 { - i -= len(m.OutboundTxHash) - copy(dAtA[i:], m.OutboundTxHash) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxHash))) - i-- - dAtA[i] = 0x42 - } - if len(m.OutboundTxGasPrice) > 0 { - i -= len(m.OutboundTxGasPrice) - copy(dAtA[i:], m.OutboundTxGasPrice) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.OutboundTxGasPrice))) - i-- - dAtA[i] = 0x3a - } - if m.OutboundTxGasLimit != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxGasLimit)) - i-- - dAtA[i] = 0x30 - } - if m.OutboundTxTssNonce != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.OutboundTxTssNonce)) - i-- - dAtA[i] = 0x28 - } - { - size := m.Amount.Size() - i -= size - if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - if m.CoinType != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.CoinType)) - i-- - dAtA[i] = 0x18 - } - if m.ReceiverChainId != 0 { - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(m.ReceiverChainId)) - i-- - dAtA[i] = 0x10 - } - if len(m.Receiver) > 0 { - i -= len(m.Receiver) - copy(dAtA[i:], m.Receiver) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Receiver))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *CrossChainTxV14) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *CrossChainTxV14) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *CrossChainTxV14) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.OutboundTxParams) > 0 { - for iNdEx := len(m.OutboundTxParams) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.OutboundTxParams[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x52 - } - } - if m.InboundTxParams != nil { - { - size, err := m.InboundTxParams.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } - if m.CctxStatus != nil { - { - size, err := m.CctxStatus.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x42 - } - if len(m.RelayedMessage) > 0 { - i -= len(m.RelayedMessage) - copy(dAtA[i:], m.RelayedMessage) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.RelayedMessage))) - i-- - dAtA[i] = 0x32 - } - { - size := m.ZetaFees.Size() - i -= size - if _, err := m.ZetaFees.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x2a - if len(m.Index) > 0 { - i -= len(m.Index) - copy(dAtA[i:], m.Index) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Index))) - i-- - dAtA[i] = 0x12 - } - if len(m.Creator) > 0 { - i -= len(m.Creator) - copy(dAtA[i:], m.Creator) - i = encodeVarintCrossChainTxV14(dAtA, i, uint64(len(m.Creator))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintCrossChainTxV14(dAtA []byte, offset int, v uint64) int { - offset -= sovCrossChainTxV14(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *InboundTxParamsV14) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.SenderChainId != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.SenderChainId)) - } - l = len(m.TxOrigin) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.CoinType != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.CoinType)) - } - l = len(m.Asset) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - l = len(m.InboundTxObservedHash) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.InboundTxObservedExternalHeight != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.InboundTxObservedExternalHeight)) - } - l = len(m.InboundTxBallotIndex) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.InboundTxFinalizedZetaHeight != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.InboundTxFinalizedZetaHeight)) - } - if m.TxFinalizationStatus != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.TxFinalizationStatus)) - } - return n -} - -func (m *OutboundTxParamsV14) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Receiver) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.ReceiverChainId != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.ReceiverChainId)) - } - if m.CoinType != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.CoinType)) - } - l = m.Amount.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - if m.OutboundTxTssNonce != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxTssNonce)) - } - if m.OutboundTxGasLimit != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxGasLimit)) - } - l = len(m.OutboundTxGasPrice) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - l = len(m.OutboundTxHash) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - l = len(m.OutboundTxBallotIndex) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.OutboundTxObservedExternalHeight != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.OutboundTxObservedExternalHeight)) - } - l = len(m.TssPubkey) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.TxFinalizationStatus != 0 { - n += 1 + sovCrossChainTxV14(uint64(m.TxFinalizationStatus)) - } - if m.OutboundTxGasUsed != 0 { - n += 2 + sovCrossChainTxV14(uint64(m.OutboundTxGasUsed)) - } - l = m.OutboundTxEffectiveGasPrice.Size() - n += 2 + l + sovCrossChainTxV14(uint64(l)) - if m.OutboundTxEffectiveGasLimit != 0 { - n += 2 + sovCrossChainTxV14(uint64(m.OutboundTxEffectiveGasLimit)) - } - return n -} - -func (m *CrossChainTxV14) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - l = len(m.Index) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - l = m.ZetaFees.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - l = len(m.RelayedMessage) - if l > 0 { - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.CctxStatus != nil { - l = m.CctxStatus.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if m.InboundTxParams != nil { - l = m.InboundTxParams.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - if len(m.OutboundTxParams) > 0 { - for _, e := range m.OutboundTxParams { - l = e.Size() - n += 1 + l + sovCrossChainTxV14(uint64(l)) - } - } - return n -} - -func sovCrossChainTxV14(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozCrossChainTxV14(x uint64) (n int) { - return sovCrossChainTxV14(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *InboundTxParamsV14) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: InboundTxParamsV14: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: InboundTxParamsV14: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SenderChainId", wireType) - } - m.SenderChainId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SenderChainId |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TxOrigin", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TxOrigin = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) - } - m.CoinType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CoinType |= common.CoinType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Asset = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InboundTxObservedHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.InboundTxObservedHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field InboundTxObservedExternalHeight", wireType) - } - m.InboundTxObservedExternalHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.InboundTxObservedExternalHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InboundTxBallotIndex", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.InboundTxBallotIndex = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field InboundTxFinalizedZetaHeight", wireType) - } - m.InboundTxFinalizedZetaHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.InboundTxFinalizedZetaHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) - } - m.TxFinalizationStatus = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *OutboundTxParamsV14) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: OutboundTxParamsV14: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: OutboundTxParamsV14: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ReceiverChainId", wireType) - } - m.ReceiverChainId = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ReceiverChainId |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) - } - m.CoinType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.CoinType |= common.CoinType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxTssNonce", wireType) - } - m.OutboundTxTssNonce = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OutboundTxTssNonce |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasLimit", wireType) - } - m.OutboundTxGasLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OutboundTxGasLimit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OutboundTxGasPrice = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OutboundTxHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxBallotIndex", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OutboundTxBallotIndex = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxObservedExternalHeight", wireType) - } - m.OutboundTxObservedExternalHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OutboundTxObservedExternalHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TssPubkey", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TssPubkey = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 12: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) - } - m.TxFinalizationStatus = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 20: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasUsed", wireType) - } - m.OutboundTxGasUsed = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OutboundTxGasUsed |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 21: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxEffectiveGasPrice", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.OutboundTxEffectiveGasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 22: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxEffectiveGasLimit", wireType) - } - m.OutboundTxEffectiveGasLimit = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OutboundTxEffectiveGasLimit |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *CrossChainTxV14) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: CrossChainTxV14: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: CrossChainTxV14: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Index = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ZetaFees", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.ZetaFees.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RelayedMessage", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RelayedMessage = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CctxStatus", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.CctxStatus == nil { - m.CctxStatus = &Status{} - } - if err := m.CctxStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InboundTxParams", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.InboundTxParams == nil { - m.InboundTxParams = &InboundTxParamsV14{} - } - if err := m.InboundTxParams.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxParams", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.OutboundTxParams = append(m.OutboundTxParams, &OutboundTxParamsV14{}) - if err := m.OutboundTxParams[len(m.OutboundTxParams)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipCrossChainTxV14(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthCrossChainTxV14 - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipCrossChainTxV14(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowCrossChainTxV14 - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthCrossChainTxV14 - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupCrossChainTxV14 - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthCrossChainTxV14 - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthCrossChainTxV14 = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowCrossChainTxV14 = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupCrossChainTxV14 = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 62720aaf66..bfdef64cc2 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -41,4 +41,6 @@ var ( ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") + + ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1151, "invalid cctx index") ) diff --git a/zetaclient/bitcoin/bitcoin_signer.go b/zetaclient/bitcoin/bitcoin_signer.go index f250805a8f..90b6b48d3e 100644 --- a/zetaclient/bitcoin/bitcoin_signer.go +++ b/zetaclient/bitcoin/bitcoin_signer.go @@ -259,7 +259,8 @@ func (signer *BTCSigner) TryProcessOutTx( Logger() params := cctx.GetCurrentOutTxParam() - if cctx.CoinType == common.CoinType_Zeta || cctx.CoinType == common.CoinType_ERC20 { + coinType := cctx.InboundTxParams.CoinType + if coinType == common.CoinType_Zeta || coinType == common.CoinType_ERC20 { logger.Error().Msgf("BTC TryProcessOutTx: can only send BTC to a BTC network") return } diff --git a/zetaclient/evm/evm_client.go b/zetaclient/evm/evm_client.go index 443510f545..1580464245 100644 --- a/zetaclient/evm/evm_client.go +++ b/zetaclient/evm/evm_client.go @@ -314,7 +314,7 @@ func (ob *ChainClient) Stop() { // If isConfirmed, it also post to ZetaCore func (ob *ChainClient) IsSendOutTxProcessed(cctx *crosschaintypes.CrossChainTx, logger zerolog.Logger) (bool, bool, error) { sendHash := cctx.Index - cointype := cctx.CoinType + cointype := cctx.InboundTxParams.CoinType nonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce // skip if outtx is not confirmed diff --git a/zetaclient/evm/evm_signer.go b/zetaclient/evm/evm_signer.go index 474864c246..f77bc343f9 100644 --- a/zetaclient/evm/evm_signer.go +++ b/zetaclient/evm/evm_signer.go @@ -324,13 +324,13 @@ func (signer *Signer) TryProcessOutTx( // compliance check goes first if clientcommon.IsCctxRestricted(cctx) { clientcommon.PrintComplianceLog(logger, signer.logger.Compliance, - true, evmClient.chain.ChainId, cctx.Index, cctx.InboundTxParams.Sender, txData.to.Hex(), cctx.CoinType.String()) + true, evmClient.chain.ChainId, cctx.Index, cctx.InboundTxParams.Sender, txData.to.Hex(), cctx.InboundTxParams.CoinType.String()) tx, err = signer.SignCancelTx(txData.nonce, txData.gasPrice, height) // cancel the tx if err != nil { logger.Warn().Err(err).Msg(SignerErrorMsg(cctx)) return } - } else if cctx.CoinType == common.CoinType_Cmd { // admin command + } else if cctx.InboundTxParams.CoinType == common.CoinType_Cmd { // admin command to := ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver) if to == (ethcommon.Address{}) { logger.Error().Msgf("invalid receiver %s", cctx.GetCurrentOutTxParam().Receiver) @@ -353,7 +353,7 @@ func (signer *Signer) TryProcessOutTx( return } } else if IsSenderZetaChain(cctx, zetaBridge, &crossChainflags) { - switch cctx.CoinType { + switch cctx.InboundTxParams.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) @@ -369,7 +369,7 @@ func (signer *Signer) TryProcessOutTx( return } } else if cctx.CctxStatus.Status == types.CctxStatus_PendingRevert && cctx.OutboundTxParams[0].ReceiverChainId == zetaBridge.ZetaChain().ChainId { - switch cctx.CoinType { + switch cctx.InboundTxParams.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) diff --git a/zetaclient/evm/outbound_transaction_data.go b/zetaclient/evm/outbound_transaction_data.go index 544d8c0503..b595dd42c5 100644 --- a/zetaclient/evm/outbound_transaction_data.go +++ b/zetaclient/evm/outbound_transaction_data.go @@ -169,7 +169,7 @@ func NewOutBoundTransactionData( } // Base64 decode message - if cctx.CoinType != common.CoinType_Cmd { + if cctx.InboundTxParams.CoinType != common.CoinType_Cmd { txData.message, err = base64.StdEncoding.DecodeString(cctx.RelayedMessage) if err != nil { logger.Err(err).Msgf("decode CCTX.Message %s error", cctx.RelayedMessage) diff --git a/zetaclient/supplychecker/zeta_supply_checker.go b/zetaclient/supplychecker/zeta_supply_checker.go index d69cb28c54..0206b27f21 100644 --- a/zetaclient/supplychecker/zeta_supply_checker.go +++ b/zetaclient/supplychecker/zeta_supply_checker.go @@ -246,7 +246,7 @@ func (zs *ZetaSupplyChecker) GetPendingCCTXInTransit(receivingChains []common.Ch } nonceToCctxMap := make(map[uint64]*types.CrossChainTx) for _, c := range cctx { - if c.CoinType == common.CoinType_Zeta { + if c.InboundTxParams.CoinType == common.CoinType_Zeta { nonceToCctxMap[c.GetCurrentOutTxParam().OutboundTxTssNonce] = c } } From 267dbcec692ccc83168defeb962e28e520223d06 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 18 Mar 2024 17:55:39 -0400 Subject: [PATCH 24/36] modify changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index f1cefeb587..619c29db36 100644 --- a/changelog.md +++ b/changelog.md @@ -3,7 +3,7 @@ ## Unreleased ### Refactor -* [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx . Refactor CCTX struct to remove duplicate CoinType +* [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx and vote outbound tx ## Version: v14 From 34da80fb6fd28845eef258c65c67138e78894df2 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 20 Mar 2024 14:53:46 -0400 Subject: [PATCH 25/36] add tests for types package --- x/crosschain/keeper/evm_hooks.go | 8 +- .../keeper/msg_server_migrate_tss_funds.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 100 +------ .../keeper/msg_server_vote_inbound_tx_test.go | 62 +---- .../keeper/msg_server_vote_outbound_tx.go | 49 +--- .../msg_server_vote_outbound_tx_test.go | 75 ------ .../keeper/msg_server_whitelist_erc20.go | 2 +- x/crosschain/types/cctx.go | 189 +++++++++++++ x/crosschain/types/cctx_test.go | 252 ++++++++++++++++++ x/crosschain/types/cctx_utils.go | 210 --------------- x/crosschain/types/cctx_utils_test.go | 183 ------------- x/crosschain/types/inbound_params.go | 42 +++ x/crosschain/types/inbound_params_test.go | 43 +++ x/crosschain/types/outbound_params.go | 47 ++++ x/crosschain/types/outbound_params_test.go | 48 ++++ x/crosschain/types/utils.go | 77 ++++++ x/crosschain/types/utils_test.go | 40 +++ 17 files changed, 772 insertions(+), 657 deletions(-) create mode 100644 x/crosschain/types/cctx.go create mode 100644 x/crosschain/types/cctx_test.go delete mode 100644 x/crosschain/types/cctx_utils.go delete mode 100644 x/crosschain/types/cctx_utils_test.go create mode 100644 x/crosschain/types/inbound_params.go create mode 100644 x/crosschain/types/inbound_params_test.go create mode 100644 x/crosschain/types/outbound_params.go create mode 100644 x/crosschain/types/outbound_params_test.go create mode 100644 x/crosschain/types/utils.go create mode 100644 x/crosschain/types/utils_test.go diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index d4b916d215..57b6c376f9 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -170,9 +170,9 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W ) sendHash := msg.Digest() - cctx := CreateNewCCTX( + cctx := types.CreateNewCCTX( ctx, - msg, + *msg, sendHash, tss.TssPubkey, types.CctxStatus_PendingOutbound, @@ -249,9 +249,9 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC sendHash := msg.Digest() // Create the CCTX - cctx := CreateNewCCTX( + cctx := types.CreateNewCCTX( ctx, - msg, + *msg, sendHash, tss.TssPubkey, types.CctxStatus_PendingOutbound, diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 3a76462b4f..9cba4f8c24 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -79,7 +79,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() - // TODO : Use the `CreateNewCctx` function to create the cctx + // TODO : Use the `GetInbound` method to create the cctx // https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: "", diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 6a78d66844..d9ee59548e 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -5,7 +5,6 @@ import ( "fmt" cosmoserrors "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" @@ -90,8 +89,11 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if !finalized { return &types.MsgVoteOnObservedInboundTxResponse{}, nil } - - inboundCctx := k.GetInbound(ctx, msg) + tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) + if !tssFound { + return nil, types.ErrCannotFindTSSKeys + } + inboundCctx := types.GetInbound(ctx, *msg, tss.TssPubkey) err = inboundCctx.Validate() if err != nil { return nil, err @@ -102,73 +104,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg } // GetInbound returns a new CCTX from a given inbound message. -func (k Keeper) GetInbound(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx) types.CrossChainTx { - - // get the latest TSS to set the TSS public key in the CCTX - tssPub := "" - tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) - if tssFound { - tssPub = tss.TssPubkey - } - return CreateNewCCTX(ctx, msg, msg.Digest(), tssPub, types.CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) -} - -// CreateNewCCTX creates a new CCTX with the given parameters. -func CreateNewCCTX( - ctx sdk.Context, - msg *types.MsgVoteOnObservedInboundTx, - index string, - tssPubkey string, - s types.CctxStatus, - senderChainID, - receiverChainID int64, -) types.CrossChainTx { - if msg.TxOrigin == "" { - msg.TxOrigin = msg.Sender - } - inboundParams := &types.InboundTxParams{ - Sender: msg.Sender, - SenderChainId: senderChainID, - TxOrigin: msg.TxOrigin, - Asset: msg.Asset, - Amount: msg.Amount, - InboundTxObservedHash: msg.InTxHash, - InboundTxObservedExternalHeight: msg.InBlockHeight, - InboundTxFinalizedZetaHeight: 0, - InboundTxBallotIndex: index, - CoinType: msg.CoinType, - } - - outBoundParams := &types.OutboundTxParams{ - Receiver: msg.Receiver, - ReceiverChainId: receiverChainID, - OutboundTxHash: "", - OutboundTxTssNonce: 0, - OutboundTxGasLimit: msg.GasLimit, - OutboundTxGasPrice: "", - OutboundTxBallotIndex: "", - OutboundTxObservedExternalHeight: 0, - Amount: sdkmath.ZeroUint(), - TssPubkey: tssPubkey, - CoinType: msg.CoinType, - } - status := &types.Status{ - Status: s, - StatusMessage: "", - LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), - IsAbortRefunded: false, - } - newCctx := types.CrossChainTx{ - Creator: msg.Creator, - Index: index, - ZetaFees: sdkmath.ZeroUint(), - RelayedMessage: msg.Message, - CctxStatus: status, - InboundTxParams: inboundParams, - OutboundTxParams: []*types.OutboundTxParams{outBoundParams}, - } - return newCctx -} // ProcessInbound processes the inbound CCTX. // It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. @@ -193,19 +128,19 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.SetAbort(err.Error()) return } else if err != nil && isContractReverted { // contract call reverted; should refund revertMessage := err.Error() senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) if senderChain == nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "invalid sender chain") + cctx.SetAbort(fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId)) return } gasLimit, err := k.GetRevertGasLimit(ctx, cctx) if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("can't get revert tx gas limit,%s", err.Error())) + cctx.SetAbort(fmt.Sprintf("revert gas limit error: %s", err.Error())) return } if gasLimit == 0 { @@ -213,14 +148,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit } - // create new OutboundTxParams for the revert - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - OutboundTxGasLimit: gasLimit, - } - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) + cctx.AddRevertOutbound(gasLimit) // we create a new cached context, and we don't commit the previous one with EVM deposit tmpCtxRevert, commitRevert := ctx.CacheContext() @@ -239,16 +167,16 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) }() if err != nil { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) + cctx.SetAbort(fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) return } commitRevert() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) + cctx.SetPendingRevert(revertMessage) return } // successful HandleEVMDeposit; commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "Remote omnichain contract call completed") + cctx.SetOutBoundMined("Remote omnichain contract call completed") return } @@ -275,11 +203,11 @@ func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossCh }() if err != nil { // do not commit anything here as the CCTX should be aborted - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.SetAbort(err.Error()) return } commit() - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingOutbound, "") + cctx.SetPendingOutbound("") return } diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 3b27ebb1a0..c1c5526b4f 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -56,6 +56,8 @@ func TestKeeper_VoteOnObservedInboundTx(t *testing.T) { to = chain.ChainId } } + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + msg := sample.InboundVote(0, from, to) for _, validatorAddr := range validatorList { msg.Creator = validatorAddr @@ -102,6 +104,9 @@ func TestKeeper_VoteOnObservedInboundTx(t *testing.T) { ObserverList: []string{validatorAddr}, }) + // Add tss to the observer keeper + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + // Vote on the FIRST message. msg := &types.MsgVoteOnObservedInboundTx{ Creator: validatorAddr, @@ -283,7 +288,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, "invalid sender chain", cctx.CctxStatus.StatusMessage) + require.Equal(t, fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId), cctx.CctxStatus.StatusMessage) }) t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { @@ -315,7 +320,7 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) k.ProcessZEVMDeposit(ctx, cctx) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("can't get revert tx gas limit,%s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) + require.Equal(t, fmt.Sprintf("revert gas limit error: %s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) }) t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { @@ -510,59 +515,6 @@ func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { }) } -func TestKeeper_GetInbound(t *testing.T) { - t.Run("should return a cctx with correct values", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - senderChain := getValidEthChain(t) - sender := sample.EthAddress() - receiverChain := getValidEthChain(t) - receiver := sample.EthAddress() - creator := sample.AccAddress() - amount := sdkmath.NewUint(42) - message := "test" - intxBlockHeight := uint64(420) - intxHash := sample.Hash() - gasLimit := uint64(100) - asset := "test-asset" - eventIndex := uint64(1) - cointType := common.CoinType_ERC20 - tss := sample.Tss() - msg := types.MsgVoteOnObservedInboundTx{ - Creator: creator, - Sender: sender.String(), - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InTxHash: intxHash.String(), - InBlockHeight: intxBlockHeight, - GasLimit: gasLimit, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, - } - zk.ObserverKeeper.SetTSS(ctx, tss) - cctx := k.GetInbound(ctx, &msg) - require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) - require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) - require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) - require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) - require.Equal(t, amount, cctx.GetInboundTxParams().Amount) - require.Equal(t, message, cctx.RelayedMessage) - require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) - require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) - require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) - require.Equal(t, asset, cctx.GetInboundTxParams().Asset) - require.Equal(t, cointType, cctx.InboundTxParams.CoinType) - require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) - require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) - require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) - }) -} - func TestKeeper_SaveInbound(t *testing.T) { t.Run("should save the cctx", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 09c2cd2cfc..5eb81fd21e 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -86,7 +86,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms } // if ballot successful, the value received should be the out tx amount - err = SetOutboundValues(ctx, &cctx, *msg, ballot.BallotStatus) + err = cctx.AddOutbound(ctx, *msg, ballot.BallotStatus) if err != nil { return nil, err } @@ -106,45 +106,10 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } -// SetRevertOutboundValues does the following things in one function: +// AddRevertOutbound does the following things in one function: // 1. create a new OutboundTxParams for the revert // 2. append the new OutboundTxParams to the current OutboundTxParams // 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. -func SetRevertOutboundValues(cctx *types.CrossChainTx, gasLimit uint64) { - revertTxParams := &types.OutboundTxParams{ - Receiver: cctx.InboundTxParams.Sender, - ReceiverChainId: cctx.InboundTxParams.SenderChainId, - Amount: cctx.InboundTxParams.Amount, - OutboundTxGasLimit: gasLimit, - TssPubkey: cctx.GetCurrentOutTxParam().TssPubkey, - } - // The original outbound has been finalized, the new outbound is pending - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.OutboundTxParams = append(cctx.OutboundTxParams, revertTxParams) -} - -// SetOutboundValues sets the required values for the outbound transaction -// Note: It expects the cctx to already have been created, -// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer -func SetOutboundValues(ctx sdk.Context, cctx *types.CrossChainTx, msg types.MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { - if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { - if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { - ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", - msg.ValueReceived, - cctx.GetCurrentOutTxParam().Amount)) - return cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, cctx.GetCurrentOutTxParam().Amount)) - } - } - // Update CCTX values - cctx.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash - cctx.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice - cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit - cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight - cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() - - return nil -} // FundStabilityPool funds the stability pool with the remaining fees of an outbound tx // The funds are sent to the gas stability pool associated with the receiver chain @@ -199,9 +164,9 @@ func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChai oldStatus := cctx.CctxStatus.Status switch oldStatus { case types.CctxStatus_PendingRevert: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") + cctx.SetReverted("Outbound succeeded, revert executed") case types.CctxStatus_PendingOutbound: - cctx.CctxStatus.ChangeStatus(types.CctxStatus_OutboundMined, "") + cctx.SetOutBoundMined("Outbound succeeded, mined") default: return } @@ -235,7 +200,7 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, } // create new OutboundTxParams for the revert - SetRevertOutboundValues(cctx, gasLimit) + cctx.AddRevertOutbound(gasLimit) err = k.PayGasAndUpdateCctx( ctx, @@ -252,10 +217,10 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, return err } // Not setting the finalization status here, the required changes have been mad while creating the revert tx - cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, "Outbound failed, start revert") + cctx.SetPendingRevert("Outbound failed, start revert") case types.CctxStatus_PendingRevert: cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "Outbound failed: revert failed; abort TX") + cctx.SetAbort("Outbound failed: revert failed; abort TX") } } newStatus := cctx.CctxStatus.Status.String() diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 1b35b832a6..2812ad32f0 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -441,68 +441,6 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { }) } -func TestKeeper_GetOutbound(t *testing.T) { - t.Run("successfully get outbound tx", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ValueReceived: cctx.GetCurrentOutTxParam().Amount, - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: math.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, math.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) - require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) - }) - - t.Run("successfully get outbound tx for failed ballot without amount check", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: math.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_FailureObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, math.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) - require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) - }) - - t.Run("failed to get outbound tx if amount does not match value received", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - - cctx := sample.CrossChainTx(t, "test") - hash := sample.Hash().String() - - err := keeper.SetOutboundValues(ctx, cctx, types.MsgVoteOnObservedOutboundTx{ - ValueReceived: math.NewUint(100), - ObservedOutTxHash: hash, - ObservedOutTxBlockHeight: 10, - ObservedOutTxGasUsed: 100, - ObservedOutTxEffectiveGasPrice: math.NewInt(100), - ObservedOutTxEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - }) -} - func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) cctx := sample.CrossChainTx(t, "test") @@ -831,19 +769,6 @@ func TestKeeper_SaveOutbound(t *testing.T) { }) } -func Test_SetRevertOutboundValues(t *testing.T) { - cctx := sample.CrossChainTx(t, "test") - cctx.OutboundTxParams = cctx.OutboundTxParams[:1] - keeper.SetRevertOutboundValues(cctx, 100) - require.Len(t, cctx.OutboundTxParams, 2) - require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) - require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) - require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) -} - func TestKeeper_ValidateOutboundMessage(t *testing.T) { t.Run("successfully validate outbound message", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index efd79e7f28..c0d713b6c1 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -111,7 +111,7 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist index := hash.Hex() // create a cmd cctx to whitelist the erc20 on the external chain - // TODO : refactor this to use the `CreateNewCCTX` function instead. + // TODO : refactor this to use the `GetInbound` function instead. //https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: msg.Creator, diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go new file mode 100644 index 0000000000..f6a7e4de9a --- /dev/null +++ b/x/crosschain/types/cctx.go @@ -0,0 +1,189 @@ +package types + +import ( + "fmt" + + cosmoserrors "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// GetCurrentOutTxParam returns the current outbound tx params. +// There can only be one active outtx. +// OutboundTxParams[0] is the original outtx, if it reverts, then +// OutboundTxParams[1] is the new outtx. +func (m CrossChainTx) GetCurrentOutTxParam() *OutboundTxParams { + if len(m.OutboundTxParams) == 0 { + return &OutboundTxParams{} + } + return m.OutboundTxParams[len(m.OutboundTxParams)-1] +} + +// IsCurrentOutTxRevert returns true if the current outbound tx is the revert tx. +func (m CrossChainTx) IsCurrentOutTxRevert() bool { + return len(m.OutboundTxParams) == 2 +} + +// OriginalDestinationChainID returns the original destination of the outbound tx, reverted or not +// If there is no outbound tx, return -1 +func (m CrossChainTx) OriginalDestinationChainID() int64 { + if len(m.OutboundTxParams) == 0 { + return -1 + } + return m.OutboundTxParams[0].ReceiverChainId +} + +// GetAllAuthzZetaclientTxTypes returns all the authz types for zetaclient + +func (m CrossChainTx) Validate() error { + if m.InboundTxParams == nil { + return fmt.Errorf("inbound tx params cannot be nil") + } + if m.OutboundTxParams == nil { + return fmt.Errorf("outbound tx params cannot be nil") + } + if m.CctxStatus == nil { + return fmt.Errorf("cctx status cannot be nil") + } + if len(m.OutboundTxParams) > 2 { + return fmt.Errorf("outbound tx params cannot be more than 2") + } + if m.Index != "" { + err := ValidateZetaIndex(m.Index) + if err != nil { + return err + } + } + err := m.InboundTxParams.Validate() + if err != nil { + return err + } + for _, outboundTxParam := range m.OutboundTxParams { + err = outboundTxParam.Validate() + if err != nil { + return err + } + } + return nil +} + +func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) { + revertTxParams := &OutboundTxParams{ + Receiver: m.InboundTxParams.Sender, + ReceiverChainId: m.InboundTxParams.SenderChainId, + Amount: m.InboundTxParams.Amount, + OutboundTxGasLimit: gasLimit, + TssPubkey: m.GetCurrentOutTxParam().TssPubkey, + } + // The original outbound has been finalized, the new outbound is pending + m.GetCurrentOutTxParam().TxFinalizationStatus = TxFinalizationStatus_Executed + m.OutboundTxParams = append(m.OutboundTxParams, revertTxParams) +} + +// AddOutbound sets the required values for the outbound transaction +// Note: It expects the cctx to already have been created, +// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer +func (m *CrossChainTx) AddOutbound(ctx sdk.Context, msg MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { + if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { + if !msg.ValueReceived.Equal(m.GetCurrentOutTxParam().Amount) { + ctx.Logger().Error(fmt.Sprintf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", + msg.ValueReceived, + m.GetCurrentOutTxParam().Amount)) + return cosmoserrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("ValueReceived %s does not match sent value %s", msg.ValueReceived, m.GetCurrentOutTxParam().Amount)) + } + } + // Update CCTX values + m.GetCurrentOutTxParam().OutboundTxHash = msg.ObservedOutTxHash + m.GetCurrentOutTxParam().OutboundTxGasUsed = msg.ObservedOutTxGasUsed + m.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice = msg.ObservedOutTxEffectiveGasPrice + m.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit + m.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight + m.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() + + return nil +} + +// SetAbort sets the CCTX status to Aborted with the given error message. +func (m CrossChainTx) SetAbort(message string) { + m.CctxStatus.ChangeStatus(CctxStatus_Aborted, message) +} + +// SetPendingRevert sets the CCTX status to PendingRevert with the given error message. +func (m CrossChainTx) SetPendingRevert(message string) { + m.CctxStatus.ChangeStatus(CctxStatus_PendingRevert, message) +} + +func (m CrossChainTx) SetPendingOutbound(message string) { + m.CctxStatus.ChangeStatus(CctxStatus_PendingOutbound, message) +} + +func (m CrossChainTx) SetOutBoundMined(message string) { + m.CctxStatus.ChangeStatus(CctxStatus_OutboundMined, message) +} + +func (m CrossChainTx) SetReverted(message string) { + m.CctxStatus.ChangeStatus(CctxStatus_Reverted, message) +} + +func GetInbound(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) CrossChainTx { + return CreateNewCCTX(ctx, msg, msg.Digest(), tssPubkey, CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) +} + +// CreateNewCCTX creates a new CCTX with the given parameters. +func CreateNewCCTX( + ctx sdk.Context, + msg MsgVoteOnObservedInboundTx, + index string, + tssPubkey string, + s CctxStatus, + senderChainID, + receiverChainID int64, +) CrossChainTx { + if msg.TxOrigin == "" { + msg.TxOrigin = msg.Sender + } + inboundParams := &InboundTxParams{ + Sender: msg.Sender, + SenderChainId: senderChainID, + TxOrigin: msg.TxOrigin, + Asset: msg.Asset, + Amount: msg.Amount, + InboundTxObservedHash: msg.InTxHash, + InboundTxObservedExternalHeight: msg.InBlockHeight, + InboundTxFinalizedZetaHeight: 0, + InboundTxBallotIndex: index, + CoinType: msg.CoinType, + } + + outBoundParams := &OutboundTxParams{ + Receiver: msg.Receiver, + ReceiverChainId: receiverChainID, + OutboundTxHash: "", + OutboundTxTssNonce: 0, + OutboundTxGasLimit: msg.GasLimit, + OutboundTxGasPrice: "", + OutboundTxBallotIndex: "", + OutboundTxObservedExternalHeight: 0, + Amount: sdkmath.ZeroUint(), + TssPubkey: tssPubkey, + CoinType: msg.CoinType, + } + status := &Status{ + Status: s, + StatusMessage: "", + LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), + IsAbortRefunded: false, + } + newCctx := CrossChainTx{ + Creator: msg.Creator, + Index: index, + ZetaFees: sdkmath.ZeroUint(), + RelayedMessage: msg.Message, + CctxStatus: status, + InboundTxParams: inboundParams, + OutboundTxParams: []*OutboundTxParams{outBoundParams}, + } + return newCctx +} diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go new file mode 100644 index 0000000000..41aa9f31db --- /dev/null +++ b/x/crosschain/types/cctx_test.go @@ -0,0 +1,252 @@ +package types_test + +import ( + "math/rand" + "testing" + + sdkmath "cosmossdk.io/math" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestCrossChainTx_Validate(t *testing.T) { + cctx := sample.CrossChainTx(t, "foo") + cctx.InboundTxParams = nil + require.ErrorContains(t, cctx.Validate(), "inbound tx params cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = nil + require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.CctxStatus = nil + require.ErrorContains(t, cctx.Validate(), "cctx status cannot be nil") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = make([]*types.OutboundTxParams, 3) + require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be more than 2") + cctx = sample.CrossChainTx(t, "foo") + cctx.Index = "0" + require.ErrorContains(t, cctx.Validate(), "invalid index hash 0") + cctx = sample.CrossChainTx(t, "foo") + cctx.InboundTxParams = sample.InboundTxParamsValidChainID(rand.New(rand.NewSource(42))) + cctx.InboundTxParams.SenderChainId = 1000 + require.ErrorContains(t, cctx.Validate(), "invalid sender chain id 1000") + cctx = sample.CrossChainTx(t, "foo") + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParamsValidChainID(rand.New(rand.NewSource(42)))} + cctx.InboundTxParams = sample.InboundTxParamsValidChainID(rand.New(rand.NewSource(42))) + cctx.InboundTxParams.InboundTxObservedHash = sample.Hash().String() + cctx.InboundTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) + cctx.OutboundTxParams[0].ReceiverChainId = 1000 + require.ErrorContains(t, cctx.Validate(), "invalid receiver chain id 1000") +} + +func TestCrossChainTx_GetCurrentOutTxParam(t *testing.T) { + r := rand.New(rand.NewSource(42)) + cctx := sample.CrossChainTx(t, "foo") + + cctx.OutboundTxParams = []*types.OutboundTxParams{} + require.Equal(t, &types.OutboundTxParams{}, cctx.GetCurrentOutTxParam()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} + require.Equal(t, cctx.OutboundTxParams[0], cctx.GetCurrentOutTxParam()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} + require.Equal(t, cctx.OutboundTxParams[1], cctx.GetCurrentOutTxParam()) +} + +func TestCrossChainTx_IsCurrentOutTxRevert(t *testing.T) { + r := rand.New(rand.NewSource(42)) + cctx := sample.CrossChainTx(t, "foo") + + cctx.OutboundTxParams = []*types.OutboundTxParams{} + require.False(t, cctx.IsCurrentOutTxRevert()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} + require.False(t, cctx.IsCurrentOutTxRevert()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} + require.True(t, cctx.IsCurrentOutTxRevert()) +} + +func TestCrossChainTx_OriginalDestinationChainID(t *testing.T) { + r := rand.New(rand.NewSource(42)) + cctx := sample.CrossChainTx(t, "foo") + + cctx.OutboundTxParams = []*types.OutboundTxParams{} + require.Equal(t, int64(-1), cctx.OriginalDestinationChainID()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} + require.Equal(t, cctx.OutboundTxParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) + + cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} + require.Equal(t, cctx.OutboundTxParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) +} + +func Test_GetInbound(t *testing.T) { + t.Run("should return a cctx with correct values", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + senderChain := common.GoerliChain() + sender := sample.EthAddress() + receiverChain := common.GoerliChain() + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + intxBlockHeight := uint64(420) + intxHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := common.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteOnObservedInboundTx{ + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InTxHash: intxHash.String(), + InBlockHeight: intxBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + cctx := types.GetInbound(ctx, msg, tss.TssPubkey) + require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) + require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) + require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) + require.Equal(t, amount, cctx.GetInboundTxParams().Amount) + require.Equal(t, message, cctx.RelayedMessage) + require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) + require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) + require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) + require.Equal(t, asset, cctx.GetInboundTxParams().Asset) + require.Equal(t, cointType, cctx.InboundTxParams.CoinType) + require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) + require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) + require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + }) +} + +func TestC_GetOutbound(t *testing.T) { + t.Run("successfully get outbound tx", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := cctx.AddOutbound(ctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: cctx.GetCurrentOutTxParam().Amount, + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("successfully get outbound tx for failed ballot without amount check", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := cctx.AddOutbound(ctx, types.MsgVoteOnObservedOutboundTx{ + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_FailureObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxHash, hash) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight, uint64(10)) + require.Equal(t, cctx.CctxStatus.LastUpdateTimestamp, ctx.BlockHeader().Time.Unix()) + }) + + t.Run("failed to get outbound tx if amount does not match value received", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + + cctx := sample.CrossChainTx(t, "test") + hash := sample.Hash().String() + + err := cctx.AddOutbound(ctx, types.MsgVoteOnObservedOutboundTx{ + ValueReceived: sdkmath.NewUint(100), + ObservedOutTxHash: hash, + ObservedOutTxBlockHeight: 10, + ObservedOutTxGasUsed: 100, + ObservedOutTxEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutTxEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + }) +} + +func Test_SetRevertOutboundValues(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.OutboundTxParams = cctx.OutboundTxParams[:1] + cctx.AddRevertOutbound(100) + require.Len(t, cctx.OutboundTxParams, 2) + require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) + require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) +} + +func TestCrossChainTx_SetAbort(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.SetAbort("test") + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "test", "test") +} + +func TestCrossChainTx_SetPendingRevert(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.SetPendingRevert("test") + require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) + require.Equal(t, cctx.CctxStatus.StatusMessage, "test") +} + +func TestCrossChainTx_SetPendingOutbound(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingInbound + cctx.SetPendingOutbound("test") + require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) + require.Equal(t, cctx.CctxStatus.StatusMessage, "test") +} + +func TestCrossChainTx_SetOutBoundMined(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.SetOutBoundMined("test") + require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + require.Equal(t, cctx.CctxStatus.StatusMessage, "test") +} + +func TestCrossChainTx_SetReverted(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + cctx.SetReverted("test") + require.Equal(t, types.CctxStatus_Reverted, cctx.CctxStatus.Status) + require.Equal(t, cctx.CctxStatus.StatusMessage, "test") +} diff --git a/x/crosschain/types/cctx_utils.go b/x/crosschain/types/cctx_utils.go deleted file mode 100644 index 144acc379c..0000000000 --- a/x/crosschain/types/cctx_utils.go +++ /dev/null @@ -1,210 +0,0 @@ -package types - -import ( - "fmt" - "regexp" - "strconv" - - "cosmossdk.io/errors" - "github.com/btcsuite/btcutil" - sdk "github.com/cosmos/cosmos-sdk/types" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/zeta-chain/zetacore/common" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" -) - -// GetCurrentOutTxParam returns the current outbound tx params. -// There can only be one active outtx. -// OutboundTxParams[0] is the original outtx, if it reverts, then -// OutboundTxParams[1] is the new outtx. -func (m CrossChainTx) GetCurrentOutTxParam() *OutboundTxParams { - if len(m.OutboundTxParams) == 0 { - return &OutboundTxParams{} - } - return m.OutboundTxParams[len(m.OutboundTxParams)-1] -} - -// IsCurrentOutTxRevert returns true if the current outbound tx is the revert tx. -func (m CrossChainTx) IsCurrentOutTxRevert() bool { - return len(m.OutboundTxParams) == 2 -} - -// OriginalDestinationChainID returns the original destination of the outbound tx, reverted or not -// If there is no outbound tx, return -1 -func (m CrossChainTx) OriginalDestinationChainID() int64 { - if len(m.OutboundTxParams) == 0 { - return -1 - } - return m.OutboundTxParams[0].ReceiverChainId -} - -// GetAllAuthzZetaclientTxTypes returns all the authz types for zetaclient -func GetAllAuthzZetaclientTxTypes() []string { - return []string{ - sdk.MsgTypeURL(&MsgGasPriceVoter{}), - sdk.MsgTypeURL(&MsgVoteOnObservedInboundTx{}), - sdk.MsgTypeURL(&MsgVoteOnObservedOutboundTx{}), - sdk.MsgTypeURL(&MsgCreateTSSVoter{}), - sdk.MsgTypeURL(&MsgAddToOutTxTracker{}), - sdk.MsgTypeURL(&observertypes.MsgAddBlameVote{}), - sdk.MsgTypeURL(&observertypes.MsgAddBlockHeader{}), - } -} - -func (m CrossChainTx) Validate() error { - if m.InboundTxParams == nil { - return fmt.Errorf("inbound tx params cannot be nil") - } - if m.OutboundTxParams == nil { - return fmt.Errorf("outbound tx params cannot be nil") - } - if m.CctxStatus == nil { - return fmt.Errorf("cctx status cannot be nil") - } - if len(m.OutboundTxParams) > 2 { - return fmt.Errorf("outbound tx params cannot be more than 2") - } - if m.Index != "" { - err := ValidateZetaIndex(m.Index) - if err != nil { - return err - } - } - err := m.InboundTxParams.Validate() - if err != nil { - return err - } - for _, outboundTxParam := range m.OutboundTxParams { - err = outboundTxParam.Validate() - if err != nil { - return err - } - } - return nil -} - -func (m InboundTxParams) Validate() error { - if m.Sender == "" { - return fmt.Errorf("sender cannot be empty") - } - if common.GetChainFromChainID(m.SenderChainId) == nil { - return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) - } - err := ValidateAddressForChain(m.Sender, m.SenderChainId) - if err != nil { - return err - } - - if m.TxOrigin != "" { - errTxOrigin := ValidateAddressForChain(m.TxOrigin, m.SenderChainId) - if errTxOrigin != nil { - return errTxOrigin - } - } - if m.Amount.IsNil() { - return fmt.Errorf("amount cannot be nil") - } - err = ValidateHashForChain(m.InboundTxObservedHash, m.SenderChainId) - if err != nil { - return errors.Wrap(err, "invalid inbound tx observed hash") - } - if m.InboundTxBallotIndex != "" { - err = ValidateZetaIndex(m.InboundTxBallotIndex) - if err != nil { - return errors.Wrap(err, "invalid inbound tx ballot index") - } - } - return nil -} - -func (m OutboundTxParams) Validate() error { - if m.Receiver == "" { - return fmt.Errorf("receiver cannot be empty") - } - if common.GetChainFromChainID(m.ReceiverChainId) == nil { - return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) - } - err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) - if err != nil { - return err - } - if m.Amount.IsNil() { - return fmt.Errorf("amount cannot be nil") - } - if m.OutboundTxBallotIndex != "" { - err = ValidateZetaIndex(m.OutboundTxBallotIndex) - if err != nil { - return errors.Wrap(err, "invalid outbound tx ballot index") - } - } - if m.OutboundTxHash != "" { - err = ValidateHashForChain(m.OutboundTxHash, m.ReceiverChainId) - if err != nil { - return errors.Wrap(err, "invalid outbound tx hash") - } - } - return nil -} - -func ValidateZetaIndex(index string) error { - if len(index) != 66 { - return fmt.Errorf("invalid index hash %s", index) - } - return nil -} -func ValidateHashForChain(hash string, chainID int64) error { - if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { - _, err := hexutil.Decode(hash) - if err != nil { - return fmt.Errorf("hash must be a valid ethereum hash %s", hash) - } - return nil - } - if common.IsBitcoinChain(chainID) { - r, err := regexp.Compile("^[a-fA-F0-9]{64}$") - if err != nil { - return fmt.Errorf("error compiling regex") - } - if !r.MatchString(hash) { - return fmt.Errorf("hash must be a valid bitcoin hash %s", hash) - } - return nil - } - return fmt.Errorf("invalid chain id %d", chainID) -} - -func ValidateAddressForChain(address string, chainID int64) error { - // we do not validate the address for zeta chain as the address field can be btc or eth address - if common.IsZetaChain(chainID) { - return nil - } - if common.IsEthereumChain(chainID) { - if !ethcommon.IsHexAddress(address) { - return fmt.Errorf("invalid address %s , chain %d", address, chainID) - } - return nil - } - if common.IsBitcoinChain(chainID) { - addr, err := common.DecodeBtcAddress(address, chainID) - if err != nil { - return fmt.Errorf("invalid address %s , chain %d: %s", address, chainID, err) - } - _, ok := addr.(*btcutil.AddressWitnessPubKeyHash) - if !ok { - return fmt.Errorf(" invalid address %s (not P2WPKH address)", address) - } - return nil - } - return fmt.Errorf("invalid chain id %d", chainID) -} - -// GetGasPrice returns the gas price of the outbound tx -func (m OutboundTxParams) GetGasPrice() (uint64, error) { - gasPrice, err := strconv.ParseUint(m.OutboundTxGasPrice, 10, 64) - if err != nil { - return 0, fmt.Errorf("unable to parse cctx gas price %s: %s", m.OutboundTxGasPrice, err.Error()) - } - - return gasPrice, nil -} diff --git a/x/crosschain/types/cctx_utils_test.go b/x/crosschain/types/cctx_utils_test.go deleted file mode 100644 index e28581ac88..0000000000 --- a/x/crosschain/types/cctx_utils_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package types_test - -import ( - "math/rand" - "testing" - - sdkmath "cosmossdk.io/math" - "github.com/stretchr/testify/require" - "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/testutil/sample" - "github.com/zeta-chain/zetacore/x/crosschain/types" -) - -func TestValidateAddressForChain(t *testing.T) { - require.Error(t, types.ValidateAddressForChain("0x123", common.GoerliChain().ChainId)) - require.Error(t, types.ValidateAddressForChain("", common.GoerliChain().ChainId)) - require.Error(t, types.ValidateAddressForChain("%%%%", common.GoerliChain().ChainId)) - require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.GoerliChain().ChainId)) - require.Error(t, types.ValidateAddressForChain("1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3", common.BtcMainnetChain().ChainId)) - require.Error(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcMainnetChain().ChainId)) - require.Error(t, types.ValidateAddressForChain("", common.BtcRegtestChain().ChainId)) - require.NoError(t, types.ValidateAddressForChain("bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu", common.BtcMainnetChain().ChainId)) - require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcRegtestChain().ChainId)) - require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.ZetaChainMainnet().ChainId)) - require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.ZetaChainMainnet().ChainId)) -} - -func TestValidateZetaIndex(t *testing.T) { - require.NoError(t, types.ValidateZetaIndex("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910")) - require.NoError(t, types.ValidateZetaIndex(sample.ZetaIndex(t))) - require.Error(t, types.ValidateZetaIndex("0")) - require.Error(t, types.ValidateZetaIndex("0x70e967acFcC17c3941E87562161406d41676FD83")) -} - -func TestValidateHashForChain(t *testing.T) { - require.NoError(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.GoerliChain().ChainId)) - require.Error(t, types.ValidateHashForChain("", common.GoerliChain().ChainId)) - require.Error(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.GoerliChain().ChainId)) - require.NoError(t, types.ValidateHashForChain("15b7880f5d236e857a5e8f043ce9d56f5ef01e1c3f2a786baf740fc0bb7a22a3", common.BtcMainnetChain().ChainId)) - require.NoError(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.BtcTestNetChain().ChainId)) - require.Error(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.BtcMainnetChain().ChainId)) -} - -func TestInboundTxParams_Validate(t *testing.T) { - r := rand.New(rand.NewSource(42)) - inTxParams := sample.InboundTxParamsValidChainID(r) - inTxParams.Sender = "" - require.ErrorContains(t, inTxParams.Validate(), "sender cannot be empty") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.SenderChainId = 1000 - require.ErrorContains(t, inTxParams.Validate(), "invalid sender chain id 1000") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.SenderChainId = common.GoerliChain().ChainId - inTxParams.Sender = "0x123" - require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.SenderChainId = common.GoerliChain().ChainId - inTxParams.TxOrigin = "0x123" - require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.Amount = sdkmath.Uint{} - require.ErrorContains(t, inTxParams.Validate(), "amount cannot be nil") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.InboundTxObservedHash = "12" - require.ErrorContains(t, inTxParams.Validate(), "hash must be a valid ethereum hash 12") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.InboundTxObservedHash = sample.Hash().String() - inTxParams.InboundTxBallotIndex = "12" - require.ErrorContains(t, inTxParams.Validate(), "invalid index hash 12") - inTxParams = sample.InboundTxParamsValidChainID(r) - inTxParams.InboundTxObservedHash = sample.Hash().String() - inTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) - require.NoError(t, inTxParams.Validate()) -} - -func TestOutboundTxParams_Validate(t *testing.T) { - r := rand.New(rand.NewSource(42)) - outTxParams := sample.OutboundTxParamsValidChainID(r) - outTxParams.Receiver = "" - require.ErrorContains(t, outTxParams.Validate(), "receiver cannot be empty") - outTxParams = sample.OutboundTxParamsValidChainID(r) - outTxParams.ReceiverChainId = 1000 - require.ErrorContains(t, outTxParams.Validate(), "invalid receiver chain id 1000") - outTxParams = sample.OutboundTxParamsValidChainID(r) - outTxParams.Receiver = "0x123" - require.ErrorContains(t, outTxParams.Validate(), "invalid address 0x123") - outTxParams = sample.OutboundTxParamsValidChainID(r) - outTxParams.Amount = sdkmath.Uint{} - require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") - outTxParams = sample.OutboundTxParamsValidChainID(r) - outTxParams.OutboundTxBallotIndex = "12" - require.ErrorContains(t, outTxParams.Validate(), "invalid index hash 12") - outTxParams = sample.OutboundTxParamsValidChainID(r) - outTxParams.OutboundTxBallotIndex = sample.ZetaIndex(t) - outTxParams.OutboundTxHash = sample.Hash().String() - require.NoError(t, outTxParams.Validate()) -} - -func TestCrossChainTx_Validate(t *testing.T) { - cctx := sample.CrossChainTx(t, "foo") - cctx.InboundTxParams = nil - require.ErrorContains(t, cctx.Validate(), "inbound tx params cannot be nil") - cctx = sample.CrossChainTx(t, "foo") - cctx.OutboundTxParams = nil - require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be nil") - cctx = sample.CrossChainTx(t, "foo") - cctx.CctxStatus = nil - require.ErrorContains(t, cctx.Validate(), "cctx status cannot be nil") - cctx = sample.CrossChainTx(t, "foo") - cctx.OutboundTxParams = make([]*types.OutboundTxParams, 3) - require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be more than 2") - cctx = sample.CrossChainTx(t, "foo") - cctx.Index = "0" - require.ErrorContains(t, cctx.Validate(), "invalid index hash 0") - cctx = sample.CrossChainTx(t, "foo") - cctx.InboundTxParams = sample.InboundTxParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundTxParams.SenderChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid sender chain id 1000") - cctx = sample.CrossChainTx(t, "foo") - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParamsValidChainID(rand.New(rand.NewSource(42)))} - cctx.InboundTxParams = sample.InboundTxParamsValidChainID(rand.New(rand.NewSource(42))) - cctx.InboundTxParams.InboundTxObservedHash = sample.Hash().String() - cctx.InboundTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) - cctx.OutboundTxParams[0].ReceiverChainId = 1000 - require.ErrorContains(t, cctx.Validate(), "invalid receiver chain id 1000") -} - -func TestCrossChainTx_GetCurrentOutTxParam(t *testing.T) { - r := rand.New(rand.NewSource(42)) - cctx := sample.CrossChainTx(t, "foo") - - cctx.OutboundTxParams = []*types.OutboundTxParams{} - require.Equal(t, &types.OutboundTxParams{}, cctx.GetCurrentOutTxParam()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} - require.Equal(t, cctx.OutboundTxParams[0], cctx.GetCurrentOutTxParam()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} - require.Equal(t, cctx.OutboundTxParams[1], cctx.GetCurrentOutTxParam()) -} - -func TestCrossChainTx_IsCurrentOutTxRevert(t *testing.T) { - r := rand.New(rand.NewSource(42)) - cctx := sample.CrossChainTx(t, "foo") - - cctx.OutboundTxParams = []*types.OutboundTxParams{} - require.False(t, cctx.IsCurrentOutTxRevert()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} - require.False(t, cctx.IsCurrentOutTxRevert()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} - require.True(t, cctx.IsCurrentOutTxRevert()) -} - -func TestCrossChainTx_OriginalDestinationChainID(t *testing.T) { - r := rand.New(rand.NewSource(42)) - cctx := sample.CrossChainTx(t, "foo") - - cctx.OutboundTxParams = []*types.OutboundTxParams{} - require.Equal(t, int64(-1), cctx.OriginalDestinationChainID()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r)} - require.Equal(t, cctx.OutboundTxParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) - - cctx.OutboundTxParams = []*types.OutboundTxParams{sample.OutboundTxParams(r), sample.OutboundTxParams(r)} - require.Equal(t, cctx.OutboundTxParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) -} - -func TestOutboundTxParams_GetGasPrice(t *testing.T) { - // #nosec G404 - random seed is not used for security purposes - r := rand.New(rand.NewSource(42)) - outTxParams := sample.OutboundTxParams(r) - - outTxParams.OutboundTxGasPrice = "42" - gasPrice, err := outTxParams.GetGasPrice() - require.NoError(t, err) - require.EqualValues(t, uint64(42), gasPrice) - - outTxParams.OutboundTxGasPrice = "invalid" - _, err = outTxParams.GetGasPrice() - require.Error(t, err) -} diff --git a/x/crosschain/types/inbound_params.go b/x/crosschain/types/inbound_params.go new file mode 100644 index 0000000000..0ee4f91e08 --- /dev/null +++ b/x/crosschain/types/inbound_params.go @@ -0,0 +1,42 @@ +package types + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" +) + +func (m InboundTxParams) Validate() error { + if m.Sender == "" { + return fmt.Errorf("sender cannot be empty") + } + if common.GetChainFromChainID(m.SenderChainId) == nil { + return fmt.Errorf("invalid sender chain id %d", m.SenderChainId) + } + err := ValidateAddressForChain(m.Sender, m.SenderChainId) + if err != nil { + return err + } + + if m.TxOrigin != "" { + errTxOrigin := ValidateAddressForChain(m.TxOrigin, m.SenderChainId) + if errTxOrigin != nil { + return errTxOrigin + } + } + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") + } + err = ValidateHashForChain(m.InboundTxObservedHash, m.SenderChainId) + if err != nil { + return errors.Wrap(err, "invalid inbound tx observed hash") + } + if m.InboundTxBallotIndex != "" { + err = ValidateZetaIndex(m.InboundTxBallotIndex) + if err != nil { + return errors.Wrap(err, "invalid inbound tx ballot index") + } + } + return nil +} diff --git a/x/crosschain/types/inbound_params_test.go b/x/crosschain/types/inbound_params_test.go new file mode 100644 index 0000000000..88f5121860 --- /dev/null +++ b/x/crosschain/types/inbound_params_test.go @@ -0,0 +1,43 @@ +package types_test + +import ( + "math/rand" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/sample" +) + +func TestInboundTxParams_Validate(t *testing.T) { + r := rand.New(rand.NewSource(42)) + inTxParams := sample.InboundTxParamsValidChainID(r) + inTxParams.Sender = "" + require.ErrorContains(t, inTxParams.Validate(), "sender cannot be empty") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.SenderChainId = 1000 + require.ErrorContains(t, inTxParams.Validate(), "invalid sender chain id 1000") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.SenderChainId = common.GoerliChain().ChainId + inTxParams.Sender = "0x123" + require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.SenderChainId = common.GoerliChain().ChainId + inTxParams.TxOrigin = "0x123" + require.ErrorContains(t, inTxParams.Validate(), "invalid address 0x123") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.Amount = sdkmath.Uint{} + require.ErrorContains(t, inTxParams.Validate(), "amount cannot be nil") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.InboundTxObservedHash = "12" + require.ErrorContains(t, inTxParams.Validate(), "hash must be a valid ethereum hash 12") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.InboundTxObservedHash = sample.Hash().String() + inTxParams.InboundTxBallotIndex = "12" + require.ErrorContains(t, inTxParams.Validate(), "invalid index hash 12") + inTxParams = sample.InboundTxParamsValidChainID(r) + inTxParams.InboundTxObservedHash = sample.Hash().String() + inTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) + require.NoError(t, inTxParams.Validate()) +} diff --git a/x/crosschain/types/outbound_params.go b/x/crosschain/types/outbound_params.go new file mode 100644 index 0000000000..96a4294403 --- /dev/null +++ b/x/crosschain/types/outbound_params.go @@ -0,0 +1,47 @@ +package types + +import ( + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" +) + +func (m OutboundTxParams) GetGasPrice() (uint64, error) { + gasPrice, err := strconv.ParseUint(m.OutboundTxGasPrice, 10, 64) + if err != nil { + return 0, fmt.Errorf("unable to parse cctx gas price %s: %s", m.OutboundTxGasPrice, err.Error()) + } + + return gasPrice, nil +} + +func (m OutboundTxParams) Validate() error { + if m.Receiver == "" { + return fmt.Errorf("receiver cannot be empty") + } + if common.GetChainFromChainID(m.ReceiverChainId) == nil { + return fmt.Errorf("invalid receiver chain id %d", m.ReceiverChainId) + } + err := ValidateAddressForChain(m.Receiver, m.ReceiverChainId) + if err != nil { + return err + } + if m.Amount.IsNil() { + return fmt.Errorf("amount cannot be nil") + } + if m.OutboundTxBallotIndex != "" { + err = ValidateZetaIndex(m.OutboundTxBallotIndex) + if err != nil { + return errors.Wrap(err, "invalid outbound tx ballot index") + } + } + if m.OutboundTxHash != "" { + err = ValidateHashForChain(m.OutboundTxHash, m.ReceiverChainId) + if err != nil { + return errors.Wrap(err, "invalid outbound tx hash") + } + } + return nil +} diff --git a/x/crosschain/types/outbound_params_test.go b/x/crosschain/types/outbound_params_test.go new file mode 100644 index 0000000000..45b724b9e9 --- /dev/null +++ b/x/crosschain/types/outbound_params_test.go @@ -0,0 +1,48 @@ +package types_test + +import ( + "math/rand" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/testutil/sample" +) + +func TestOutboundTxParams_Validate(t *testing.T) { + r := rand.New(rand.NewSource(42)) + outTxParams := sample.OutboundTxParamsValidChainID(r) + outTxParams.Receiver = "" + require.ErrorContains(t, outTxParams.Validate(), "receiver cannot be empty") + outTxParams = sample.OutboundTxParamsValidChainID(r) + outTxParams.ReceiverChainId = 1000 + require.ErrorContains(t, outTxParams.Validate(), "invalid receiver chain id 1000") + outTxParams = sample.OutboundTxParamsValidChainID(r) + outTxParams.Receiver = "0x123" + require.ErrorContains(t, outTxParams.Validate(), "invalid address 0x123") + outTxParams = sample.OutboundTxParamsValidChainID(r) + outTxParams.Amount = sdkmath.Uint{} + require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") + outTxParams = sample.OutboundTxParamsValidChainID(r) + outTxParams.OutboundTxBallotIndex = "12" + require.ErrorContains(t, outTxParams.Validate(), "invalid index hash 12") + outTxParams = sample.OutboundTxParamsValidChainID(r) + outTxParams.OutboundTxBallotIndex = sample.ZetaIndex(t) + outTxParams.OutboundTxHash = sample.Hash().String() + require.NoError(t, outTxParams.Validate()) +} + +func TestOutboundTxParams_GetGasPrice(t *testing.T) { + // #nosec G404 - random seed is not used for security purposes + r := rand.New(rand.NewSource(42)) + outTxParams := sample.OutboundTxParams(r) + + outTxParams.OutboundTxGasPrice = "42" + gasPrice, err := outTxParams.GetGasPrice() + require.NoError(t, err) + require.EqualValues(t, uint64(42), gasPrice) + + outTxParams.OutboundTxGasPrice = "invalid" + _, err = outTxParams.GetGasPrice() + require.Error(t, err) +} diff --git a/x/crosschain/types/utils.go b/x/crosschain/types/utils.go new file mode 100644 index 0000000000..8a1b2a61f7 --- /dev/null +++ b/x/crosschain/types/utils.go @@ -0,0 +1,77 @@ +package types + +import ( + "fmt" + "regexp" + + "github.com/btcsuite/btcutil" + sdk "github.com/cosmos/cosmos-sdk/types" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/zeta-chain/zetacore/common" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func GetAllAuthzZetaclientTxTypes() []string { + return []string{ + sdk.MsgTypeURL(&MsgGasPriceVoter{}), + sdk.MsgTypeURL(&MsgVoteOnObservedInboundTx{}), + sdk.MsgTypeURL(&MsgVoteOnObservedOutboundTx{}), + sdk.MsgTypeURL(&MsgCreateTSSVoter{}), + sdk.MsgTypeURL(&MsgAddToOutTxTracker{}), + sdk.MsgTypeURL(&observertypes.MsgAddBlameVote{}), + sdk.MsgTypeURL(&observertypes.MsgAddBlockHeader{}), + } +} + +func ValidateZetaIndex(index string) error { + if len(index) != 66 { + return fmt.Errorf("invalid index hash %s", index) + } + return nil +} +func ValidateHashForChain(hash string, chainID int64) error { + if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { + _, err := hexutil.Decode(hash) + if err != nil { + return fmt.Errorf("hash must be a valid ethereum hash %s", hash) + } + return nil + } + if common.IsBitcoinChain(chainID) { + r, err := regexp.Compile("^[a-fA-F0-9]{64}$") + if err != nil { + return fmt.Errorf("error compiling regex") + } + if !r.MatchString(hash) { + return fmt.Errorf("hash must be a valid bitcoin hash %s", hash) + } + return nil + } + return fmt.Errorf("invalid chain id %d", chainID) +} + +func ValidateAddressForChain(address string, chainID int64) error { + // we do not validate the address for zeta chain as the address field can be btc or eth address + if common.IsZetaChain(chainID) { + return nil + } + if common.IsEthereumChain(chainID) { + if !ethcommon.IsHexAddress(address) { + return fmt.Errorf("invalid address %s , chain %d", address, chainID) + } + return nil + } + if common.IsBitcoinChain(chainID) { + addr, err := common.DecodeBtcAddress(address, chainID) + if err != nil { + return fmt.Errorf("invalid address %s , chain %d: %s", address, chainID, err) + } + _, ok := addr.(*btcutil.AddressWitnessPubKeyHash) + if !ok { + return fmt.Errorf(" invalid address %s (not P2WPKH address)", address) + } + return nil + } + return fmt.Errorf("invalid chain id %d", chainID) +} diff --git a/x/crosschain/types/utils_test.go b/x/crosschain/types/utils_test.go new file mode 100644 index 0000000000..0279582d0d --- /dev/null +++ b/x/crosschain/types/utils_test.go @@ -0,0 +1,40 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestValidateAddressForChain(t *testing.T) { + require.Error(t, types.ValidateAddressForChain("0x123", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("%%%%", common.GoerliChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3", common.BtcMainnetChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcMainnetChain().ChainId)) + require.Error(t, types.ValidateAddressForChain("", common.BtcRegtestChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu", common.BtcMainnetChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.BtcRegtestChain().ChainId)) + require.NoError(t, types.ValidateAddressForChain("bcrt1qs758ursh4q9z627kt3pp5yysm78ddny6txaqgw", common.ZetaChainMainnet().ChainId)) + require.NoError(t, types.ValidateAddressForChain("0x792c127Fa3AC1D52F904056Baf1D9257391e7D78", common.ZetaChainMainnet().ChainId)) +} + +func TestValidateZetaIndex(t *testing.T) { + require.NoError(t, types.ValidateZetaIndex("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910")) + require.NoError(t, types.ValidateZetaIndex(sample.ZetaIndex(t))) + require.Error(t, types.ValidateZetaIndex("0")) + require.Error(t, types.ValidateZetaIndex("0x70e967acFcC17c3941E87562161406d41676FD83")) +} + +func TestValidateHashForChain(t *testing.T) { + require.NoError(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateHashForChain("", common.GoerliChain().ChainId)) + require.Error(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.GoerliChain().ChainId)) + require.NoError(t, types.ValidateHashForChain("15b7880f5d236e857a5e8f043ce9d56f5ef01e1c3f2a786baf740fc0bb7a22a3", common.BtcMainnetChain().ChainId)) + require.NoError(t, types.ValidateHashForChain("a0fa5a82f106fb192e4c503bfa8d54b2de20a821e09338094ab825cc9b275059", common.BtcTestNetChain().ChainId)) + require.Error(t, types.ValidateHashForChain("0x84bd5c9922b63c52d8a9ca686e0a57ff978150b71be0583514d01c27aa341910", common.BtcMainnetChain().ChainId)) +} From d432e40964f17476658b2c639b8c02a2d3891fdc Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 20 Mar 2024 15:39:38 -0400 Subject: [PATCH 26/36] add comments --- x/crosschain/keeper/evm_hooks.go | 26 +---- .../keeper/msg_server_migrate_tss_funds.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 56 ++++++--- .../keeper/msg_server_vote_outbound_tx.go | 65 +++++++---- .../keeper/msg_server_whitelist_erc20.go | 2 +- x/crosschain/types/cctx.go | 44 ++++---- x/crosschain/types/cctx_test.go | 106 +++++++++--------- 7 files changed, 162 insertions(+), 139 deletions(-) diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 57b6c376f9..a551a1980e 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -168,17 +168,9 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W foreignCoin.Asset, event.Raw.Index, ) - sendHash := msg.Digest() - cctx := types.CreateNewCCTX( - ctx, - *msg, - sendHash, - tss.TssPubkey, - types.CctxStatus_PendingOutbound, - senderChain.ChainId, - receiverChain.ChainId, - ) + // Create a new cctx with status as pending Inbound, this is created directly from the event without waiting for any observer votes + cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) // Get gas price and amount gasprice, found := k.GetGasPrice(ctx, receiverChain.ChainId) @@ -246,18 +238,10 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC "", event.Raw.Index, ) - sendHash := msg.Digest() - // Create the CCTX - cctx := types.CreateNewCCTX( - ctx, - *msg, - sendHash, - tss.TssPubkey, - types.CctxStatus_PendingOutbound, - senderChain.ChainId, - receiverChain.ChainId, - ) + // create a new cctx with status as pending Inbound, + // this is created directly from the event without waiting for any observer votes + cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) if err := k.PayGasAndUpdateCctx( ctx, diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index 9cba4f8c24..aaac261352 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -79,7 +79,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() - // TODO : Use the `GetInbound` method to create the cctx + // TODO : Use the `InitializeCCTX` method to create the cctx // https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: "", diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index d9ee59548e..2d07abb93b 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -93,20 +93,27 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if !tssFound { return nil, types.ErrCannotFindTSSKeys } - inboundCctx := types.GetInbound(ctx, *msg, tss.TssPubkey) - err = inboundCctx.Validate() + // 1 .create a new CCTX from the inbound message. The status of the new CCTX is set to PendingInbound. + cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) + + // 2. Validate the CCTX + err = cctx.Validate() if err != nil { return nil, err } - k.ProcessInbound(ctx, &inboundCctx) - k.SaveInbound(ctx, &inboundCctx, msg.EventIndex) + + // 3. Process the inbound CCTX, the process function manages the state commit and cctx status change.If the process fails the changes to the evm state are rolled back. + k.ProcessInbound(ctx, &cctx) + // 4. Save the inbound CCTX to the store.This is called irrespective of the status of the CCTX or the outcome of the process function. + k.SaveInbound(ctx, &cctx, msg.EventIndex) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } -// GetInbound returns a new CCTX from a given inbound message. +// InitializeCCTX returns a new CCTX from a given inbound message. // ProcessInbound processes the inbound CCTX. // It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. +// The internal functions handle the state changes and error handling. func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { k.ProcessZEVMDeposit(ctx, cctx) @@ -115,14 +122,17 @@ func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { } } -// ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain. -// If the deposit is successful, the CCTX status is changed to OutboundMined. -// If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. -// If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. -// If the creation of revert tx also fails it changes the status to Aborted. -// Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. -// We do not return an error from this function , as all changes need to be persisted to the state. -// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. +/* +ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain.It trasnsitions state according to the following rules: + - If the deposit is successful, the CCTX status is changed to OutboundMined. + - If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. + - If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. + - If the creation of revert tx also fails it changes the status to Aborted. + +Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. +We do not return an error from this function , as all changes need to be persisted to the state. +Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. +*/ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { tmpCtx, commit := ctx.CacheContext() isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) @@ -180,11 +190,13 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return } -// ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain. -// If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. -// If the crosschain message passing returns an error, the CCTX status is changed to Aborted. -// We do not return an error from this function , as all changes need to be persisted to the state. -// Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. +/* +ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain.It trasnsitions state according to the following rules: + - If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. + - If the crosschain message passing returns an error, the CCTX status is changed to Aborted. + We do not return an error from this function, as all changes need to be persisted to the state. + Instead, we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. +*/ func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { tmpCtx, commit := ctx.CacheContext() outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId @@ -211,6 +223,14 @@ func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossCh return } +/* SaveInbound saves the inbound CCTX to the store.It does the following: + - Emits an event for the finalized inbound CCTX. + - Adds the inbound CCTX to the finalized inbound CCTX store.This is done to prevent double spending, using the same inbound tx hash and event index. + - Updates the CCTX with the finalized height and finalization status. + - Removes the inbound CCTX from the inbound transaction tracker store.This is only for inbounds created via InTx tracker suggestions + - Sets the CCTX and nonce to the CCTX and inbound transaction hash to CCTX store. +*/ + func (k Keeper) SaveInbound(ctx sdk.Context, cctx *types.CrossChainTx, eventIndex uint64) { EmitEventInboundFinalized(ctx, cctx) k.AddFinalizedInbound(ctx, diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 5eb81fd21e..ef026b1fa5 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -106,11 +106,6 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } -// AddRevertOutbound does the following things in one function: -// 1. create a new OutboundTxParams for the revert -// 2. append the new OutboundTxParams to the current OutboundTxParams -// 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. - // FundStabilityPool funds the stability pool with the remaining fees of an outbound tx // The funds are sent to the gas stability pool associated with the receiver chain func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) { @@ -156,10 +151,17 @@ func percentOf(n *big.Int, percent int64) *big.Int { return n } -// ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: -// 1. Change the status of the CCTX from PendingRevert to Reverted or from PendingOutbound to OutboundMined -// 2. Set the finalization status of the current outbound tx to executed -// 3. Emit an event for the successful outbound transaction +/* ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: + + 1. Change the status of the CCTX from + - PendingRevert to Reverted + - PendingOutbound to OutboundMined + + 2. Set the finalization status of the current outbound tx to executed + + 3. Emit an event for the successful outbound transaction +*/ + func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { oldStatus := cctx.CctxStatus.Status switch oldStatus { @@ -175,11 +177,19 @@ func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChai EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) } -// ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: -// 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX -// 2. For other CCTX, it creates a revert tx if the outbound tx is pending. If the status is pending revert, it aborts the CCTX -// 3. Emit an event for the failed outbound transaction -// 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction +/* +ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: + + 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX + + 2. For other CCTX + - If the CCTX is in PendingOutbound, it creates a revert tx and sets the finalization status of the current outbound tx to executed + - If the CCTX is in PendingRevert, it sets the Status to Aborted + + 3. Emit an event for the failed outbound transaction + + 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction +*/ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { oldStatus := cctx.CctxStatus.Status if cctx.InboundTxParams.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { @@ -251,10 +261,13 @@ func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballo return nil } -// SaveFailedOutBound saves a failed outbound transaction. -// It does the following things in one function: -// 1. Change the status of the CCTX to Aborted -// 2. Save the outbound +/* +SaveFailedOutBound saves a failed outbound transaction.It does the following things in one function: + + 1. Change the status of the CCTX to Aborted + + 2. Save the outbound +*/ func (k Keeper) SaveFailedOutBound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) ctx.Logger().Error(errMessage) @@ -267,11 +280,17 @@ func (k Keeper) SaveSuccessfulOutBound(ctx sdk.Context, cctx *types.CrossChainTx k.SaveOutbound(ctx, cctx, ballotIndex) } -// SaveOutbound saves the outbound transaction.It does the following things in one function: -// 1. Set the ballot index for the outbound vote to the cctx -// 2. Remove the nonce from the pending nonces -// 3. Remove the outbound tx tracker -// 4. Set the cctx and nonce to cctx and inTxHash to cctx +/* +SaveOutbound saves the outbound transaction.It does the following things in one function: + + 1. Set the ballot index for the outbound vote to the cctx + + 2. Remove the nonce from the pending nonces + + 3. Remove the outbound tx tracker + + 4. Set the cctx and nonce to cctx and inTxHash to cctx +*/ func (k Keeper) SaveOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { receiverChain := cctx.GetCurrentOutTxParam().ReceiverChainId tssPubkey := cctx.GetCurrentOutTxParam().TssPubkey diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index c0d713b6c1..33cdb151c0 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -111,7 +111,7 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist index := hash.Hex() // create a cmd cctx to whitelist the erc20 on the external chain - // TODO : refactor this to use the `GetInbound` function instead. + // TODO : refactor this to use the `InitializeCCTX` function instead. //https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: msg.Creator, diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index f6a7e4de9a..5ad47d6f1e 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -69,6 +69,16 @@ func (m CrossChainTx) Validate() error { return nil } +/* +AddRevertOutbound does the following things in one function: + + 1. create a new OutboundTxParams for the revert + + 2. append the new OutboundTxParams to the current OutboundTxParams + + 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. +*/ + func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) { revertTxParams := &OutboundTxParams{ Receiver: m.InboundTxParams.Sender, @@ -82,9 +92,7 @@ func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) { m.OutboundTxParams = append(m.OutboundTxParams, revertTxParams) } -// AddOutbound sets the required values for the outbound transaction -// Note: It expects the cctx to already have been created, -// it updates the cctx based on the MsgVoteOnObservedOutboundTx message which is signed and broadcasted by the observer +// AddOutbound adds a new outbound tx to the CCTX. func (m *CrossChainTx) AddOutbound(ctx sdk.Context, msg MsgVoteOnObservedOutboundTx, ballotStatus observertypes.BallotStatus) error { if ballotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { if !msg.ValueReceived.Equal(m.GetCurrentOutTxParam().Amount) { @@ -101,7 +109,6 @@ func (m *CrossChainTx) AddOutbound(ctx sdk.Context, msg MsgVoteOnObservedOutboun m.GetCurrentOutTxParam().OutboundTxEffectiveGasLimit = msg.ObservedOutTxEffectiveGasLimit m.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight m.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix() - return nil } @@ -115,38 +122,31 @@ func (m CrossChainTx) SetPendingRevert(message string) { m.CctxStatus.ChangeStatus(CctxStatus_PendingRevert, message) } +// SetPendingOutbound sets the CCTX status to PendingOutbound with the given error message. func (m CrossChainTx) SetPendingOutbound(message string) { m.CctxStatus.ChangeStatus(CctxStatus_PendingOutbound, message) } +// SetOutBoundMined sets the CCTX status to OutboundMined with the given error message. func (m CrossChainTx) SetOutBoundMined(message string) { m.CctxStatus.ChangeStatus(CctxStatus_OutboundMined, message) } +// SetReverted sets the CCTX status to Reverted with the given error message. func (m CrossChainTx) SetReverted(message string) { m.CctxStatus.ChangeStatus(CctxStatus_Reverted, message) } -func GetInbound(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) CrossChainTx { - return CreateNewCCTX(ctx, msg, msg.Digest(), tssPubkey, CctxStatus_PendingInbound, msg.SenderChainId, msg.ReceiverChain) -} +// InitializeCCTX initializes the CCTX with the given message and tssPubkey +func InitializeCCTX(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) CrossChainTx { + index := msg.Digest() -// CreateNewCCTX creates a new CCTX with the given parameters. -func CreateNewCCTX( - ctx sdk.Context, - msg MsgVoteOnObservedInboundTx, - index string, - tssPubkey string, - s CctxStatus, - senderChainID, - receiverChainID int64, -) CrossChainTx { if msg.TxOrigin == "" { msg.TxOrigin = msg.Sender } inboundParams := &InboundTxParams{ Sender: msg.Sender, - SenderChainId: senderChainID, + SenderChainId: msg.SenderChainId, TxOrigin: msg.TxOrigin, Asset: msg.Asset, Amount: msg.Amount, @@ -159,7 +159,7 @@ func CreateNewCCTX( outBoundParams := &OutboundTxParams{ Receiver: msg.Receiver, - ReceiverChainId: receiverChainID, + ReceiverChainId: msg.ReceiverChain, OutboundTxHash: "", OutboundTxTssNonce: 0, OutboundTxGasLimit: msg.GasLimit, @@ -171,12 +171,12 @@ func CreateNewCCTX( CoinType: msg.CoinType, } status := &Status{ - Status: s, + Status: CctxStatus_PendingInbound, StatusMessage: "", LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), IsAbortRefunded: false, } - newCctx := CrossChainTx{ + cctx := CrossChainTx{ Creator: msg.Creator, Index: index, ZetaFees: sdkmath.ZeroUint(), @@ -185,5 +185,5 @@ func CreateNewCCTX( InboundTxParams: inboundParams, OutboundTxParams: []*OutboundTxParams{outBoundParams}, } - return newCctx + return cctx } diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 41aa9f31db..0f6f9c6535 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -14,6 +14,58 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +func Test_InitializeCCTX(t *testing.T) { + t.Run("should return a cctx with correct values", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + senderChain := common.GoerliChain() + sender := sample.EthAddress() + receiverChain := common.GoerliChain() + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + intxBlockHeight := uint64(420) + intxHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := common.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteOnObservedInboundTx{ + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InTxHash: intxHash.String(), + InBlockHeight: intxBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + cctx := types.InitializeCCTX(ctx, msg, tss.TssPubkey) + require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) + require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) + require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) + require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) + require.Equal(t, amount, cctx.GetInboundTxParams().Amount) + require.Equal(t, message, cctx.RelayedMessage) + require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) + require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) + require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) + require.Equal(t, asset, cctx.GetInboundTxParams().Asset) + require.Equal(t, cointType, cctx.InboundTxParams.CoinType) + require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) + require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) + require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + }) +} + func TestCrossChainTx_Validate(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.InboundTxParams = nil @@ -85,59 +137,7 @@ func TestCrossChainTx_OriginalDestinationChainID(t *testing.T) { require.Equal(t, cctx.OutboundTxParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) } -func Test_GetInbound(t *testing.T) { - t.Run("should return a cctx with correct values", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - senderChain := common.GoerliChain() - sender := sample.EthAddress() - receiverChain := common.GoerliChain() - receiver := sample.EthAddress() - creator := sample.AccAddress() - amount := sdkmath.NewUint(42) - message := "test" - intxBlockHeight := uint64(420) - intxHash := sample.Hash() - gasLimit := uint64(100) - asset := "test-asset" - eventIndex := uint64(1) - cointType := common.CoinType_ERC20 - tss := sample.Tss() - msg := types.MsgVoteOnObservedInboundTx{ - Creator: creator, - Sender: sender.String(), - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InTxHash: intxHash.String(), - InBlockHeight: intxBlockHeight, - GasLimit: gasLimit, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, - } - cctx := types.GetInbound(ctx, msg, tss.TssPubkey) - require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) - require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) - require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) - require.Equal(t, senderChain.ChainId, cctx.GetInboundTxParams().SenderChainId) - require.Equal(t, amount, cctx.GetInboundTxParams().Amount) - require.Equal(t, message, cctx.RelayedMessage) - require.Equal(t, intxHash.String(), cctx.GetInboundTxParams().InboundTxObservedHash) - require.Equal(t, intxBlockHeight, cctx.GetInboundTxParams().InboundTxObservedExternalHeight) - require.Equal(t, gasLimit, cctx.GetCurrentOutTxParam().OutboundTxGasLimit) - require.Equal(t, asset, cctx.GetInboundTxParams().Asset) - require.Equal(t, cointType, cctx.InboundTxParams.CoinType) - require.Equal(t, uint64(0), cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutTxParam().Amount) - require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) - require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) - }) -} - -func TestC_GetOutbound(t *testing.T) { +func TestCrossChainTx_AddOutbound(t *testing.T) { t.Run("successfully get outbound tx", func(t *testing.T) { _, ctx, _, _ := keepertest.CrosschainKeeper(t) cctx := sample.CrossChainTx(t, "test") From 071ea2920d5ee951d1f59ed9637a7724f3446842 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 21 Mar 2024 16:29:39 -0400 Subject: [PATCH 27/36] resolve comments --- e2e/runner/logger.go | 4 +- testutil/sample/common.go | 8 ---- x/authority/types/genesis_test.go | 2 +- x/authority/types/policies_test.go | 11 +++--- x/crosschain/keeper/cctx_utils.go | 2 +- x/crosschain/keeper/cctx_utils_test.go | 16 ++++---- x/crosschain/keeper/events.go | 8 ++-- x/crosschain/keeper/evm_hooks.go | 10 ++++- .../keeper/msg_server_migrate_tss_funds.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 16 +++----- .../keeper/msg_server_vote_outbound_tx.go | 18 ++++----- .../msg_server_vote_outbound_tx_test.go | 8 ++-- .../keeper/msg_server_whitelist_erc20.go | 2 +- x/crosschain/types/cctx.go | 13 ++++--- x/crosschain/types/cctx_test.go | 38 ++++++++++++++++++- x/crosschain/types/errors.go | 2 - x/crosschain/types/keys.go | 1 + .../types/message_abort_stuck_cctx.go | 4 +- .../types/message_abort_stuck_cctx_test.go | 2 +- x/crosschain/types/message_refund_aborted.go | 2 +- x/crosschain/types/utils.go | 10 ++++- 21 files changed, 107 insertions(+), 72 deletions(-) diff --git a/e2e/runner/logger.go b/e2e/runner/logger.go index 91180d5eac..3a9ed4827c 100644 --- a/e2e/runner/logger.go +++ b/e2e/runner/logger.go @@ -122,7 +122,7 @@ func (l *Logger) CCTX(cctx crosschaintypes.CrossChainTx, name string) { l.Info(" TxHeight: %d", cctx.InboundTxParams.InboundTxObservedExternalHeight) l.Info(" BallotIndex: %s", cctx.InboundTxParams.InboundTxBallotIndex) l.Info(" Amount: %s", cctx.InboundTxParams.Amount.String()) - l.Info(" CoinType: %s", cctx.InboundTxParams.String()) + l.Info(" CoinType: %s", cctx.InboundTxParams.CoinType.String()) l.Info(" SenderChainID: %d", cctx.InboundTxParams.SenderChainId) l.Info(" Origin: %s", cctx.InboundTxParams.TxOrigin) if cctx.InboundTxParams.Sender != "" { @@ -151,7 +151,7 @@ func (l *Logger) CCTX(cctx crosschaintypes.CrossChainTx, name string) { l.Info(" EffectiveGasPrice: %s", outTxParam.OutboundTxEffectiveGasPrice.String()) l.Info(" EffectiveGasLimit: %d", outTxParam.OutboundTxEffectiveGasLimit) l.Info(" Amount: %s", outTxParam.Amount.String()) - l.Info(" CoinType: %s", outTxParam.String()) + l.Info(" CoinType: %s", outTxParam.CoinType.String()) l.Info(" Receiver: %s", outTxParam.Receiver) l.Info(" ReceiverChainID: %d", outTxParam.ReceiverChainId) } diff --git a/testutil/sample/common.go b/testutil/sample/common.go index 674e8d477d..86eef50a71 100644 --- a/testutil/sample/common.go +++ b/testutil/sample/common.go @@ -27,11 +27,3 @@ func EventIndex() uint64 { r := newRandFromSeed(1) return r.Uint64() } - -func EthChain() common.Chain { - return common.EthChain() -} - -func BtcChain() common.Chain { - return common.BtcMainnetChain() -} diff --git a/x/authority/types/genesis_test.go b/x/authority/types/genesis_test.go index ec53fc1fad..7b835c3ea4 100644 --- a/x/authority/types/genesis_test.go +++ b/x/authority/types/genesis_test.go @@ -9,7 +9,7 @@ import ( ) func TestGenesisState_Validate(t *testing.T) { - setConfig() + setConfig(t) tests := []struct { name string diff --git a/x/authority/types/policies_test.go b/x/authority/types/policies_test.go index b71d4e93c9..7e8edcc64e 100644 --- a/x/authority/types/policies_test.go +++ b/x/authority/types/policies_test.go @@ -1,7 +1,6 @@ package types_test import ( - "fmt" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,19 +11,19 @@ import ( ) // setConfig sets the global config to use zeta chain's bech32 prefixes -func setConfig() { - defer func() { +func setConfig(t *testing.T) { + defer func(t *testing.T) { if r := recover(); r != nil { - fmt.Println("config is already sealed", r) + t.Log("config is already sealed", r) } - }() + }(t) cfg := sdk.GetConfig() cfg.SetBech32PrefixForAccount(app.Bech32PrefixAccAddr, app.Bech32PrefixAccPub) cfg.Seal() } func TestPolicies_Validate(t *testing.T) { - setConfig() + setConfig(t) // use table driven tests to test the validation of policies tests := []struct { name string diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 190574dcfb..8c2edd5013 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -54,7 +54,7 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C // GetRevertGasLimit returns the gas limit for the revert transaction in a CCTX // It returns 0 if there is no error but the gas limit can't be determined from the CCTX data -func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx *types.CrossChainTx) (uint64, error) { +func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx types.CrossChainTx) (uint64, error) { if cctx.InboundTxParams == nil { return 0, nil } diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 00bf4db518..01ad952597 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -19,7 +19,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if no inbound tx params", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{}) + gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{}) require.NoError(t, err) require.Equal(t, uint64(0), gasLimit) }) @@ -27,7 +27,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if coin type is not gas or erc20", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: common.CoinType_Zeta, }, @@ -47,7 +47,7 @@ func TestGetRevertGasLimit(t *testing.T) { _, err := zk.FungibleKeeper.UpdateZRC20GasLimit(ctx, gas, big.NewInt(42)) require.NoError(t, err) - gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, @@ -78,7 +78,7 @@ func TestGetRevertGasLimit(t *testing.T) { _, err := zk.FungibleKeeper.UpdateZRC20GasLimit(ctx, zrc20Addr, big.NewInt(42)) require.NoError(t, err) - gasLimit, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + gasLimit, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, @@ -92,7 +92,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should fail if no gas coin found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: 999999, @@ -114,7 +114,7 @@ func TestGetRevertGasLimit(t *testing.T) { }) // no contract deployed therefore will fail - _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, @@ -126,7 +126,7 @@ func TestGetRevertGasLimit(t *testing.T) { t.Run("should fail if no asset found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: 999999, @@ -150,7 +150,7 @@ func TestGetRevertGasLimit(t *testing.T) { }) // no contract deployed therefore will fail - _, err := k.GetRevertGasLimit(ctx, &types.CrossChainTx{ + _, err := k.GetRevertGasLimit(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ SenderChainId: chainID, Asset: asset, diff --git a/x/crosschain/keeper/events.go b/x/crosschain/keeper/events.go index fbcf46b5d9..2f801c9b90 100644 --- a/x/crosschain/keeper/events.go +++ b/x/crosschain/keeper/events.go @@ -59,10 +59,10 @@ func EmitZetaWithdrawCreated(ctx sdk.Context, cctx types.CrossChainTx) { } -func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctx types.CrossChainTx) { +func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctxIndex string) { err := ctx.EventManager().EmitTypedEvents(&types.EventOutboundSuccess{ MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteOnObservedOutboundTx{}), - CctxIndex: cctx.Index, + CctxIndex: cctxIndex, ValueReceived: valueReceived, OldStatus: oldStatus, NewStatus: newStatus, @@ -73,10 +73,10 @@ func EmitOutboundSuccess(ctx sdk.Context, valueReceived string, oldStatus string } -func EmitOutboundFailure(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctx types.CrossChainTx) { +func EmitOutboundFailure(ctx sdk.Context, valueReceived string, oldStatus string, newStatus string, cctxIndex string) { err := ctx.EventManager().EmitTypedEvents(&types.EventOutboundFailure{ MsgTypeUrl: sdk.MsgTypeURL(&types.MsgVoteOnObservedOutboundTx{}), - CctxIndex: cctx.Index, + CctxIndex: cctxIndex, ValueReceived: valueReceived, OldStatus: oldStatus, NewStatus: newStatus, diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index a551a1980e..ef2898313a 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -170,7 +170,10 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W ) // Create a new cctx with status as pending Inbound, this is created directly from the event without waiting for any observer votes - cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) + cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey) + if err != nil { + return fmt.Errorf("ProcessZRC20WithdrawalEvent: failed to initialize cctx: %s", err.Error()) + } // Get gas price and amount gasprice, found := k.GetGasPrice(ctx, receiverChain.ChainId) @@ -241,7 +244,10 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC // create a new cctx with status as pending Inbound, // this is created directly from the event without waiting for any observer votes - cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) + cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey) + if err != nil { + return fmt.Errorf("ProcessZetaSentEvent: failed to initialize cctx: %s", err.Error()) + } if err := k.PayGasAndUpdateCctx( ctx, diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index aaac261352..317e6f35ba 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -79,7 +79,7 @@ func (k Keeper) MigrateTSSFundsForChain(ctx sdk.Context, chainID int64, amount s hash := crypto.Keccak256Hash([]byte(indexString)) index := hash.Hex() - // TODO : Use the `InitializeCCTX` method to create the cctx + // TODO : Use the `NewCCTX` method to create the cctx // https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: "", diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 2d07abb93b..0d93ca96e0 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -93,24 +93,18 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if !tssFound { return nil, types.ErrCannotFindTSSKeys } - // 1 .create a new CCTX from the inbound message. The status of the new CCTX is set to PendingInbound. - cctx := types.InitializeCCTX(ctx, *msg, tss.TssPubkey) - - // 2. Validate the CCTX - err = cctx.Validate() + // create a new CCTX from the inbound message. The status of the new CCTX is set to PendingInbound. + cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey) if err != nil { return nil, err } - - // 3. Process the inbound CCTX, the process function manages the state commit and cctx status change.If the process fails the changes to the evm state are rolled back. + // Process the inbound CCTX, the process function manages the state commit and cctx status change.If the process fails the changes to the evm state are rolled back. k.ProcessInbound(ctx, &cctx) - // 4. Save the inbound CCTX to the store.This is called irrespective of the status of the CCTX or the outcome of the process function. + // Save the inbound CCTX to the store.This is called irrespective of the status of the CCTX or the outcome of the process function. k.SaveInbound(ctx, &cctx, msg.EventIndex) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } -// InitializeCCTX returns a new CCTX from a given inbound message. - // ProcessInbound processes the inbound CCTX. // It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. // The internal functions handle the state changes and error handling. @@ -148,7 +142,7 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { return } - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) if err != nil { cctx.SetAbort(fmt.Sprintf("revert gas limit error: %s", err.Error())) return diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index ef026b1fa5..fd79fe7a5c 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -95,14 +95,14 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms err = k.ProcessOutbound(ctx, &cctx, ballot.BallotStatus, msg.ValueReceived.String()) if err != nil { - k.SaveFailedOutBound(ctx, &cctx, err.Error(), ballotIndex) + k.SaveFailedOutbound(ctx, &cctx, err.Error(), ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } err = cctx.Validate() if err != nil { return nil, err } - k.SaveSuccessfulOutBound(ctx, &cctx, ballotIndex) + k.SaveSuccessfulOutbound(ctx, &cctx, ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } @@ -174,7 +174,7 @@ func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChai } cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed newStatus := cctx.CctxStatus.Status.String() - EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) + EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) } /* @@ -200,7 +200,7 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, switch oldStatus { case types.CctxStatus_PendingOutbound: - gasLimit, err := k.GetRevertGasLimit(ctx, cctx) + gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) if err != nil { return cosmoserrors.Wrap(err, "GetRevertGasLimit") } @@ -234,7 +234,7 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, } } newStatus := cctx.CctxStatus.Status.String() - EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, *cctx) + EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) return nil } @@ -262,21 +262,21 @@ func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballo } /* -SaveFailedOutBound saves a failed outbound transaction.It does the following things in one function: +SaveFailedOutbound saves a failed outbound transaction.It does the following things in one function: 1. Change the status of the CCTX to Aborted 2. Save the outbound */ -func (k Keeper) SaveFailedOutBound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { +func (k Keeper) SaveFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) ctx.Logger().Error(errMessage) k.SaveOutbound(ctx, cctx, ballotIndex) } -// SaveSuccessfulOutBound saves a successful outbound transaction. -func (k Keeper) SaveSuccessfulOutBound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { +// SaveSuccessfulOutbound saves a successful outbound transaction. +func (k Keeper) SaveSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIndex string) { k.SaveOutbound(ctx, cctx, ballotIndex) } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 2812ad32f0..da811ad8c7 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -146,7 +146,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { // Successfully mock GetOutBound keepertest.MockGetOutBound(observerMock, ctx) - // Successfully mock SaveSuccessfulOutBound + // Successfully mock SaveSuccessfulOutbound keepertest.MockSaveOutBound(observerMock, ctx, cctx, tss) msgServer := keeper.NewMsgServerImpl(*k) @@ -324,7 +324,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { // Fail ProcessOutbound so that changes are not committed to the state fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, mock.Anything, mock.Anything).Return(fungibletypes.ForeignCoins{}, false) - //Successfully mock SaveFailedOutBound + //Successfully mock SaveFailedOutbound keepertest.MockSaveOutBound(observerMock, ctx, cctx, tss) msgServer := keeper.NewMsgServerImpl(*k) @@ -703,7 +703,7 @@ func TestKeeper_SaveFailedOutBound(t *testing.T) { HashList: nil, }) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.SaveFailedOutBound(ctx, cctx, sample.String(), sample.ZetaIndex(t)) + k.SaveFailedOutbound(ctx, cctx, sample.String(), sample.ZetaIndex(t)) require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) require.False(t, found) @@ -721,7 +721,7 @@ func TestKeeper_SaveSuccessfulOutBound(t *testing.T) { HashList: nil, }) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.SaveSuccessfulOutBound(ctx, cctx, sample.String()) + k.SaveSuccessfulOutbound(ctx, cctx, sample.String()) require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxBallotIndex, sample.String()) _, found := k.GetOutTxTracker(ctx, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) require.False(t, found) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20.go b/x/crosschain/keeper/msg_server_whitelist_erc20.go index 33cdb151c0..6d31a449c8 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20.go @@ -111,7 +111,7 @@ func (k msgServer) WhitelistERC20(goCtx context.Context, msg *types.MsgWhitelist index := hash.Hex() // create a cmd cctx to whitelist the erc20 on the external chain - // TODO : refactor this to use the `InitializeCCTX` function instead. + // TODO : refactor this to use the `NewCCTX` function instead. //https://github.com/zeta-chain/node/issues/1909 cctx := types.CrossChainTx{ Creator: msg.Creator, diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 5ad47d6f1e..76864e8c43 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -35,8 +35,7 @@ func (m CrossChainTx) OriginalDestinationChainID() int64 { return m.OutboundTxParams[0].ReceiverChainId } -// GetAllAuthzZetaclientTxTypes returns all the authz types for zetaclient - +// Validate checks if the CCTX is valid. func (m CrossChainTx) Validate() error { if m.InboundTxParams == nil { return fmt.Errorf("inbound tx params cannot be nil") @@ -137,8 +136,8 @@ func (m CrossChainTx) SetReverted(message string) { m.CctxStatus.ChangeStatus(CctxStatus_Reverted, message) } -// InitializeCCTX initializes the CCTX with the given message and tssPubkey -func InitializeCCTX(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) CrossChainTx { +// NewCCTX initializes the CCTX with the given message and tssPubkey +func NewCCTX(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) (CrossChainTx, error) { index := msg.Digest() if msg.TxOrigin == "" { @@ -185,5 +184,9 @@ func InitializeCCTX(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey s InboundTxParams: inboundParams, OutboundTxParams: []*OutboundTxParams{outBoundParams}, } - return cctx + err := cctx.Validate() + if err != nil { + return CrossChainTx{}, err + } + return cctx, nil } diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 0f6f9c6535..bb60386725 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -47,7 +47,8 @@ func Test_InitializeCCTX(t *testing.T) { Asset: asset, EventIndex: eventIndex, } - cctx := types.InitializeCCTX(ctx, msg, tss.TssPubkey) + cctx, err := types.NewCCTX(ctx, msg, tss.TssPubkey) + require.NoError(t, err) require.Equal(t, receiver.String(), cctx.GetCurrentOutTxParam().Receiver) require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutTxParam().ReceiverChainId) require.Equal(t, sender.String(), cctx.GetInboundTxParams().Sender) @@ -64,6 +65,41 @@ func Test_InitializeCCTX(t *testing.T) { require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) }) + t.Run("should return an error if the cctx is invalid", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + senderChain := common.GoerliChain() + sender := sample.EthAddress() + receiverChain := common.GoerliChain() + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + intxBlockHeight := uint64(420) + intxHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := common.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteOnObservedInboundTx{ + Creator: creator, + Sender: "invalid", + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InTxHash: intxHash.String(), + InBlockHeight: intxBlockHeight, + GasLimit: gasLimit, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + _, err := types.NewCCTX(ctx, msg, tss.TssPubkey) + require.ErrorContains(t, err, "invalid address") + }) } func TestCrossChainTx_Validate(t *testing.T) { diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index bfdef64cc2..62720aaf66 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -41,6 +41,4 @@ var ( ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") - - ErrInvalidCCTXIndex = errorsmod.Register(ModuleName, 1151, "invalid cctx index") ) diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index ab572e3cb6..719f54687f 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -27,6 +27,7 @@ const ( ProtocolFee = 2000000000000000000 //TssMigrationGasMultiplierEVM is multiplied to the median gas price to get the gas price for the tss migration . This is done to avoid the tss migration tx getting stuck in the mempool TssMigrationGasMultiplierEVM = "2.5" + ZetaIndexLength = 66 ) func GetProtocolFee() sdk.Uint { diff --git a/x/crosschain/types/message_abort_stuck_cctx.go b/x/crosschain/types/message_abort_stuck_cctx.go index 47c383276b..86a1f31ec6 100644 --- a/x/crosschain/types/message_abort_stuck_cctx.go +++ b/x/crosschain/types/message_abort_stuck_cctx.go @@ -43,8 +43,8 @@ func (msg *MsgAbortStuckCCTX) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if len(msg.CctxIndex) != 66 { - return ErrInvalidCCTXIndex + if len(msg.CctxIndex) != ZetaIndexLength { + return ErrInvalidIndexValue } return nil } diff --git a/x/crosschain/types/message_abort_stuck_cctx_test.go b/x/crosschain/types/message_abort_stuck_cctx_test.go index 14b1e82d78..5b0d539c0f 100644 --- a/x/crosschain/types/message_abort_stuck_cctx_test.go +++ b/x/crosschain/types/message_abort_stuck_cctx_test.go @@ -24,7 +24,7 @@ func TestMsgAbortStuckCCTX_ValidateBasic(t *testing.T) { { name: "invalid cctx index", msg: types.NewMsgAbortStuckCCTX(sample.AccAddress(), "cctx_index"), - err: types.ErrInvalidCCTXIndex, + err: types.ErrInvalidIndexValue, }, { name: "valid", diff --git a/x/crosschain/types/message_refund_aborted.go b/x/crosschain/types/message_refund_aborted.go index 20115aec21..d019b8ea31 100644 --- a/x/crosschain/types/message_refund_aborted.go +++ b/x/crosschain/types/message_refund_aborted.go @@ -45,7 +45,7 @@ func (msg *MsgRefundAbortedCCTX) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } - if len(msg.CctxIndex) != 66 { + if len(msg.CctxIndex) != ZetaIndexLength { return ErrInvalidIndexValue } if msg.RefundAddress != "" && !ethcommon.IsHexAddress(msg.RefundAddress) { diff --git a/x/crosschain/types/utils.go b/x/crosschain/types/utils.go index 8a1b2a61f7..fa86f790a3 100644 --- a/x/crosschain/types/utils.go +++ b/x/crosschain/types/utils.go @@ -8,10 +8,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" "github.com/zeta-chain/zetacore/common" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +// GetAllAuthzZetaclientTxTypes returns all the authz types for zetaclient func GetAllAuthzZetaclientTxTypes() []string { return []string{ sdk.MsgTypeURL(&MsgGasPriceVoter{}), @@ -24,12 +26,15 @@ func GetAllAuthzZetaclientTxTypes() []string { } } +// ValidateZetaIndex validates the zeta index func ValidateZetaIndex(index string) error { - if len(index) != 66 { - return fmt.Errorf("invalid index hash %s", index) + if len(index) != ZetaIndexLength { + return errors.Wrap(ErrInvalidIndexValue, fmt.Sprintf("invalid index length %d", len(index))) } return nil } + +// ValidateHashForChain validates the hash for the chain func ValidateHashForChain(hash string, chainID int64) error { if common.IsEthereumChain(chainID) || common.IsZetaChain(chainID) { _, err := hexutil.Decode(hash) @@ -51,6 +56,7 @@ func ValidateHashForChain(hash string, chainID int64) error { return fmt.Errorf("invalid chain id %d", chainID) } +// ValidateAddressForChain validates the address for the chain func ValidateAddressForChain(address string, chainID int64) error { // we do not validate the address for zeta chain as the address field can be btc or eth address if common.IsZetaChain(chainID) { From b79405d7ce1c87622797c5c69143bc8872271099 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 21 Mar 2024 23:56:13 -0400 Subject: [PATCH 28/36] modify comments based on suggestions --- x/crosschain/keeper/evm_hooks_test.go | 5 +++++ x/crosschain/keeper/msg_server_vote_inbound_tx.go | 7 ++++--- x/crosschain/types/cctx.go | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index 8ef8007508..f927f94cf3 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -23,6 +23,9 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +// SetupStateForProcessLogsZetaSent sets up additional state required for processing logs for ZetaSent events +// This sets up the gas coin, zrc20 contract, gas price, zrc20 pool. +// This should be used in conjunction with SetupStateForProcessLogs for processing ZetaSent events func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosschainkeeper.Keeper, zk keepertest.ZetaKeepers, sdkk keepertest.SDKKeepers, chain common.Chain, admin string) { assetAddress := sample.EthAddress().String() @@ -60,6 +63,8 @@ func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosscha ) } +// SetupStateForProcessLogs sets up observer state for required for processing logs +// It deploys system contracts, sets up TSS, gas price, chain nonce's, pending nonce's.These are all required to create a cctx from a log func SetupStateForProcessLogs(t *testing.T, ctx sdk.Context, k *crosschainkeeper.Keeper, zk keepertest.ZetaKeepers, sdkk keepertest.SDKKeepers, chain common.Chain) { deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 0d93ca96e0..b854498815 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -93,14 +93,15 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if !tssFound { return nil, types.ErrCannotFindTSSKeys } - // create a new CCTX from the inbound message. The status of the new CCTX is set to PendingInbound. + // create a new CCTX from the inbound message.The status of the new CCTX is set to PendingInbound. cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey) if err != nil { return nil, err } - // Process the inbound CCTX, the process function manages the state commit and cctx status change.If the process fails the changes to the evm state are rolled back. + // Process the inbound CCTX, the process function manages the state commit and cctx status change. + // If the process fails, the changes to the evm state are rolled back. k.ProcessInbound(ctx, &cctx) - // Save the inbound CCTX to the store.This is called irrespective of the status of the CCTX or the outcome of the process function. + // Save the inbound CCTX to the store. This is called irrespective of the status of the CCTX or the outcome of the process function. k.SaveInbound(ctx, &cctx, msg.EventIndex) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 76864e8c43..dab3861fc6 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -136,7 +136,8 @@ func (m CrossChainTx) SetReverted(message string) { m.CctxStatus.ChangeStatus(CctxStatus_Reverted, message) } -// NewCCTX initializes the CCTX with the given message and tssPubkey +// NewCCTX creates a new CCTX.From a MsgVoteOnObservedInboundTx message and a TSS pubkey. +// It also validates the created cctx func NewCCTX(ctx sdk.Context, msg MsgVoteOnObservedInboundTx, tssPubkey string) (CrossChainTx, error) { index := msg.Digest() From b67126a276c3a88f779c2d77460743b01a2fd260 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 22 Mar 2024 00:27:54 -0400 Subject: [PATCH 29/36] add error message for add revert --- .../keeper/msg_server_vote_inbound_tx.go | 6 +++- .../keeper/msg_server_vote_inbound_tx_test.go | 33 +++++++++++++++++++ .../keeper/msg_server_vote_outbound_tx.go | 15 +++++---- .../msg_server_vote_outbound_tx_test.go | 28 ++++++++++++++-- x/crosschain/types/cctx.go | 8 +++-- x/crosschain/types/cctx_test.go | 31 ++++++++++------- x/crosschain/types/inbound_params_test.go | 2 +- x/crosschain/types/outbound_params_test.go | 2 +- 8 files changed, 100 insertions(+), 25 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index b854498815..6cf8d252d5 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -153,7 +153,11 @@ func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit } - cctx.AddRevertOutbound(gasLimit) + err = cctx.AddRevertOutbound(gasLimit) + if err != nil { + cctx.SetAbort(fmt.Sprintf("revert outbound error: %s", err.Error())) + return + } // we create a new cached context, and we don't commit the previous one with EVM deposit tmpCtxRevert, commitRevert := ctx.CacheContext() diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index c1c5526b4f..f4f3f27b09 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -435,6 +435,39 @@ func TestKeeper_ProcessZEVMDeposit(t *testing.T) { require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails as the cctx has already been reverted", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.OutboundTxParams = append(cctx.OutboundTxParams, cctx.GetCurrentOutTxParam()) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, fmt.Sprintf("revert outbound error: %s", "cannot revert a revert tx")) + }) } func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index fd79fe7a5c..66e4abf4ae 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -98,10 +98,6 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms k.SaveFailedOutbound(ctx, &cctx, err.Error(), ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } - err = cctx.Validate() - if err != nil { - return nil, err - } k.SaveSuccessfulOutbound(ctx, &cctx, ballotIndex) return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } @@ -210,7 +206,10 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, } // create new OutboundTxParams for the revert - cctx.AddRevertOutbound(gasLimit) + err = cctx.AddRevertOutbound(gasLimit) + if err != nil { + return cosmoserrors.Wrap(err, "AddRevertOutbound") + } err = k.PayGasAndUpdateCctx( ctx, @@ -226,7 +225,7 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, if err != nil { return err } - // Not setting the finalization status here, the required changes have been mad while creating the revert tx + // Not setting the finalization status here, the required changes have been made while creating the revert tx cctx.SetPendingRevert("Outbound failed, start revert") case types.CctxStatus_PendingRevert: cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed @@ -257,6 +256,10 @@ func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballo if err != nil { return err } + err = cctx.Validate() + if err != nil { + return err + } commit() return nil } diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index da811ad8c7..1592bd9bec 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -599,7 +599,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { func TestKeeper_ProcessOutbound(t *testing.T) { t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) require.NoError(t, err) @@ -608,7 +608,7 @@ func TestKeeper_ProcessOutbound(t *testing.T) { t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) cctx.CctxStatus.Status = types.CctxStatus_PendingRevert err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) require.NoError(t, err) @@ -618,7 +618,7 @@ func TestKeeper_ProcessOutbound(t *testing.T) { t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound cctx.InboundTxParams.CoinType = common.CoinType_Cmd err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) @@ -656,6 +656,28 @@ func TestKeeper_ProcessOutbound(t *testing.T) { require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) }) + t.Run("do not process outbound if the cctx has already been reverted once", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.OutboundTxParams = append(cctx.OutboundTxParams, sample.OutboundTxParams(sample.Rand())) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.ErrorContains(t, err, "cannot revert a revert") + }) + t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ UseFungibleMock: true, diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index dab3861fc6..45138232fc 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -23,7 +23,7 @@ func (m CrossChainTx) GetCurrentOutTxParam() *OutboundTxParams { // IsCurrentOutTxRevert returns true if the current outbound tx is the revert tx. func (m CrossChainTx) IsCurrentOutTxRevert() bool { - return len(m.OutboundTxParams) == 2 + return len(m.OutboundTxParams) >= 2 } // OriginalDestinationChainID returns the original destination of the outbound tx, reverted or not @@ -78,7 +78,10 @@ AddRevertOutbound does the following things in one function: 3. update the TxFinalizationStatus of the current OutboundTxParams to Executed. */ -func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) { +func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) error { + if m.IsCurrentOutTxRevert() { + return fmt.Errorf("cannot revert a revert tx") + } revertTxParams := &OutboundTxParams{ Receiver: m.InboundTxParams.Sender, ReceiverChainId: m.InboundTxParams.SenderChainId, @@ -89,6 +92,7 @@ func (m *CrossChainTx) AddRevertOutbound(gasLimit uint64) { // The original outbound has been finalized, the new outbound is pending m.GetCurrentOutTxParam().TxFinalizationStatus = TxFinalizationStatus_Executed m.OutboundTxParams = append(m.OutboundTxParams, revertTxParams) + return nil } // AddOutbound adds a new outbound tx to the CCTX. diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index bb60386725..85bbeb2859 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -117,7 +117,7 @@ func TestCrossChainTx_Validate(t *testing.T) { require.ErrorContains(t, cctx.Validate(), "outbound tx params cannot be more than 2") cctx = sample.CrossChainTx(t, "foo") cctx.Index = "0" - require.ErrorContains(t, cctx.Validate(), "invalid index hash 0") + require.ErrorContains(t, cctx.Validate(), "invalid index length 1") cctx = sample.CrossChainTx(t, "foo") cctx.InboundTxParams = sample.InboundTxParamsValidChainID(rand.New(rand.NewSource(42))) cctx.InboundTxParams.SenderChainId = 1000 @@ -236,16 +236,25 @@ func TestCrossChainTx_AddOutbound(t *testing.T) { } func Test_SetRevertOutboundValues(t *testing.T) { - cctx := sample.CrossChainTx(t, "test") - cctx.OutboundTxParams = cctx.OutboundTxParams[:1] - cctx.AddRevertOutbound(100) - require.Len(t, cctx.OutboundTxParams, 2) - require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) - require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) - require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) - require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) - require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) + t.Run("successfully set revert outbound values", func(t *testing.T) { + cctx := sample.CrossChainTx(t, "test") + cctx.OutboundTxParams = cctx.OutboundTxParams[:1] + err := cctx.AddRevertOutbound(100) + require.NoError(t, err) + require.Len(t, cctx.OutboundTxParams, 2) + require.Equal(t, cctx.GetCurrentOutTxParam().Receiver, cctx.InboundTxParams.Sender) + require.Equal(t, cctx.GetCurrentOutTxParam().ReceiverChainId, cctx.InboundTxParams.SenderChainId) + require.Equal(t, cctx.GetCurrentOutTxParam().Amount, cctx.InboundTxParams.Amount) + require.Equal(t, cctx.GetCurrentOutTxParam().OutboundTxGasLimit, uint64(100)) + require.Equal(t, cctx.GetCurrentOutTxParam().TssPubkey, cctx.OutboundTxParams[0].TssPubkey) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[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) + require.ErrorContains(t, err, "cannot revert a revert tx") + }) } func TestCrossChainTx_SetAbort(t *testing.T) { diff --git a/x/crosschain/types/inbound_params_test.go b/x/crosschain/types/inbound_params_test.go index 88f5121860..aef9dd4dff 100644 --- a/x/crosschain/types/inbound_params_test.go +++ b/x/crosschain/types/inbound_params_test.go @@ -35,7 +35,7 @@ func TestInboundTxParams_Validate(t *testing.T) { inTxParams = sample.InboundTxParamsValidChainID(r) inTxParams.InboundTxObservedHash = sample.Hash().String() inTxParams.InboundTxBallotIndex = "12" - require.ErrorContains(t, inTxParams.Validate(), "invalid index hash 12") + require.ErrorContains(t, inTxParams.Validate(), "invalid index length 2") inTxParams = sample.InboundTxParamsValidChainID(r) inTxParams.InboundTxObservedHash = sample.Hash().String() inTxParams.InboundTxBallotIndex = sample.ZetaIndex(t) diff --git a/x/crosschain/types/outbound_params_test.go b/x/crosschain/types/outbound_params_test.go index 45b724b9e9..b0075ccde7 100644 --- a/x/crosschain/types/outbound_params_test.go +++ b/x/crosschain/types/outbound_params_test.go @@ -25,7 +25,7 @@ func TestOutboundTxParams_Validate(t *testing.T) { require.ErrorContains(t, outTxParams.Validate(), "amount cannot be nil") outTxParams = sample.OutboundTxParamsValidChainID(r) outTxParams.OutboundTxBallotIndex = "12" - require.ErrorContains(t, outTxParams.Validate(), "invalid index hash 12") + require.ErrorContains(t, outTxParams.Validate(), "invalid index length 2") outTxParams = sample.OutboundTxParamsValidChainID(r) outTxParams.OutboundTxBallotIndex = sample.ZetaIndex(t) outTxParams.OutboundTxHash = sample.Hash().String() From 2c856b06d8026602ae5118c27cf657bf42a04bb9 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 22 Mar 2024 13:13:31 -0400 Subject: [PATCH 30/36] replace broken eth rpc --- common/headers_test.go | 2 +- .../keeper/msg_server_vote_inbound_tx.go | 117 ------ .../keeper/msg_server_vote_inbound_tx_test.go | 342 +---------------- .../keeper/msg_server_vote_outbound_tx.go | 121 +----- .../msg_server_vote_outbound_tx_test.go | 273 -------------- x/crosschain/keeper/process_inbound.go | 125 ++++++ x/crosschain/keeper/process_inbound_test.go | 355 ++++++++++++++++++ x/crosschain/keeper/process_outbound_test.go | 288 ++++++++++++++ x/crosschain/keeper/processs_outbound.go | 126 +++++++ x/crosschain/types/authz.go | 19 + x/crosschain/types/authz_test.go | 19 + x/crosschain/types/{utils.go => validate.go} | 17 +- .../types/{utils_test.go => validate_test.go} | 0 13 files changed, 937 insertions(+), 867 deletions(-) create mode 100644 x/crosschain/keeper/process_inbound.go create mode 100644 x/crosschain/keeper/process_inbound_test.go create mode 100644 x/crosschain/keeper/process_outbound_test.go create mode 100644 x/crosschain/keeper/processs_outbound.go create mode 100644 x/crosschain/types/authz.go create mode 100644 x/crosschain/types/authz_test.go rename x/crosschain/types/{utils.go => validate.go} (76%) rename x/crosschain/types/{utils_test.go => validate_test.go} (100%) diff --git a/common/headers_test.go b/common/headers_test.go index db0bc002d4..d519a65066 100644 --- a/common/headers_test.go +++ b/common/headers_test.go @@ -24,7 +24,7 @@ import ( const numHeadersToTest = 100 func generateHeader() { - rpcclient, _ := ethclient.Dial("https://eth.llamarpc.com") + rpcclient, _ := ethclient.Dial("https://ethereum.blockpi.network/v1/rpc/public") header, _ := rpcclient.HeaderByNumber(context.Background(), big.NewInt(18495266)) file, _ := os.Create("testdata/eth_header_18495266.json") b, _ := header.MarshalJSON() diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 6cf8d252d5..5d36965647 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -6,7 +6,6 @@ import ( cosmoserrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -106,122 +105,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg return &types.MsgVoteOnObservedInboundTxResponse{}, nil } -// ProcessInbound processes the inbound CCTX. -// It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. -// The internal functions handle the state changes and error handling. -func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { - if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { - k.ProcessZEVMDeposit(ctx, cctx) - } else { - k.ProcessCrosschainMsgPassing(ctx, cctx) - } -} - -/* -ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain.It trasnsitions state according to the following rules: - - If the deposit is successful, the CCTX status is changed to OutboundMined. - - If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. - - If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. - - If the creation of revert tx also fails it changes the status to Aborted. - -Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. -We do not return an error from this function , as all changes need to be persisted to the state. -Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. -*/ -func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { - tmpCtx, commit := ctx.CacheContext() - isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) - - if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - cctx.SetAbort(err.Error()) - return - } else if err != nil && isContractReverted { // contract call reverted; should refund - revertMessage := err.Error() - senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) - if senderChain == nil { - cctx.SetAbort(fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId)) - return - } - - gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) - if err != nil { - cctx.SetAbort(fmt.Sprintf("revert gas limit error: %s", err.Error())) - return - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit - } - - err = cctx.AddRevertOutbound(gasLimit) - if err != nil { - cctx.SetAbort(fmt.Sprintf("revert outbound error: %s", err.Error())) - return - } - - // we create a new cached context, and we don't commit the previous one with EVM deposit - tmpCtxRevert, commitRevert := ctx.CacheContext() - err = func() error { - err := k.PayGasAndUpdateCctx( - tmpCtxRevert, - senderChain.ChainId, - cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - // Update nonce using senderchain id as this is a revert tx and would go back to the original sender - return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) - }() - if err != nil { - cctx.SetAbort(fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) - return - } - commitRevert() - cctx.SetPendingRevert(revertMessage) - return - } - // successful HandleEVMDeposit; - commit() - cctx.SetOutBoundMined("Remote omnichain contract call completed") - return -} - -/* -ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain.It trasnsitions state according to the following rules: - - If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. - - If the crosschain message passing returns an error, the CCTX status is changed to Aborted. - We do not return an error from this function, as all changes need to be persisted to the state. - Instead, we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. -*/ -func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { - tmpCtx, commit := ctx.CacheContext() - outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId - err := func() error { - err := k.PayGasAndUpdateCctx( - tmpCtx, - outboundReceiverChainID, - cctx, - cctx.InboundTxParams.Amount, - false, - ) - if err != nil { - return err - } - return k.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx) - }() - if err != nil { - // do not commit anything here as the CCTX should be aborted - cctx.SetAbort(err.Error()) - return - } - commit() - cctx.SetPendingOutbound("") - return -} - /* SaveInbound saves the inbound CCTX to the store.It does the following: - Emits an event for the finalized inbound CCTX. - Adds the inbound CCTX to the finalized inbound CCTX store.This is done to prevent double spending, using the same inbound tx hash and event index. diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index f4f3f27b09..5c20c41049 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -2,21 +2,19 @@ package keeper_test import ( "encoding/hex" - "fmt" "math/big" "testing" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/crosschain/keeper" + "github.com/zeta-chain/zetacore/x/crosschain/types" - fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -210,344 +208,6 @@ func TestStatus_ChangeStatus(t *testing.T) { } } -func TestKeeper_ProcessZEVMDeposit(t *testing.T) { - t.Run("process zevm deposit successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - - // expect DepositCoinZeta to be called - fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). - Return(nil) - - // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.InboundTxParams.CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = 0 - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit returns err without reverting", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - - // mock unsuccessful HandleEVMDeposit which does not revert - fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). - Return(fmt.Errorf("deposit error"), false) - - // call ProcessZEVMDeposit - cctx := sample.CrossChainTx(t, "test") - cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} - cctx.GetCurrentOutTxParam().Receiver = receiver.String() - cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) - cctx.InboundTxParams.CoinType = common.CoinType_Zeta - cctx.GetInboundTxParams().SenderChainId = 0 - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at GetSupportedChainFromChainID", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // mock unsuccessful GetSupportedChainFromChainID - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock unsuccessful GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{}, false) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("revert gas limit error: %s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // Setup expected calls - errDeposit := fmt.Errorf("deposit failed") - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - observerMock := keepertest.GetCrosschainObserverMock(t, k) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock unsuccessful PayGasInERC20AndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at UpdateNonce", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // Mock unsuccessful UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) - require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) - require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - }) - - t.Run("unable to process zevm deposit HandleEVMDeposit revert fails as the cctx has already been reverted", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - errDeposit := fmt.Errorf("deposit failed") - - // Setup expected calls - // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true - keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) - - // Mock successful GetSupportedChainFromChainID - keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // call ProcessZEVMDeposit - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.OutboundTxParams = append(cctx.OutboundTxParams, cctx.GetCurrentOutTxParam()) - k.ProcessZEVMDeposit(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Contains(t, cctx.CctxStatus.StatusMessage, fmt.Sprintf("revert outbound error: %s", "cannot revert a revert tx")) - }) -} - -func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { - t.Run("process crosschain msg passing successfully", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") - - // mock successful UpdateNonce - updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) - require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) - }) - - t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock unsuccessful PayGasAndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). - Return(nil).Once() - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) - }) - - t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - receiverChain := getValidEthChain(t) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") - - // mock unsuccessful UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - // call ProcessCrosschainMsgPassing - cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) - k.ProcessCrosschainMsgPassing(ctx, cctx) - require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") - }) -} - func TestKeeper_SaveInbound(t *testing.T) { t.Run("should save the cctx", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 66e4abf4ae..364241786f 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -9,10 +9,8 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) // VoteOnObservedOutboundTx casts a vote on an outbound transaction observed on a connected chain (after @@ -104,6 +102,8 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms // FundStabilityPool funds the stability pool with the remaining fees of an outbound tx // The funds are sent to the gas stability pool associated with the receiver chain +// This wraps the FundGasStabilityPoolFromRemainingFees function and logs an error if it fails.We do not return an error here. +// Event if the funding fails, the outbound tx is still processed. func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) { // Fund the gas stability pool with the remaining funds if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutTxParam(), cctx.GetCurrentOutTxParam().ReceiverChainId); err != nil { @@ -147,123 +147,6 @@ func percentOf(n *big.Int, percent int64) *big.Int { return n } -/* ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: - - 1. Change the status of the CCTX from - - PendingRevert to Reverted - - PendingOutbound to OutboundMined - - 2. Set the finalization status of the current outbound tx to executed - - 3. Emit an event for the successful outbound transaction -*/ - -func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { - oldStatus := cctx.CctxStatus.Status - switch oldStatus { - case types.CctxStatus_PendingRevert: - cctx.SetReverted("Outbound succeeded, revert executed") - case types.CctxStatus_PendingOutbound: - cctx.SetOutBoundMined("Outbound succeeded, mined") - default: - return - } - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) -} - -/* -ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: - - 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX - - 2. For other CCTX - - If the CCTX is in PendingOutbound, it creates a revert tx and sets the finalization status of the current outbound tx to executed - - If the CCTX is in PendingRevert, it sets the Status to Aborted - - 3. Emit an event for the failed outbound transaction - - 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction -*/ -func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { - oldStatus := cctx.CctxStatus.Status - if cctx.InboundTxParams.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { - // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") - } else { - switch oldStatus { - case types.CctxStatus_PendingOutbound: - - gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) - if err != nil { - return cosmoserrors.Wrap(err, "GetRevertGasLimit") - } - if gasLimit == 0 { - // use same gas limit of outbound as a fallback -- should not happen - gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit - } - - // create new OutboundTxParams for the revert - err = cctx.AddRevertOutbound(gasLimit) - if err != nil { - return cosmoserrors.Wrap(err, "AddRevertOutbound") - } - - err = k.PayGasAndUpdateCctx( - ctx, - cctx.InboundTxParams.SenderChainId, - cctx, - cctx.OutboundTxParams[0].Amount, - false, - ) - if err != nil { - return err - } - err = k.UpdateNonce(ctx, cctx.InboundTxParams.SenderChainId, cctx) - if err != nil { - return err - } - // Not setting the finalization status here, the required changes have been made while creating the revert tx - cctx.SetPendingRevert("Outbound failed, start revert") - case types.CctxStatus_PendingRevert: - cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.SetAbort("Outbound failed: revert failed; abort TX") - } - } - newStatus := cctx.CctxStatus.Status.String() - EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) - return nil -} - -// ProcessOutbound processes the finalization of an outbound transaction based on the ballot status -// The state is committed only if the individual steps are successful -func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotStatus observertypes.BallotStatus, valueReceived string) error { - tmpCtx, commit := ctx.CacheContext() - err := func() error { - switch ballotStatus { - case observertypes.BallotStatus_BallotFinalized_SuccessObservation: - k.ProcessSuccessfulOutbound(tmpCtx, cctx, valueReceived) - case observertypes.BallotStatus_BallotFinalized_FailureObservation: - err := k.ProcessFailedOutbound(tmpCtx, cctx, valueReceived) - if err != nil { - return err - } - } - return nil - }() - if err != nil { - return err - } - err = cctx.Validate() - if err != nil { - return err - } - commit() - return nil -} - /* SaveFailedOutbound saves a failed outbound transaction.It does the following things in one function: diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index 1592bd9bec..38a49c2957 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -441,279 +441,6 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { }) } -func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - // transition to reverted if pending revert - cctx.CctxStatus.Status = types.CctxStatus_PendingRevert - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Reverted) - // transition to outbound mined if pending outbound - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) - // do nothing if it's in any other state - k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) -} - -func TestKeeper_ProcessFailedOutbound(t *testing.T) { - t.Run("successfully process failed outbound set to aborted for type cmd", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.InboundTxParams.CoinType = common.CoinType_Cmd - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process failed outbound set to aborted for withdraw tx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := sample.CrossChainTx(t, "test") - cctx.InboundTxParams.SenderChainId = common.ZetaChainMainnet().ChainId - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process failed outbound set to pending revert", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) - require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) - require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) - - }) - - t.Run("unable to process revert when update nonce fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock failed UpdateNonce - observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). - Return(observertypes.ChainNonces{}, false) - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, types.ErrCannotFindReceiverNonce) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) - - t.Run("unable to process revert when PayGasAndUpdateCctx fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). - Return(nil).Once() - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, observertypes.ErrSupportedChains) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) - - t.Run("unable to process revert when GetRevertGasLimit fails", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - // mock failed GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, false).Once() - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) - require.ErrorIs(t, err, types.ErrForeignCoinNotFound) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - }) -} - -func TestKeeper_ProcessOutbound(t *testing.T) { - t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) - }) - - t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) - cctx.CctxStatus.Status = types.CctxStatus_PendingRevert - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - cctx.InboundTxParams.CoinType = common.CoinType_Cmd - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) - - t.Run("do not process outbound on error, no new outbound created", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - oldOutTxParamsLen := len(cctx.OutboundTxParams) - // mock failed GetRevertGasLimit for ERC20 - fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). - Return(fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().String(), - }, false).Once() - - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.ErrorIs(t, err, types.ErrForeignCoinNotFound) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) - // New outbound not added and the old outbound is not finalized - require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) - }) - - t.Run("do not process outbound if the cctx has already been reverted once", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.OutboundTxParams = append(cctx.OutboundTxParams, sample.OutboundTxParams(sample.Rand())) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.ErrorContains(t, err, "cannot revert a revert") - }) - - t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ - UseFungibleMock: true, - UseObserverMock: true, - }) - - // Setup mock data - fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) - observerMock := keepertest.GetCrosschainObserverMock(t, k) - receiver := sample.EthAddress() - amount := big.NewInt(42) - senderChain := getValidEthChain(t) - asset := "" - - cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) - cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - oldOutTxParamsLen := len(cctx.OutboundTxParams) - // mock successful GetRevertGasLimit for ERC20 - keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) - - // mock successful PayGasAndUpdateCctx - keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) - - // mock successful UpdateNonce - _ = keepertest.MockUpdateNonce(observerMock, *senderChain) - - err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) - require.NoError(t, err) - require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) - // New outbound added for revert and the old outbound is finalized - require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen+1) - require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) - require.Equal(t, cctx.OutboundTxParams[oldOutTxParamsLen-1].TxFinalizationStatus, types.TxFinalizationStatus_Executed) - }) -} - func TestKeeper_SaveFailedOutBound(t *testing.T) { t.Run("successfully save failed outbound", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/process_inbound.go b/x/crosschain/keeper/process_inbound.go new file mode 100644 index 0000000000..3f1128f512 --- /dev/null +++ b/x/crosschain/keeper/process_inbound.go @@ -0,0 +1,125 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// ProcessInbound processes the inbound CCTX. +// It does a conditional dispatch to ProcessZEVMDeposit or ProcessCrosschainMsgPassing based on the receiver chain. +// The internal functions handle the state changes and error handling. +func (k Keeper) ProcessInbound(ctx sdk.Context, cctx *types.CrossChainTx) { + if common.IsZetaChain(cctx.GetCurrentOutTxParam().ReceiverChainId) { + k.ProcessZEVMDeposit(ctx, cctx) + } else { + k.ProcessCrosschainMsgPassing(ctx, cctx) + } +} + +/* +ProcessZEVMDeposit processes the EVM deposit CCTX. A deposit is a cctx which has Zetachain as the receiver chain.It trasnsitions state according to the following rules: + - If the deposit is successful, the CCTX status is changed to OutboundMined. + - If the deposit returns an internal error i.e if HandleEVMDeposit() returns an error, but isContractReverted is false, the CCTX status is changed to Aborted. + - If the deposit is reverted, the function tries to create a revert cctx with status PendingRevert. + - If the creation of revert tx also fails it changes the status to Aborted. + +Note : Aborted CCTXs are not refunded in this function. The refund is done using a separate refunding mechanism. +We do not return an error from this function , as all changes need to be persisted to the state. +Instead we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to OutboundMined. +*/ +func (k Keeper) ProcessZEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + isContractReverted, err := k.HandleEVMDeposit(tmpCtx, cctx) + + if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX + cctx.SetAbort(err.Error()) + return + } else if err != nil && isContractReverted { // contract call reverted; should refund + revertMessage := err.Error() + senderChain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, cctx.InboundTxParams.SenderChainId) + if senderChain == nil { + cctx.SetAbort(fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId)) + return + } + + gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) + if err != nil { + cctx.SetAbort(fmt.Sprintf("revert gas limit error: %s", err.Error())) + return + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.GetCurrentOutTxParam().OutboundTxGasLimit + } + + err = cctx.AddRevertOutbound(gasLimit) + if err != nil { + cctx.SetAbort(fmt.Sprintf("revert outbound error: %s", err.Error())) + return + } + + // we create a new cached context, and we don't commit the previous one with EVM deposit + tmpCtxRevert, commitRevert := ctx.CacheContext() + err = func() error { + err := k.PayGasAndUpdateCctx( + tmpCtxRevert, + senderChain.ChainId, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + // Update nonce using senderchain id as this is a revert tx and would go back to the original sender + return k.UpdateNonce(tmpCtxRevert, senderChain.ChainId, cctx) + }() + if err != nil { + cctx.SetAbort(fmt.Sprintf("deposit revert message: %s err : %s", revertMessage, err.Error())) + return + } + commitRevert() + cctx.SetPendingRevert(revertMessage) + return + } + // successful HandleEVMDeposit; + commit() + cctx.SetOutBoundMined("Remote omnichain contract call completed") + return +} + +/* +ProcessCrosschainMsgPassing processes the CCTX for crosschain message passing. A crosschain message passing is a cctx which has a non-Zetachain as the receiver chain.It trasnsitions state according to the following rules: + - If the crosschain message passing is successful, the CCTX status is changed to PendingOutbound. + - If the crosschain message passing returns an error, the CCTX status is changed to Aborted. + We do not return an error from this function, as all changes need to be persisted to the state. + Instead, we use a temporary context to make changes and then commit the context on for the happy path ,i.e cctx is set to PendingOutbound. +*/ +func (k Keeper) ProcessCrosschainMsgPassing(ctx sdk.Context, cctx *types.CrossChainTx) { + tmpCtx, commit := ctx.CacheContext() + outboundReceiverChainID := cctx.GetCurrentOutTxParam().ReceiverChainId + err := func() error { + err := k.PayGasAndUpdateCctx( + tmpCtx, + outboundReceiverChainID, + cctx, + cctx.InboundTxParams.Amount, + false, + ) + if err != nil { + return err + } + return k.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx) + }() + if err != nil { + // do not commit anything here as the CCTX should be aborted + cctx.SetAbort(err.Error()) + return + } + commit() + cctx.SetPendingOutbound("") + return +} diff --git a/x/crosschain/keeper/process_inbound_test.go b/x/crosschain/keeper/process_inbound_test.go new file mode 100644 index 0000000000..dd8acb6c97 --- /dev/null +++ b/x/crosschain/keeper/process_inbound_test.go @@ -0,0 +1,355 @@ +package keeper_test + +import ( + "fmt" + "math/big" + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_ProcessZEVMDeposit(t *testing.T) { + t.Run("process zevm deposit successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + // expect DepositCoinZeta to be called + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(nil) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit returns err without reverting", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + + // mock unsuccessful HandleEVMDeposit which does not revert + fungibleMock.On("DepositCoinZeta", mock.Anything, receiver, amount). + Return(fmt.Errorf("deposit error"), false) + + // call ProcessZEVMDeposit + cctx := sample.CrossChainTx(t, "test") + cctx.CctxStatus = &types.Status{Status: types.CctxStatus_PendingInbound} + cctx.GetCurrentOutTxParam().Receiver = receiver.String() + cctx.GetInboundTxParams().Amount = sdkmath.NewUintFromBigInt(amount) + cctx.InboundTxParams.CoinType = common.CoinType_Zeta + cctx.GetInboundTxParams().SenderChainId = 0 + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at GetSupportedChainFromChainID", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // mock unsuccessful GetSupportedChainFromChainID + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("invalid sender chain id %d", cctx.InboundTxParams.SenderChainId), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at and GetRevertGasLimit", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock unsuccessful GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{}, false) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("revert gas limit error: %s", types.ErrForeignCoinNotFound), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails at PayGasInERC20AndUpdateCctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // Setup expected calls + errDeposit := fmt.Errorf("deposit failed") + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + observerMock := keepertest.GetCrosschainObserverMock(t, k) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock unsuccessful PayGasInERC20AndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, fmt.Sprintf("deposit revert message: %s err : %s", errDeposit, observertypes.ErrSupportedChains), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit reverts fails at UpdateNonce", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // Mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *senderChain) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) + require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + }) + + t.Run("unable to process zevm deposit HandleEVMDeposit revert fails as the cctx has already been reverted", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + errDeposit := fmt.Errorf("deposit failed") + + // Setup expected calls + // mock unsuccessful HandleEVMDeposit which reverts , i.e returns err and isContractReverted = true + keepertest.MockRevertForHandleEVMDeposit(fungibleMock, receiver, amount, senderChain.ChainId, errDeposit) + + // Mock successful GetSupportedChainFromChainID + keepertest.MockGetSupportedChainFromChainID(observerMock, senderChain) + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // call ProcessZEVMDeposit + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.OutboundTxParams = append(cctx.OutboundTxParams, cctx.GetCurrentOutTxParam()) + k.ProcessZEVMDeposit(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, fmt.Sprintf("revert outbound error: %s", "cannot revert a revert tx")) + }) +} + +func TestKeeper_ProcessCrosschainMsgPassing(t *testing.T) { + t.Run("process crosschain msg passing successfully", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock successful UpdateNonce + updatedNonce := keepertest.MockUpdateNonce(observerMock, *receiverChain) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) + require.Equal(t, updatedNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce) + }) + + t.Run("unable to process crosschain msg passing PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock unsuccessful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). + Return(nil).Once() + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) + }) + + t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + receiverChain := getValidEthChain(t) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") + + // mock unsuccessful UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, receiverChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + // call ProcessCrosschainMsgPassing + cctx := GetERC20Cctx(t, receiver, *receiverChain, "", amount) + k.ProcessCrosschainMsgPassing(ctx, cctx) + require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) + require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + }) +} diff --git a/x/crosschain/keeper/process_outbound_test.go b/x/crosschain/keeper/process_outbound_test.go new file mode 100644 index 0000000000..9cbd4e4710 --- /dev/null +++ b/x/crosschain/keeper/process_outbound_test.go @@ -0,0 +1,288 @@ +package keeper_test + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_ProcessSuccessfulOutbound(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + // transition to reverted if pending revert + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Reverted) + // transition to outbound mined if pending outbound + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + // do nothing if it's in any other state + k.ProcessSuccessfulOutbound(ctx, cctx, sample.String()) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) +} + +func TestKeeper_ProcessFailedOutbound(t *testing.T) { + t.Run("successfully process failed outbound set to aborted for type cmd", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.CoinType = common.CoinType_Cmd + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to aborted for withdraw tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.SenderChainId = common.ZetaChainMainnet().ChainId + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process failed outbound set to pending revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + require.Equal(t, types.TxFinalizationStatus_NotFinalized, cctx.GetCurrentOutTxParam().TxFinalizationStatus) + require.Equal(t, types.TxFinalizationStatus_Executed, cctx.OutboundTxParams[0].TxFinalizationStatus) + + }) + + t.Run("unable to process revert when update nonce fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock failed UpdateNonce + observerMock.On("GetChainNonces", mock.Anything, senderChain.ChainName.String()). + Return(observertypes.ChainNonces{}, false) + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrCannotFindReceiverNonce) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when PayGasAndUpdateCctx fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + observerMock.On("GetSupportedChainFromChainID", mock.Anything, senderChain.ChainId). + Return(nil).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, observertypes.ErrSupportedChains) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) + + t.Run("unable to process revert when GetRevertGasLimit fails", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + }) +} + +func TestKeeper_ProcessOutbound(t *testing.T) { + t.Run("successfully process outbound with ballot finalized to success", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_SuccessObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + }) + + t.Run("successfully process outbound with ballot finalized to failed and old status is Pending Revert", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) + cctx.CctxStatus.Status = types.CctxStatus_PendingRevert + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("successfully process outbound with ballot finalized to failed and coin-type is CMD", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := GetERC20Cctx(t, sample.EthAddress(), common.GoerliChain(), "", big.NewInt(42)) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.InboundTxParams.CoinType = common.CoinType_Cmd + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("do not process outbound on error, no new outbound created", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock failed GetRevertGasLimit for ERC20 + fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId). + Return(fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + }, false).Once() + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.ErrorIs(t, err, types.ErrForeignCoinNotFound) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingOutbound) + // New outbound not added and the old outbound is not finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + }) + + t.Run("do not process outbound if the cctx has already been reverted once", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.OutboundTxParams = append(cctx.OutboundTxParams, sample.OutboundTxParams(sample.Rand())) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.ErrorContains(t, err, "cannot revert a revert") + }) + + t.Run("successfully revert a outbound and create a new revert tx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + UseObserverMock: true, + }) + + // Setup mock data + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + observerMock := keepertest.GetCrosschainObserverMock(t, k) + receiver := sample.EthAddress() + amount := big.NewInt(42) + senderChain := getValidEthChain(t) + asset := "" + + cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + oldOutTxParamsLen := len(cctx.OutboundTxParams) + // mock successful GetRevertGasLimit for ERC20 + keepertest.MockGetRevertGasLimitForERC20(fungibleMock, asset, *senderChain) + + // mock successful PayGasAndUpdateCctx + keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *senderChain, asset) + + // mock successful UpdateNonce + _ = keepertest.MockUpdateNonce(observerMock, *senderChain) + + err := k.ProcessOutbound(ctx, cctx, observertypes.BallotStatus_BallotFinalized_FailureObservation, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_PendingRevert) + // New outbound added for revert and the old outbound is finalized + require.Len(t, cctx.OutboundTxParams, oldOutTxParamsLen+1) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_NotFinalized) + require.Equal(t, cctx.OutboundTxParams[oldOutTxParamsLen-1].TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) +} diff --git a/x/crosschain/keeper/processs_outbound.go b/x/crosschain/keeper/processs_outbound.go new file mode 100644 index 0000000000..c18032e425 --- /dev/null +++ b/x/crosschain/keeper/processs_outbound.go @@ -0,0 +1,126 @@ +package keeper + +import ( + cosmoserrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +/* ProcessSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function: + + 1. Change the status of the CCTX from + - PendingRevert to Reverted + - PendingOutbound to OutboundMined + + 2. Set the finalization status of the current outbound tx to executed + + 3. Emit an event for the successful outbound transaction +*/ + +func (k Keeper) ProcessSuccessfulOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) { + oldStatus := cctx.CctxStatus.Status + switch oldStatus { + case types.CctxStatus_PendingRevert: + cctx.SetReverted("Outbound succeeded, revert executed") + case types.CctxStatus_PendingOutbound: + cctx.SetOutBoundMined("Outbound succeeded, mined") + default: + return + } + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundSuccess(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) +} + +/* +ProcessFailedOutbound processes a failed outbound transaction. It does the following things in one function: + + 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX + + 2. For other CCTX + - If the CCTX is in PendingOutbound, it creates a revert tx and sets the finalization status of the current outbound tx to executed + - If the CCTX is in PendingRevert, it sets the Status to Aborted + + 3. Emit an event for the failed outbound transaction + + 4. Set the finalization status of the current outbound tx to executed. If a revert tx is is created, the finalization status is not set, it would get set when the revert is processed via a subsequent transaction +*/ +func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error { + oldStatus := cctx.CctxStatus.Status + if cctx.InboundTxParams.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { + // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") + } else { + switch oldStatus { + case types.CctxStatus_PendingOutbound: + + gasLimit, err := k.GetRevertGasLimit(ctx, *cctx) + if err != nil { + return cosmoserrors.Wrap(err, "GetRevertGasLimit") + } + if gasLimit == 0 { + // use same gas limit of outbound as a fallback -- should not happen + gasLimit = cctx.OutboundTxParams[0].OutboundTxGasLimit + } + + // create new OutboundTxParams for the revert + err = cctx.AddRevertOutbound(gasLimit) + if err != nil { + return cosmoserrors.Wrap(err, "AddRevertOutbound") + } + + err = k.PayGasAndUpdateCctx( + ctx, + cctx.InboundTxParams.SenderChainId, + cctx, + cctx.OutboundTxParams[0].Amount, + false, + ) + if err != nil { + return err + } + err = k.UpdateNonce(ctx, cctx.InboundTxParams.SenderChainId, cctx) + if err != nil { + return err + } + // Not setting the finalization status here, the required changes have been made while creating the revert tx + cctx.SetPendingRevert("Outbound failed, start revert") + case types.CctxStatus_PendingRevert: + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.SetAbort("Outbound failed: revert failed; abort TX") + } + } + newStatus := cctx.CctxStatus.Status.String() + EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index) + return nil +} + +// ProcessOutbound processes the finalization of an outbound transaction based on the ballot status +// The state is committed only if the individual steps are successful +func (k Keeper) ProcessOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotStatus observertypes.BallotStatus, valueReceived string) error { + tmpCtx, commit := ctx.CacheContext() + err := func() error { + switch ballotStatus { + case observertypes.BallotStatus_BallotFinalized_SuccessObservation: + k.ProcessSuccessfulOutbound(tmpCtx, cctx, valueReceived) + case observertypes.BallotStatus_BallotFinalized_FailureObservation: + err := k.ProcessFailedOutbound(tmpCtx, cctx, valueReceived) + if err != nil { + return err + } + } + return nil + }() + if err != nil { + return err + } + err = cctx.Validate() + if err != nil { + return err + } + commit() + return nil +} diff --git a/x/crosschain/types/authz.go b/x/crosschain/types/authz.go new file mode 100644 index 0000000000..7733a34d7a --- /dev/null +++ b/x/crosschain/types/authz.go @@ -0,0 +1,19 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// GetAllAuthzZetaclientTxTypes returns all the authz types for required for zetaclient +func GetAllAuthzZetaclientTxTypes() []string { + return []string{ + sdk.MsgTypeURL(&MsgGasPriceVoter{}), + sdk.MsgTypeURL(&MsgVoteOnObservedInboundTx{}), + sdk.MsgTypeURL(&MsgVoteOnObservedOutboundTx{}), + sdk.MsgTypeURL(&MsgCreateTSSVoter{}), + sdk.MsgTypeURL(&MsgAddToOutTxTracker{}), + sdk.MsgTypeURL(&observertypes.MsgAddBlameVote{}), + sdk.MsgTypeURL(&observertypes.MsgAddBlockHeader{}), + } +} diff --git a/x/crosschain/types/authz_test.go b/x/crosschain/types/authz_test.go new file mode 100644 index 0000000000..9846949636 --- /dev/null +++ b/x/crosschain/types/authz_test.go @@ -0,0 +1,19 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestGetAllAuthzZetaclientTxTypes(t *testing.T) { + require.Equal(t, []string{"/zetachain.zetacore.crosschain.MsgGasPriceVoter", + "/zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx", + "/zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx", + "/zetachain.zetacore.crosschain.MsgCreateTSSVoter", + "/zetachain.zetacore.crosschain.MsgAddToOutTxTracker", + "/zetachain.zetacore.observer.MsgAddBlameVote", + "/zetachain.zetacore.observer.MsgAddBlockHeader"}, + crosschaintypes.GetAllAuthzZetaclientTxTypes()) +} diff --git a/x/crosschain/types/utils.go b/x/crosschain/types/validate.go similarity index 76% rename from x/crosschain/types/utils.go rename to x/crosschain/types/validate.go index fa86f790a3..9c9f7e6af9 100644 --- a/x/crosschain/types/utils.go +++ b/x/crosschain/types/validate.go @@ -4,28 +4,13 @@ import ( "fmt" "regexp" + "cosmossdk.io/errors" "github.com/btcsuite/btcutil" - sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" "github.com/zeta-chain/zetacore/common" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) -// GetAllAuthzZetaclientTxTypes returns all the authz types for zetaclient -func GetAllAuthzZetaclientTxTypes() []string { - return []string{ - sdk.MsgTypeURL(&MsgGasPriceVoter{}), - sdk.MsgTypeURL(&MsgVoteOnObservedInboundTx{}), - sdk.MsgTypeURL(&MsgVoteOnObservedOutboundTx{}), - sdk.MsgTypeURL(&MsgCreateTSSVoter{}), - sdk.MsgTypeURL(&MsgAddToOutTxTracker{}), - sdk.MsgTypeURL(&observertypes.MsgAddBlameVote{}), - sdk.MsgTypeURL(&observertypes.MsgAddBlockHeader{}), - } -} - // ValidateZetaIndex validates the zeta index func ValidateZetaIndex(index string) error { if len(index) != ZetaIndexLength { diff --git a/x/crosschain/types/utils_test.go b/x/crosschain/types/validate_test.go similarity index 100% rename from x/crosschain/types/utils_test.go rename to x/crosschain/types/validate_test.go From 6af6ba2433aa19284008d1f17a926a61f6100b94 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Fri, 22 Mar 2024 13:19:49 -0400 Subject: [PATCH 31/36] directly modify fungible state in SetupStateForProcessLogsZetaSent --- x/crosschain/keeper/evm_hooks_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index f927f94cf3..df4410b9e6 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -18,7 +18,6 @@ import ( "github.com/zeta-chain/zetacore/testutil/sample" crosschainkeeper "github.com/zeta-chain/zetacore/x/crosschain/keeper" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" - fungiblekeeper "github.com/zeta-chain/zetacore/x/fungible/keeper" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) @@ -42,11 +41,8 @@ func SetupStateForProcessLogsZetaSent(t *testing.T, ctx sdk.Context, k *crosscha ) _, err := zk.FungibleKeeper.UpdateZRC20ProtocolFlatFee(ctx, gasZRC20, big.NewInt(withdrawFee)) - fungibleMsgServer := fungiblekeeper.NewMsgServerImpl(*zk.FungibleKeeper) - _, err = fungibleMsgServer.UpdateZRC20WithdrawFee( - sdk.UnwrapSDKContext(ctx), - fungibletypes.NewMsgUpdateZRC20WithdrawFee(admin, gasZRC20.String(), sdk.NewUint(uint64(withdrawFee)), sdkmath.Uint{}), - ) + require.NoError(t, err) + _, err = zk.FungibleKeeper.UpdateZRC20ProtocolFlatFee(ctx, zrc20Addr, big.NewInt(withdrawFee)) require.NoError(t, err) k.SetGasPrice(ctx, crosschaintypes.GasPrice{ From 861b635a0eac3ff51a6ae22f1c3f2124fab12f1a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 25 Mar 2024 02:06:58 -0400 Subject: [PATCH 32/36] set withdrawals to pending outbound --- x/crosschain/keeper/evm_hooks.go | 3 ++- x/crosschain/keeper/msg_server_vote_outbound_tx.go | 2 +- x/crosschain/types/status.go | 2 +- zetaclient/bitcoin/bitcoin_client.go | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index ef2898313a..02da2bb78c 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -174,7 +174,7 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W if err != nil { return fmt.Errorf("ProcessZRC20WithdrawalEvent: failed to initialize cctx: %s", err.Error()) } - + cctx.SetPendingOutbound("ZRC20 withdrawal event setting to pending outbound directly") // Get gas price and amount gasprice, found := k.GetGasPrice(ctx, receiverChain.ChainId) if !found { @@ -248,6 +248,7 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC if err != nil { return fmt.Errorf("ProcessZetaSentEvent: failed to initialize cctx: %s", err.Error()) } + cctx.SetPendingOutbound("ZetaSent event setting to pending outbound directly") if err := k.PayGasAndUpdateCctx( ctx, diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 364241786f..22afff1218 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -155,7 +155,7 @@ SaveFailedOutbound saves a failed outbound transaction.It does the following thi 2. Save the outbound */ func (k Keeper) SaveFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) { - cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, errMessage) + cctx.SetAbort(errMessage) ctx.Logger().Error(errMessage) k.SaveOutbound(ctx, cctx, ballotIndex) diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index be2b4af62e..44897802d1 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -13,7 +13,7 @@ func (m *Status) AbortRefunded(timeStamp int64) { // empty msg does not overwrite old status message func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { if len(msg) > 0 { - m.StatusMessage = msg + m.StatusMessage = fmt.Sprintf("%s : %s", m.StatusMessage, msg) } if !m.ValidateTransition(newStatus) { m.StatusMessage = fmt.Sprintf("Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", m.Status.String(), newStatus.String(), msg) diff --git a/zetaclient/bitcoin/bitcoin_client.go b/zetaclient/bitcoin/bitcoin_client.go index c45f8e3d61..514447f0d9 100644 --- a/zetaclient/bitcoin/bitcoin_client.go +++ b/zetaclient/bitcoin/bitcoin_client.go @@ -692,7 +692,7 @@ func (ob *BTCChainClient) GetInboundVoteMessageFromBtcEvent(inTx *BTCInTxEvnet) inTx.FromAddress, ob.chain.ChainId, inTx.FromAddress, - inTx.ToAddress, + inTx.FromAddress, ob.zetaClient.ZetaChain().ChainId, cosmosmath.NewUintFromBigInt(amountInt), message, From 3390b3dd960ca0edb4a32157193950b112f2ebd8 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 25 Mar 2024 02:42:41 -0400 Subject: [PATCH 33/36] append status message if not empty --- x/crosschain/types/cctx_test.go | 8 ++++---- x/crosschain/types/status.go | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 85bbeb2859..45b8398d89 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -269,7 +269,7 @@ func TestCrossChainTx_SetPendingRevert(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound cctx.SetPendingRevert("test") require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) - require.Equal(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.StatusMessage, "test") } func TestCrossChainTx_SetPendingOutbound(t *testing.T) { @@ -277,7 +277,7 @@ func TestCrossChainTx_SetPendingOutbound(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingInbound cctx.SetPendingOutbound("test") require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) - require.Equal(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.StatusMessage, "test") } func TestCrossChainTx_SetOutBoundMined(t *testing.T) { @@ -285,7 +285,7 @@ func TestCrossChainTx_SetOutBoundMined(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound cctx.SetOutBoundMined("test") require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) - require.Equal(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.StatusMessage, "test") } func TestCrossChainTx_SetReverted(t *testing.T) { @@ -293,5 +293,5 @@ func TestCrossChainTx_SetReverted(t *testing.T) { cctx.CctxStatus.Status = types.CctxStatus_PendingRevert cctx.SetReverted("test") require.Equal(t, types.CctxStatus_Reverted, cctx.CctxStatus.Status) - require.Equal(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.StatusMessage, "test") } diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index 44897802d1..729b0b9bcb 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -13,7 +13,11 @@ func (m *Status) AbortRefunded(timeStamp int64) { // empty msg does not overwrite old status message func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { if len(msg) > 0 { - m.StatusMessage = fmt.Sprintf("%s : %s", m.StatusMessage, msg) + if m.StatusMessage != "" { + m.StatusMessage = fmt.Sprintf("%s : %s", m.StatusMessage, msg) + } else { + m.StatusMessage = msg + } } if !m.ValidateTransition(newStatus) { m.StatusMessage = fmt.Sprintf("Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", m.Status.String(), newStatus.String(), msg) From a5a43e9c79c9bb3493bddf9cddf9b0153fe81651 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 26 Mar 2024 19:24:16 -0400 Subject: [PATCH 34/36] Update changelog.md Co-authored-by: Lucas Bertrand --- changelog.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/changelog.md b/changelog.md index af72189387..f66e27218a 100644 --- a/changelog.md +++ b/changelog.md @@ -5,10 +5,6 @@ ### Refactor * [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx and vote outbound tx -## Version: v14 - -### Fixes -- [1817](https://github.com/zeta-chain/node/pull/1817) - Add migration script to fix pending and chain nonces on testnet ### Breaking Changes From 40c8aac0e5a12174b19876c6f36cf76288edf2c0 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Tue, 26 Mar 2024 19:49:12 -0400 Subject: [PATCH 35/36] add issue https://github.com/zeta-chain/node/issues/1951 --- changelog.md | 1 + proto/crosschain/cross_chain_tx.proto | 1 + 2 files changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index f66e27218a..29ed04cf1f 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## Unreleased ### Refactor + * [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx and vote outbound tx diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index 166803f6b8..9274947e8d 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -5,6 +5,7 @@ import "common/common.proto"; import "gogoproto/gogo.proto"; //TODO : fix the descriptor numbers for the fields +// https://github.com/zeta-chain/node/issues/1951 option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; enum CctxStatus { From 7e2ac61d358627e2b7faa3d20e2768f570a0ddf4 Mon Sep 17 00:00:00 2001 From: Tanmay Date: Thu, 28 Mar 2024 00:50:13 -0400 Subject: [PATCH 36/36] adjust changelog --- changelog.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 29ed04cf1f..b201c832ee 100644 --- a/changelog.md +++ b/changelog.md @@ -1,12 +1,6 @@ # CHANGELOG ## Unreleased - -### Refactor - -* [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx and vote outbound tx - - ### Breaking Changes * Admin policies have been moved from `observer` to a new module `authority`. @@ -25,6 +19,8 @@ * [1885](https://github.com/zeta-chain/node/pull/1885) - change important metrics on port 8123 to be prometheus compatible * [1863](https://github.com/zeta-chain/node/pull/1863) - remove duplicate ValidateChainParams function * [1914](https://github.com/zeta-chain/node/pull/1914) - move crosschain flags to core context in zetaclient +* [1853](https://github.com/zeta-chain/node/pull/1853) - refactor vote inbound tx and vote outbound tx + ### Features