Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: improve crosschain module coverage #1967

Merged
merged 16 commits into from
Apr 3, 2024
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
* [1879](https://github.com/zeta-chain/node/pull/1879) - full coverage for messages in types packages
* [1899](https://github.com/zeta-chain/node/pull/1899) - add empty test files so packages are included in coverage
* [1903](https://github.com/zeta-chain/node/pull/1903) - common package tests
* [1967](https://github.com/zeta-chain/node/pull/1967) - improve crosschain module coverage

### Fixes

Expand Down
2 changes: 2 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ ignore:
- "x/**/types/types.go"
- "x/**/types/expected_keepers.go"
- "x/**/module.go"
- "x/**/events.go"
- "x/**/migrator.go"
- "x/**/module_simulation.go"
- "x/**/simulation/"
- "**/*.proto"
Expand Down
4 changes: 2 additions & 2 deletions testutil/keeper/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@ func MockGetSupportedChainFromChainID(m *crosschainmocks.CrosschainObserverKeepe
Return(senderChain).Once()

}
func MockGetRevertGasLimitForERC20(m *crosschainmocks.CrosschainFungibleKeeper, asset string, senderChain chains.Chain) {
func MockGetRevertGasLimitForERC20(m *crosschainmocks.CrosschainFungibleKeeper, asset string, senderChain chains.Chain, returnVal int64) {
m.On("GetForeignCoinFromAsset", mock.Anything, asset, senderChain.ChainId).
Return(fungibletypes.ForeignCoins{
Zrc20ContractAddress: sample.EthAddress().String(),
}, true).Once()
m.On("QueryGasLimit", mock.Anything, mock.Anything).
Return(big.NewInt(100), nil).Once()
Return(big.NewInt(returnVal), nil).Once()

}
func MockPayGasAndUpdateCCTX(m *crosschainmocks.CrosschainFungibleKeeper, m2 *crosschainmocks.CrosschainObserverKeeper, ctx sdk.Context, k keeper.Keeper, senderChain chains.Chain, asset string) {
Expand Down
10 changes: 10 additions & 0 deletions testutil/sample/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ func OutTxTracker(t *testing.T, index string) types.OutTxTracker {
}
}

func InTxTracker(t *testing.T, index string) types.InTxTracker {
r := newRandFromStringSeed(t, index)

return types.InTxTracker{
ChainId: r.Int63(),
CoinType: coin.CoinType_Zeta,
TxHash: Hash().Hex(),
}
}

func GasPrice(t *testing.T, index string) *types.GasPrice {
r := newRandFromStringSeed(t, index)

Expand Down
10 changes: 10 additions & 0 deletions x/crosschain/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ func TestGenesis(t *testing.T) {
sample.OutTxTracker(t, "1"),
sample.OutTxTracker(t, "2"),
},
InTxTrackerList: []types.InTxTracker{
sample.InTxTracker(t, "0"),
sample.InTxTracker(t, "1"),
sample.InTxTracker(t, "2"),
},
FinalizedInbounds: []string{
sample.Hash().String(),
sample.Hash().String(),
sample.Hash().String(),
},
GasPriceList: []*types.GasPrice{
sample.GasPrice(t, "0"),
sample.GasPrice(t, "1"),
Expand Down
10 changes: 10 additions & 0 deletions x/crosschain/keeper/cctx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,13 @@ func TestSendQueryPaginated(t *testing.T) {
require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request"))
})
}

func TestKeeper_RemoveCrossChainTx(t *testing.T) {
keeper, ctx, _, zk := keepertest.CrosschainKeeper(t)
zk.ObserverKeeper.SetTSS(ctx, sample.Tss())
txs := createNCctx(keeper, ctx, 5)

keeper.RemoveCrossChainTx(ctx, txs[0].Index)
txs = keeper.GetAllCrossChainTx(ctx)
require.Equal(t, 4, len(txs))
}
4 changes: 2 additions & 2 deletions x/crosschain/keeper/cctx_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// 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 {
chain := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, receiveChainID)
chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID)
if chain == nil {
return zetaObserverTypes.ErrSupportedChains
}
Expand All @@ -30,7 +30,7 @@ func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.C

// SET nonce
cctx.GetCurrentOutTxParam().OutboundTxTssNonce = nonce.Nonce
tss, found := k.zetaObserverKeeper.GetTSS(ctx)
tss, found := k.GetObserverKeeper().GetTSS(ctx)
if !found {
return cosmoserrors.Wrap(types.ErrCannotFindTSSKeys, fmt.Sprintf("Chain(%s) | Identifiers : %s ", chain.ChainName.String(), cctx.LogIdentifierForCCTX()))
}
Expand Down
158 changes: 158 additions & 0 deletions x/crosschain/keeper/cctx_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import (
"testing"

sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/pkg/coin"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
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) {
Expand Down Expand Up @@ -216,3 +219,158 @@ func Test_IsPending(t *testing.T) {
})
}
}

func TestKeeper_UpdateNonce(t *testing.T) {
t.Run("should error if supported chain is nil", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil)

err := k.UpdateNonce(ctx, 5, nil)
require.Error(t, err)
})

