diff --git a/.github/workflows/build.yml b/.github/workflows/ci.yml similarity index 68% rename from .github/workflows/build.yml rename to .github/workflows/ci.yml index 5e360f442a..518823b42f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: PR Testing +name: ci on: push: @@ -9,7 +9,7 @@ on: pull_request: concurrency: - group: pr-testing-${{ github.head_ref || github.run_id }} + group: ci-${{ github.head_ref || github.run_id }} cancel-in-progress: true env: @@ -93,3 +93,38 @@ jobs: if: always() shell: bash run: rm -rf * + rpcimportable: + runs-on: ubuntu-20.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: go get node + working-directory: contrib/rpcimportable + run: go get github.com/zeta-chain/node@${{github.event.pull_request.head.sha || github.sha}} + env: + GOPROXY: direct + - name: go mod tidy + working-directory: contrib/rpcimportable + run: go mod tidy + - name: show go.mod + working-directory: contrib/rpcimportable + run: cat go.mod + - name: go test + working-directory: contrib/rpcimportable + run: go test ./... + ci-ok: + runs-on: ubuntu-22.04 + needs: + - build-and-test + - rpcimportable + if: always() + steps: + - if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + run: | + echo "One of the jobs failed or was cancelled" + exit 1 + diff --git a/contrib/rpcimportable/go.mod b/contrib/rpcimportable/go.mod new file mode 100644 index 0000000000..32fe6d9e3d --- /dev/null +++ b/contrib/rpcimportable/go.mod @@ -0,0 +1,15 @@ +module github.com/zeta-chain/node/contrib/rpcimportable + +go 1.22.5 + +// this go.mod should be empty when committed +// the go.sum should not be committed + +// this replacement is unavoidable until we upgrade cosmos sdk >=v0.50 +// but we should not tolerate any other replacements +replace ( + github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 +) + +// uncomment this for local development/testing/debugging +// replace github.com/zeta-chain/node => ../.. \ No newline at end of file diff --git a/contrib/rpcimportable/rpcimportable_test.go b/contrib/rpcimportable/rpcimportable_test.go new file mode 100644 index 0000000000..b2bc8959a5 --- /dev/null +++ b/contrib/rpcimportable/rpcimportable_test.go @@ -0,0 +1,11 @@ +package rpcimportable + +import ( + "testing" + + "github.com/zeta-chain/node/pkg/rpc" +) + +func TestRPCImportable(t *testing.T) { + _ = rpc.Clients{} +} diff --git a/go.mod b/go.mod index b169010e38..7625fc2047 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.9.0 - github.com/zeta-chain/ethermint v0.0.0-20240909234716-2fad916e7179 + github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 gitlab.com/thorchain/tss/go-tss v1.6.5 diff --git a/go.sum b/go.sum index b06cf25283..dd2ce7f425 100644 --- a/go.sum +++ b/go.sum @@ -4172,8 +4172,8 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -github.com/zeta-chain/ethermint v0.0.0-20240909234716-2fad916e7179 h1:HykzQOeqBYFHPQCLrj7VAhoGOONtYJnt8IvyHNb9/d8= -github.com/zeta-chain/ethermint v0.0.0-20240909234716-2fad916e7179/go.mod h1:NeQEwcKBpKAUxIsii2F+jfyOD94jN/3fzPMv/1kVF9M= +github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 h1:o0Sh6Y2PKcG634hWqRWmWqBteSuoQUDxIR04OX9Llr8= +github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1/go.mod h1:NeQEwcKBpKAUxIsii2F+jfyOD94jN/3fzPMv/1kVF9M= github.com/zeta-chain/go-ethereum v1.10.26-spc h1:NvY4rR9yw52wfxWt7YoFsWbaIwVMyOtTsWKqGAXk+sE= github.com/zeta-chain/go-ethereum v1.10.26-spc/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7LzxBUfg6sVzV7ilKElQU2DZm8PxJ7KcYI= diff --git a/pkg/rpc/clients_crosschain.go b/pkg/rpc/clients_crosschain.go index 30d9c9c926..f1ef8f5e34 100644 --- a/pkg/rpc/clients_crosschain.go +++ b/pkg/rpc/clients_crosschain.go @@ -2,15 +2,12 @@ package rpc import ( "context" - "sort" "cosmossdk.io/errors" - "github.com/cosmos/cosmos-sdk/types/query" "google.golang.org/grpc" "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/x/crosschain/types" - "github.com/zeta-chain/node/zetaclient/chains/interfaces" ) // 32MB @@ -157,38 +154,3 @@ func (c *Clients) GetInboundTrackersForChain(ctx context.Context, chainID int64) return resp.InboundTracker, nil } - -// GetAllOutboundTrackerByChain returns all outbound trackers for a chain -func (c *Clients) GetAllOutboundTrackerByChain( - ctx context.Context, - chainID int64, - order interfaces.Order, -) ([]types.OutboundTracker, error) { - in := &types.QueryAllOutboundTrackerByChainRequest{ - Chain: chainID, - Pagination: &query.PageRequest{ - Key: nil, - Offset: 0, - Limit: 2000, - CountTotal: false, - Reverse: false, - }, - } - - resp, err := c.Crosschain.OutboundTrackerAllByChain(ctx, in) - if err != nil { - return nil, errors.Wrap(err, "failed to get all outbound trackers") - } - - if order == interfaces.Ascending { - sort.SliceStable(resp.OutboundTracker, func(i, j int) bool { - return resp.OutboundTracker[i].Nonce < resp.OutboundTracker[j].Nonce - }) - } else if order == interfaces.Descending { - sort.SliceStable(resp.OutboundTracker, func(i, j int) bool { - return resp.OutboundTracker[i].Nonce > resp.OutboundTracker[j].Nonce - }) - } - - return resp.OutboundTracker, nil -} diff --git a/pkg/rpc/clients_test.go b/pkg/rpc/clients_test.go index ca5abf0d92..9e14266770 100644 --- a/pkg/rpc/clients_test.go +++ b/pkg/rpc/clients_test.go @@ -12,7 +12,6 @@ import ( tmtypes "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/stretchr/testify/require" @@ -27,7 +26,6 @@ import ( crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" lightclienttypes "github.com/zeta-chain/node/x/lightclient/types" observertypes "github.com/zeta-chain/node/x/observer/types" - "github.com/zeta-chain/node/zetaclient/chains/interfaces" ) const skipMethod = "skip" @@ -688,44 +686,6 @@ func TestZetacore_GetOutboundTracker(t *testing.T) { require.Equal(t, expectedOutput.OutboundTracker, *resp) } -func TestZetacore_GetAllOutboundTrackerByChain(t *testing.T) { - ctx := context.Background() - - chain := chains.BscMainnet - expectedOutput := crosschaintypes.QueryAllOutboundTrackerByChainResponse{ - OutboundTracker: []crosschaintypes.OutboundTracker{ - { - Index: "tracker23456", - ChainId: chain.ChainId, - Nonce: 123456, - HashList: nil, - }, - }, - } - input := crosschaintypes.QueryAllOutboundTrackerByChainRequest{ - Chain: chain.ChainId, - Pagination: &query.PageRequest{ - Key: nil, - Offset: 0, - Limit: 2000, - CountTotal: false, - Reverse: false, - }, - } - method := "/zetachain.zetacore.crosschain.Query/OutboundTrackerAllByChain" - setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) - - client := setupZetacoreClients(t) - - resp, err := client.GetAllOutboundTrackerByChain(ctx, chain.ChainId, interfaces.Ascending) - require.NoError(t, err) - require.Equal(t, expectedOutput.OutboundTracker, resp) - - resp, err = client.GetAllOutboundTrackerByChain(ctx, chain.ChainId, interfaces.Descending) - require.NoError(t, err) - require.Equal(t, expectedOutput.OutboundTracker, resp) -} - func TestZetacore_GetPendingNoncesByChain(t *testing.T) { ctx := context.Background() diff --git a/pkg/sdkconfig/sdkconfig.go b/pkg/sdkconfig/sdkconfig.go new file mode 100644 index 0000000000..37149496f0 --- /dev/null +++ b/pkg/sdkconfig/sdkconfig.go @@ -0,0 +1,36 @@ +package sdkconfig + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + AccountAddressPrefix = "zeta" +) + +var ( + AccountPubKeyPrefix = AccountAddressPrefix + "pub" + ValidatorAddressPrefix = AccountAddressPrefix + "valoper" + ValidatorPubKeyPrefix = AccountAddressPrefix + "valoperpub" + ConsNodeAddressPrefix = AccountAddressPrefix + "valcons" + ConsNodePubKeyPrefix = AccountAddressPrefix + "valconspub" +) + +func SetDefault(seal bool) { + config := sdk.GetConfig() + config.SetBech32PrefixForAccount(AccountAddressPrefix, AccountPubKeyPrefix) + config.SetBech32PrefixForValidator(ValidatorAddressPrefix, ValidatorPubKeyPrefix) + config.SetBech32PrefixForConsensusNode(ConsNodeAddressPrefix, ConsNodePubKeyPrefix) + if seal { + config.Seal() + } +} + +func Set(config *sdk.Config, seal bool) { + config.SetBech32PrefixForAccount(AccountAddressPrefix, AccountPubKeyPrefix) + config.SetBech32PrefixForValidator(ValidatorAddressPrefix, ValidatorPubKeyPrefix) + config.SetBech32PrefixForConsensusNode(ConsNodeAddressPrefix, ConsNodePubKeyPrefix) + if seal { + config.Seal() + } +} diff --git a/testutil/keeper/config.go b/testutil/keeper/config.go index 58826dd5a7..732f7c0a03 100644 --- a/testutil/keeper/config.go +++ b/testutil/keeper/config.go @@ -30,28 +30,6 @@ import ( observertypes "github.com/zeta-chain/node/x/observer/types" ) -const ( - AccountAddressPrefix = "zeta" -) - -var ( - AccountPubKeyPrefix = AccountAddressPrefix + "pub" - ValidatorAddressPrefix = AccountAddressPrefix + "valoper" - ValidatorPubKeyPrefix = AccountAddressPrefix + "valoperpub" - ConsNodeAddressPrefix = AccountAddressPrefix + "valcons" - ConsNodePubKeyPrefix = AccountAddressPrefix + "valconspub" -) - -func SetConfig(seal bool) { - config := sdk.GetConfig() - config.SetBech32PrefixForAccount(AccountAddressPrefix, AccountPubKeyPrefix) - config.SetBech32PrefixForValidator(ValidatorAddressPrefix, ValidatorPubKeyPrefix) - config.SetBech32PrefixForConsensusNode(ConsNodeAddressPrefix, ConsNodePubKeyPrefix) - if seal { - config.Seal() - } -} - func StoreKeys() ( map[string]*storetypes.KVStoreKey, map[string]*storetypes.MemoryStoreKey, diff --git a/testutil/keeper/emissions.go b/testutil/keeper/emissions.go index 99c385f72d..b2ce7a004c 100644 --- a/testutil/keeper/emissions.go +++ b/testutil/keeper/emissions.go @@ -12,6 +12,7 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/sdkconfig" emissionsmocks "github.com/zeta-chain/node/testutil/keeper/mocks/emissions" "github.com/zeta-chain/node/x/emissions/keeper" "github.com/zeta-chain/node/x/emissions/types" @@ -32,7 +33,7 @@ func EmissionKeeperWithMockOptions( t testing.TB, mockOptions EmissionMockOptions, ) (*keeper.Keeper, sdk.Context, SDKKeepers, ZetaKeepers) { - SetConfig(false) + sdkconfig.SetDefault(false) storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) diff --git a/x/authority/types/genesis_test.go b/x/authority/types/genesis_test.go index 251a3192ba..8266a2e3a8 100644 --- a/x/authority/types/genesis_test.go +++ b/x/authority/types/genesis_test.go @@ -7,12 +7,13 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/authority/types" ) func TestGenesisState_Validate(t *testing.T) { - setConfig(t) + sdkconfig.SetDefault(false) tests := []struct { name string diff --git a/x/authority/types/policies_test.go b/x/authority/types/policies_test.go index faa35993a5..7fa222af69 100644 --- a/x/authority/types/policies_test.go +++ b/x/authority/types/policies_test.go @@ -3,28 +3,15 @@ package types_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/zeta-chain/node/app" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/authority/types" ) -// setConfig sets the global config to use zeta chain's bech32 prefixes -func setConfig(t *testing.T) { - defer func(t *testing.T) { - if r := recover(); r != nil { - 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(t) + sdkconfig.SetDefault(false) // use table driven tests to test the validation of policies tests := []struct { name string diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index 9b17f825d6..8a51b4cf2a 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -6,17 +6,21 @@ import ( "testing" "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/query" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" keepertest "github.com/zeta-chain/node/testutil/keeper" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/keeper" "github.com/zeta-chain/node/x/crosschain/types" + observertypes "github.com/zeta-chain/node/x/observer/types" ) func createNCctxWithStatus( @@ -290,3 +294,163 @@ func TestKeeper_RemoveCrossChainTx(t *testing.T) { txs = keeper.GetAllCrossChainTx(ctx) require.Equal(t, 4, len(txs)) } + +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") + hash := sample.Hash().String() + + err := cctx.AddOutbound(ctx, types.MsgVoteOutbound{ + ValueReceived: cctx.GetCurrentOutboundParam().Amount, + ObservedOutboundHash: hash, + ObservedOutboundBlockHeight: 10, + ObservedOutboundGasUsed: 100, + ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutboundEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutboundParam().Hash, hash) + require.Equal(t, cctx.GetCurrentOutboundParam().GasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutboundParam().ObservedExternalHeight, uint64(10)) + }) + + 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.MsgVoteOutbound{ + ObservedOutboundHash: hash, + ObservedOutboundBlockHeight: 10, + ObservedOutboundGasUsed: 100, + ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutboundEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_FailureObservation) + require.NoError(t, err) + require.Equal(t, cctx.GetCurrentOutboundParam().Hash, hash) + require.Equal(t, cctx.GetCurrentOutboundParam().GasUsed, uint64(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasPrice, sdkmath.NewInt(100)) + require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasLimit, uint64(20)) + require.Equal(t, cctx.GetCurrentOutboundParam().ObservedExternalHeight, uint64(10)) + }) + + 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.MsgVoteOutbound{ + ValueReceived: sdkmath.NewUint(100), + ObservedOutboundHash: hash, + ObservedOutboundBlockHeight: 10, + ObservedOutboundGasUsed: 100, + ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), + ObservedOutboundEffectiveGasLimit: 20, + }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) + }) +} + +func Test_NewCCTX(t *testing.T) { + t.Run("should return a cctx with correct values", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + senderChain := chains.Goerli + sender := sample.EthAddress() + receiverChain := chains.Goerli + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + inboundBlockHeight := uint64(420) + inboundHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := coin.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteInbound{ + Creator: creator, + Sender: sender.String(), + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InboundHash: inboundHash.String(), + InboundBlockHeight: inboundBlockHeight, + CallOptions: &types.CallOptions{ + GasLimit: gasLimit, + }, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + ProtocolContractVersion: types.ProtocolContractVersion_V2, + } + cctx, err := types.NewCCTX(ctx, msg, tss.TssPubkey) + require.NoError(t, err) + require.Equal(t, receiver.String(), cctx.GetCurrentOutboundParam().Receiver) + require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutboundParam().ReceiverChainId) + require.Equal(t, sender.String(), cctx.GetInboundParams().Sender) + require.Equal(t, senderChain.ChainId, cctx.GetInboundParams().SenderChainId) + require.Equal(t, amount, cctx.GetInboundParams().Amount) + require.Equal(t, message, cctx.RelayedMessage) + require.Equal(t, inboundHash.String(), cctx.GetInboundParams().ObservedHash) + require.Equal(t, inboundBlockHeight, cctx.GetInboundParams().ObservedExternalHeight) + require.Equal(t, gasLimit, cctx.GetCurrentOutboundParam().CallOptions.GasLimit) + require.Equal(t, asset, cctx.GetInboundParams().Asset) + require.Equal(t, cointType, cctx.InboundParams.CoinType) + require.Equal(t, uint64(0), cctx.GetCurrentOutboundParam().TssNonce) + require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutboundParam().Amount) + require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) + require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) + require.Equal(t, types.ProtocolContractVersion_V2, cctx.ProtocolContractVersion) + }) + + t.Run("should return an error if the cctx is invalid", func(t *testing.T) { + _, ctx, _, _ := keepertest.CrosschainKeeper(t) + senderChain := chains.Goerli + sender := sample.EthAddress() + receiverChain := chains.Goerli + receiver := sample.EthAddress() + creator := sample.AccAddress() + amount := sdkmath.NewUint(42) + message := "test" + inboundBlockHeight := uint64(420) + inboundHash := sample.Hash() + gasLimit := uint64(100) + asset := "test-asset" + eventIndex := uint64(1) + cointType := coin.CoinType_ERC20 + tss := sample.Tss() + msg := types.MsgVoteInbound{ + Creator: creator, + Sender: "", + SenderChainId: senderChain.ChainId, + Receiver: receiver.String(), + ReceiverChain: receiverChain.ChainId, + Amount: amount, + Message: message, + InboundHash: inboundHash.String(), + InboundBlockHeight: inboundBlockHeight, + CallOptions: &types.CallOptions{ + GasLimit: gasLimit, + }, + CoinType: cointType, + TxOrigin: sender.String(), + Asset: asset, + EventIndex: eventIndex, + } + _, err := types.NewCCTX(ctx, msg, tss.TssPubkey) + require.ErrorContains(t, err, "sender cannot be empty") + }) + + t.Run("zero value for protocol contract version gives V1", func(t *testing.T) { + cctx := types.CrossChainTx{} + require.Equal(t, types.ProtocolContractVersion_V1, cctx.ProtocolContractVersion) + }) +} diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 0f2f84ac7b..00fbe2ac66 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -4,16 +4,10 @@ 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/node/pkg/chains" - "github.com/zeta-chain/node/pkg/coin" - keepertest "github.com/zeta-chain/node/testutil/keeper" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" - observertypes "github.com/zeta-chain/node/x/observer/types" ) func TestCrossChainTx_GetEVMRevertAddress(t *testing.T) { @@ -63,106 +57,6 @@ func TestCrossChainTx_GetCCTXIndexBytes(t *testing.T) { require.Equal(t, cctx.Index, types.GetCctxIndexFromBytes(indexBytes)) } -func Test_NewCCTX(t *testing.T) { - t.Run("should return a cctx with correct values", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - senderChain := chains.Goerli - sender := sample.EthAddress() - receiverChain := chains.Goerli - receiver := sample.EthAddress() - creator := sample.AccAddress() - amount := sdkmath.NewUint(42) - message := "test" - inboundBlockHeight := uint64(420) - inboundHash := sample.Hash() - gasLimit := uint64(100) - asset := "test-asset" - eventIndex := uint64(1) - cointType := coin.CoinType_ERC20 - tss := sample.Tss() - msg := types.MsgVoteInbound{ - Creator: creator, - Sender: sender.String(), - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InboundHash: inboundHash.String(), - InboundBlockHeight: inboundBlockHeight, - CallOptions: &types.CallOptions{ - GasLimit: gasLimit, - }, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, - ProtocolContractVersion: types.ProtocolContractVersion_V2, - } - cctx, err := types.NewCCTX(ctx, msg, tss.TssPubkey) - require.NoError(t, err) - require.Equal(t, receiver.String(), cctx.GetCurrentOutboundParam().Receiver) - require.Equal(t, receiverChain.ChainId, cctx.GetCurrentOutboundParam().ReceiverChainId) - require.Equal(t, sender.String(), cctx.GetInboundParams().Sender) - require.Equal(t, senderChain.ChainId, cctx.GetInboundParams().SenderChainId) - require.Equal(t, amount, cctx.GetInboundParams().Amount) - require.Equal(t, message, cctx.RelayedMessage) - require.Equal(t, inboundHash.String(), cctx.GetInboundParams().ObservedHash) - require.Equal(t, inboundBlockHeight, cctx.GetInboundParams().ObservedExternalHeight) - require.Equal(t, gasLimit, cctx.GetCurrentOutboundParam().CallOptions.GasLimit) - require.Equal(t, asset, cctx.GetInboundParams().Asset) - require.Equal(t, cointType, cctx.InboundParams.CoinType) - require.Equal(t, uint64(0), cctx.GetCurrentOutboundParam().TssNonce) - require.Equal(t, sdkmath.ZeroUint(), cctx.GetCurrentOutboundParam().Amount) - require.Equal(t, types.CctxStatus_PendingInbound, cctx.CctxStatus.Status) - require.Equal(t, false, cctx.CctxStatus.IsAbortRefunded) - require.Equal(t, types.ProtocolContractVersion_V2, cctx.ProtocolContractVersion) - }) - - t.Run("should return an error if the cctx is invalid", func(t *testing.T) { - _, ctx, _, _ := keepertest.CrosschainKeeper(t) - senderChain := chains.Goerli - sender := sample.EthAddress() - receiverChain := chains.Goerli - receiver := sample.EthAddress() - creator := sample.AccAddress() - amount := sdkmath.NewUint(42) - message := "test" - inboundBlockHeight := uint64(420) - inboundHash := sample.Hash() - gasLimit := uint64(100) - asset := "test-asset" - eventIndex := uint64(1) - cointType := coin.CoinType_ERC20 - tss := sample.Tss() - msg := types.MsgVoteInbound{ - Creator: creator, - Sender: "", - SenderChainId: senderChain.ChainId, - Receiver: receiver.String(), - ReceiverChain: receiverChain.ChainId, - Amount: amount, - Message: message, - InboundHash: inboundHash.String(), - InboundBlockHeight: inboundBlockHeight, - CallOptions: &types.CallOptions{ - GasLimit: gasLimit, - }, - CoinType: cointType, - TxOrigin: sender.String(), - Asset: asset, - EventIndex: eventIndex, - } - _, err := types.NewCCTX(ctx, msg, tss.TssPubkey) - require.ErrorContains(t, err, "sender cannot be empty") - }) - - t.Run("zero value for protocol contract version gives V1", func(t *testing.T) { - cctx := types.CrossChainTx{} - require.Equal(t, types.ProtocolContractVersion_V1, cctx.ProtocolContractVersion) - }) -} - func TestCrossChainTx_Validate(t *testing.T) { cctx := sample.CrossChainTx(t, "foo") cctx.InboundParams = nil @@ -225,66 +119,6 @@ func TestCrossChainTx_OriginalDestinationChainID(t *testing.T) { require.Equal(t, cctx.OutboundParams[0].ReceiverChainId, cctx.OriginalDestinationChainID()) } -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") - hash := sample.Hash().String() - - err := cctx.AddOutbound(ctx, types.MsgVoteOutbound{ - ValueReceived: cctx.GetCurrentOutboundParam().Amount, - ObservedOutboundHash: hash, - ObservedOutboundBlockHeight: 10, - ObservedOutboundGasUsed: 100, - ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutboundEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutboundParam().Hash, hash) - require.Equal(t, cctx.GetCurrentOutboundParam().GasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasPrice, sdkmath.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutboundParam().ObservedExternalHeight, uint64(10)) - }) - - 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.MsgVoteOutbound{ - ObservedOutboundHash: hash, - ObservedOutboundBlockHeight: 10, - ObservedOutboundGasUsed: 100, - ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutboundEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_FailureObservation) - require.NoError(t, err) - require.Equal(t, cctx.GetCurrentOutboundParam().Hash, hash) - require.Equal(t, cctx.GetCurrentOutboundParam().GasUsed, uint64(100)) - require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasPrice, sdkmath.NewInt(100)) - require.Equal(t, cctx.GetCurrentOutboundParam().EffectiveGasLimit, uint64(20)) - require.Equal(t, cctx.GetCurrentOutboundParam().ObservedExternalHeight, uint64(10)) - }) - - 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.MsgVoteOutbound{ - ValueReceived: sdkmath.NewUint(100), - ObservedOutboundHash: hash, - ObservedOutboundBlockHeight: 10, - ObservedOutboundGasUsed: 100, - ObservedOutboundEffectiveGasPrice: sdkmath.NewInt(100), - ObservedOutboundEffectiveGasLimit: 20, - }, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - require.ErrorIs(t, err, sdkerrors.ErrInvalidRequest) - }) -} - func Test_SetRevertOutboundValues(t *testing.T) { t.Run("successfully set revert outbound values", func(t *testing.T) { cctx := sample.CrossChainTx(t, "test") diff --git a/x/crosschain/types/message_migrate_erc20_custody_funds_test.go b/x/crosschain/types/message_migrate_erc20_custody_funds_test.go index 4a6027e8e2..823b2a54a1 100644 --- a/x/crosschain/types/message_migrate_erc20_custody_funds_test.go +++ b/x/crosschain/types/message_migrate_erc20_custody_funds_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) func TestNewMsgMigrateERC20CustodyFunds_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgMigrateERC20CustodyFunds diff --git a/x/crosschain/types/message_migrate_tss_funds_test.go b/x/crosschain/types/message_migrate_tss_funds_test.go index 48362f207a..5e1ead5913 100644 --- a/x/crosschain/types/message_migrate_tss_funds_test.go +++ b/x/crosschain/types/message_migrate_tss_funds_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) func TestNewMsgMigrateTssFunds_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgMigrateTssFunds diff --git a/x/crosschain/types/message_update_erc20_custody_pause_status_test.go b/x/crosschain/types/message_update_erc20_custody_pause_status_test.go index cddb141db5..bbd93dbe55 100644 --- a/x/crosschain/types/message_update_erc20_custody_pause_status_test.go +++ b/x/crosschain/types/message_update_erc20_custody_pause_status_test.go @@ -7,13 +7,13 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) func TestNewMsgUpdateERC20CustodyPauseStatus_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgUpdateERC20CustodyPauseStatus diff --git a/x/crosschain/types/message_update_tss_address_test.go b/x/crosschain/types/message_update_tss_address_test.go index 4118611307..d7fca0116c 100644 --- a/x/crosschain/types/message_update_tss_address_test.go +++ b/x/crosschain/types/message_update_tss_address_test.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) func TestMessageUpdateTssAddress_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgUpdateTssAddress diff --git a/x/crosschain/types/message_whitelist_erc20_test.go b/x/crosschain/types/message_whitelist_erc20_test.go index 1cf5d6350c..8219140fd9 100644 --- a/x/crosschain/types/message_whitelist_erc20_test.go +++ b/x/crosschain/types/message_whitelist_erc20_test.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/crosschain/types" ) func TestMsgWhitelistERC20_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgWhitelistERC20 diff --git a/x/emissions/abci_test.go b/x/emissions/abci_test.go index 2ef62ed7b5..26420231fd 100644 --- a/x/emissions/abci_test.go +++ b/x/emissions/abci_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/zeta-chain/node/cmd/zetacored/config" + "github.com/zeta-chain/node/pkg/sdkconfig" keepertest "github.com/zeta-chain/node/testutil/keeper" "github.com/zeta-chain/node/testutil/sample" emissionsModule "github.com/zeta-chain/node/x/emissions" @@ -311,7 +312,7 @@ func TestBeginBlocker(t *testing.T) { } func TestDistributeObserverRewards(t *testing.T) { - keepertest.SetConfig(false) + sdkconfig.SetDefault(false) k, ctx, _, _ := keepertest.EmissionsKeeper(t) observerSet := sample.ObserverSet(4) diff --git a/x/observer/types/message_vote_blame_test.go b/x/observer/types/message_vote_blame_test.go index f7cd5c7eb4..425f7c0888 100644 --- a/x/observer/types/message_vote_blame_test.go +++ b/x/observer/types/message_vote_blame_test.go @@ -7,13 +7,13 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/observer/types" ) func TestNewMsgVoteBlameMsg_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) tests := []struct { name string msg *types.MsgVoteBlame diff --git a/x/observer/types/message_vote_block_header_test.go b/x/observer/types/message_vote_block_header_test.go index 88d27b039d..9d5d0d7974 100644 --- a/x/observer/types/message_vote_block_header_test.go +++ b/x/observer/types/message_vote_block_header_test.go @@ -12,13 +12,13 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/proofs" - "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/pkg/sdkconfig" "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/observer/types" ) func TestMsgVoteBlockHeader_ValidateBasic(t *testing.T) { - keeper.SetConfig(false) + sdkconfig.SetDefault(false) var header ethtypes.Header file, err := os.Open("../../../testutil/testdata/eth_header_18495266.json") require.NoError(t, err) diff --git a/zetaclient/zetacore/client_crosschain.go b/zetaclient/zetacore/client_crosschain.go new file mode 100644 index 0000000000..bd40665340 --- /dev/null +++ b/zetaclient/zetacore/client_crosschain.go @@ -0,0 +1,47 @@ +package zetacore + +import ( + "context" + "sort" + + "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/zeta-chain/node/x/crosschain/types" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" +) + +// GetAllOutboundTrackerByChain returns all outbound trackers for a chain +func (c *Client) GetAllOutboundTrackerByChain( + ctx context.Context, + chainID int64, + order interfaces.Order, +) ([]types.OutboundTracker, error) { + in := &types.QueryAllOutboundTrackerByChainRequest{ + Chain: chainID, + Pagination: &query.PageRequest{ + Key: nil, + Offset: 0, + Limit: 2000, + CountTotal: false, + Reverse: false, + }, + } + + resp, err := c.Crosschain.OutboundTrackerAllByChain(ctx, in) + if err != nil { + return nil, errors.Wrap(err, "failed to get all outbound trackers") + } + + if order == interfaces.Ascending { + sort.SliceStable(resp.OutboundTracker, func(i, j int) bool { + return resp.OutboundTracker[i].Nonce < resp.OutboundTracker[j].Nonce + }) + } else if order == interfaces.Descending { + sort.SliceStable(resp.OutboundTracker, func(i, j int) bool { + return resp.OutboundTracker[i].Nonce > resp.OutboundTracker[j].Nonce + }) + } + + return resp.OutboundTracker, nil +} diff --git a/zetaclient/zetacore/client_test.go b/zetaclient/zetacore/client_test.go index 060d96515d..c989ef7916 100644 --- a/zetaclient/zetacore/client_test.go +++ b/zetaclient/zetacore/client_test.go @@ -9,12 +9,15 @@ import ( cosmosclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/testutil/mock" "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/golang/mock/gomock" "github.com/rs/zerolog" "github.com/stretchr/testify/require" feemarkettypes "github.com/zeta-chain/ethermint/x/feemarket/types" + "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" keyinterfaces "github.com/zeta-chain/node/zetaclient/keys/interfaces" "go.nhat.io/grpcmock" "go.nhat.io/grpcmock/planner" @@ -189,3 +192,41 @@ func TestZetacore_GetZetaHotKeyBalance(t *testing.T) { require.Error(t, err) require.Equal(t, types.ZeroInt(), resp) } + +func TestZetacore_GetAllOutboundTrackerByChain(t *testing.T) { + ctx := context.Background() + + chain := chains.BscMainnet + expectedOutput := crosschaintypes.QueryAllOutboundTrackerByChainResponse{ + OutboundTracker: []crosschaintypes.OutboundTracker{ + { + Index: "tracker23456", + ChainId: chain.ChainId, + Nonce: 123456, + HashList: nil, + }, + }, + } + input := crosschaintypes.QueryAllOutboundTrackerByChainRequest{ + Chain: chain.ChainId, + Pagination: &query.PageRequest{ + Key: nil, + Offset: 0, + Limit: 2000, + CountTotal: false, + Reverse: false, + }, + } + method := "/zetachain.zetacore.crosschain.Query/OutboundTrackerAllByChain" + setupMockServer(t, crosschaintypes.RegisterQueryServer, method, input, expectedOutput) + + client := setupZetacoreClient(t, withDefaultObserverKeys()) + + resp, err := client.GetAllOutboundTrackerByChain(ctx, chain.ChainId, interfaces.Ascending) + require.NoError(t, err) + require.Equal(t, expectedOutput.OutboundTracker, resp) + + resp, err = client.GetAllOutboundTrackerByChain(ctx, chain.ChainId, interfaces.Descending) + require.NoError(t, err) + require.Equal(t, expectedOutput.OutboundTracker, resp) +}