t.Run("should error if chain nonces not found", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{
ChainName: 5,
ChainId: 5,
})
observerMock.On("GetChainNonces", mock.Anything, mock.Anything).Return(observertypes.ChainNonces{}, false)
cctx := types.CrossChainTx{
InboundTxParams: &types.InboundTxParams{
Amount: sdkmath.ZeroUint(),
},
OutboundTxParams: []*types.OutboundTxParams{
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
require.Error(t, err)
})

t.Run("should error if tss not found", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{
ChainName: 5,
ChainId: 5,
})
observerMock.On("GetChainNonces", mock.Anything, mock.Anything).Return(observertypes.ChainNonces{
Nonce: 100,
}, true)
observerMock.On("GetTSS", mock.Anything).Return(observertypes.TSS{}, false)
cctx := types.CrossChainTx{
InboundTxParams: &types.InboundTxParams{
Amount: sdkmath.ZeroUint(),
},
OutboundTxParams: []*types.OutboundTxParams{
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
require.Error(t, err)
require.Equal(t, uint64(100), cctx.GetCurrentOutTxParam().OutboundTxTssNonce)
})

t.Run("should error if pending nonces not found", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{
ChainName: 5,
ChainId: 5,
})
observerMock.On("GetChainNonces", mock.Anything, mock.Anything).Return(observertypes.ChainNonces{
Nonce: 100,
}, true)
observerMock.On("GetTSS", mock.Anything).Return(observertypes.TSS{}, true)
observerMock.On("GetPendingNonces", mock.Anything, mock.Anything, mock.Anything).Return(observertypes.PendingNonces{}, false)

cctx := types.CrossChainTx{
InboundTxParams: &types.InboundTxParams{
Amount: sdkmath.ZeroUint(),
},
OutboundTxParams: []*types.OutboundTxParams{
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
require.Error(t, err)
})

t.Run("should error if nonces not equal", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{
ChainName: 5,
ChainId: 5,
})
observerMock.On("GetChainNonces", mock.Anything, mock.Anything).Return(observertypes.ChainNonces{
Nonce: 100,
}, true)
observerMock.On("GetTSS", mock.Anything).Return(observertypes.TSS{}, true)
observerMock.On("GetPendingNonces", mock.Anything, mock.Anything, mock.Anything).Return(observertypes.PendingNonces{
NonceHigh: 99,
}, true)

cctx := types.CrossChainTx{
InboundTxParams: &types.InboundTxParams{
Amount: sdkmath.ZeroUint(),
},
OutboundTxParams: []*types.OutboundTxParams{
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
require.Error(t, err)
})

t.Run("should update nonces", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
})

observerMock := keepertest.GetCrosschainObserverMock(t, k)
observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(&chains.Chain{
ChainName: 5,
ChainId: 5,
})
observerMock.On("GetChainNonces", mock.Anything, mock.Anything).Return(observertypes.ChainNonces{
Nonce: 100,
}, true)
observerMock.On("GetTSS", mock.Anything).Return(observertypes.TSS{}, true)
observerMock.On("GetPendingNonces", mock.Anything, mock.Anything, mock.Anything).Return(observertypes.PendingNonces{
NonceHigh: 100,
}, true)

observerMock.On("SetChainNonces", mock.Anything, mock.Anything).Once()
observerMock.On("SetPendingNonces", mock.Anything, mock.Anything).Once()

cctx := types.CrossChainTx{
InboundTxParams: &types.InboundTxParams{
Amount: sdkmath.ZeroUint(),
},
OutboundTxParams: []*types.OutboundTxParams{
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
require.NoError(t, err)
})
}
72 changes: 72 additions & 0 deletions x/crosschain/keeper/evm_deposit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,78 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) {
fungibleMock.AssertExpectations(t)
})

t.Run("can process ERC20 deposit calling fungible method for contract call", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})

senderChain := getValidEthChainID(t)

fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
receiver := sample.EthAddress()
amount := big.NewInt(42)

// expect DepositCoinZeta to be called
// ZRC20DepositAndCallContract(ctx, from, to, msg.Amount.BigInt(), senderChain, msg.Message, contract, data, msg.CoinType, msg.Asset)
fungibleMock.On(
"ZRC20DepositAndCallContract",
ctx,
mock.Anything,
receiver,
amount,
senderChain,
mock.Anything,
coin.CoinType_ERC20,
mock.Anything,
).Return(&evmtypes.MsgEthereumTxResponse{
Logs: []*evmtypes.Log{},
}, true, nil)

// call HandleEVMDeposit
cctx := sample.CrossChainTx(t, "foo")
cctx.InboundTxParams.TxOrigin = ""
cctx.GetCurrentOutTxParam().Receiver = receiver.String()
cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount)
cctx.GetInboundTxParams().CoinType = coin.CoinType_ERC20
cctx.GetInboundTxParams().Sender = sample.EthAddress().String()
cctx.GetInboundTxParams().SenderChainId = senderChain
cctx.RelayedMessage = ""
cctx.GetInboundTxParams().Asset = ""
reverted, err := k.HandleEVMDeposit(
ctx,
cctx,
)
require.NoError(t, err)
require.False(t, reverted)
fungibleMock.AssertExpectations(t)
})

t.Run("should error if invalid sender", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})

receiver := sample.EthAddress()
amount := big.NewInt(42)

// call HandleEVMDeposit
cctx := sample.CrossChainTx(t, "foo")
cctx.InboundTxParams.TxOrigin = ""
cctx.GetCurrentOutTxParam().Receiver = receiver.String()
cctx.GetInboundTxParams().Amount = math.NewUintFromBigInt(amount)
cctx.GetInboundTxParams().CoinType = coin.CoinType_ERC20
cctx.GetInboundTxParams().Sender = "invalid"
cctx.GetInboundTxParams().SenderChainId = 987
cctx.RelayedMessage = ""
cctx.GetInboundTxParams().Asset = ""
reverted, err := k.HandleEVMDeposit(
ctx,
cctx,
)
require.Error(t, err)
require.False(t, reverted)
})

t.Run("should return error with non-reverted if deposit ERC20 fails with tx non-failed", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
Expand Down
20 changes: 20 additions & 0 deletions x/crosschain/keeper/foreign_coins_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package keeper_test

import (
"testing"

"github.com/stretchr/testify/require"
keepertest "github.com/zeta-chain/zetacore/testutil/keeper"
"github.com/zeta-chain/zetacore/testutil/sample"
)

func TestKeeper_GetAllForeignCoins(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeper(t)
fc := sample.ForeignCoins(t, sample.EthAddress().Hex())
fc.ForeignChainId = 101
k.GetFungibleKeeper().SetForeignCoins(ctx, fc)

res, err := k.GetAllForeignCoins(ctx)
require.NoError(t, err)
require.Equal(t, 1, len(res))
}
Loading
Loading