diff --git a/pkg/ticker/ticker.go b/pkg/ticker/ticker.go index 566fc03f8b..94fc9ab2fb 100644 --- a/pkg/ticker/ticker.go +++ b/pkg/ticker/ticker.go @@ -29,6 +29,8 @@ package ticker import ( "context" "fmt" + "runtime/debug" + "strings" "sync" "time" @@ -78,7 +80,14 @@ func SecondsFromUint64(d uint64) time.Duration { func (t *Ticker) Run(ctx context.Context) (err error) { defer func() { if r := recover(); r != nil { - err = fmt.Errorf("panic during ticker run: %v", r) + stack := string(debug.Stack()) + lines := strings.Split(stack, "\n") + line := "" + // 8th line should be the actual line, see the unit tests + if len(lines) > 8 { + line = strings.TrimSpace(lines[8]) + } + err = fmt.Errorf("panic during ticker run: %v at %s", r, line) } }() diff --git a/pkg/ticker/ticker_test.go b/pkg/ticker/ticker_test.go index 671091c71f..4d890bf051 100644 --- a/pkg/ticker/ticker_test.go +++ b/pkg/ticker/ticker_test.go @@ -147,6 +147,33 @@ func TestTicker(t *testing.T) { // ASSERT assert.ErrorContains(t, err, "panic during ticker run: oops") + // assert that we get error with the correct line number + assert.ErrorContains(t, err, "ticker_test.go:142") + }) + + t.Run("Nil panic", func(t *testing.T) { + // ARRANGE + // Given a context + ctx := context.Background() + + // And a ticker + ticker := New(durSmall, func(_ context.Context, _ *Ticker) error { + var a func() + a() + return nil + }) + + // ACT + err := ticker.Run(ctx) + + // ASSERT + assert.ErrorContains( + t, + err, + "panic during ticker run: runtime error: invalid memory address or nil pointer dereference", + ) + // assert that we get error with the correct line number + assert.ErrorContains(t, err, "ticker_test.go:162") }) t.Run("Run as a single call", func(t *testing.T) { diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 15c4420246..a361c943fb 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -20,6 +20,8 @@ const ( // MaxLookbackNonce is the maximum number of nonces to look back to find missed pending cctxs MaxLookbackNonce = 1000 + + DefaultPageSize = 100 ) func (k Keeper) ZetaAccounting( @@ -46,6 +48,13 @@ func (k Keeper) CctxAll(c context.Context, req *types.QueryAllCctxRequest) (*typ store := ctx.KVStore(k.storeKey) sendStore := prefix.NewStore(store, types.KeyPrefix(types.CCTXKey)) + if req.Pagination == nil { + req.Pagination = &query.PageRequest{} + } + if req.Pagination.Limit == 0 { + req.Pagination.Limit = DefaultPageSize + } + pageRes, err := query.Paginate(sendStore, req.Pagination, func(_ []byte, value []byte) error { var send types.CrossChainTx if err := k.cdc.Unmarshal(value, &send); err != nil { diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 6112d5e58c..42f87ef7e4 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -5,6 +5,7 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" "github.com/stretchr/testify/require" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -288,3 +289,40 @@ func TestKeeper_CctxByNonce(t *testing.T) { require.Equal(t, res.CrossChainTx.CctxStatus.LastUpdateTimestamp, ctx.BlockTime().Unix()) }) } + +func TestKeeper_CctxAll(t *testing.T) { + t.Run("empty request", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxAll(ctx, &types.QueryAllCctxRequest{}) + require.NoError(t, err) + }) + + t.Run("default page size", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + chainID := getValidEthChainID() + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + _ = createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) + + res, err := k.CctxAll(ctx, &types.QueryAllCctxRequest{}) + require.NoError(t, err) + require.Len(t, res.CrossChainTx, keeper.DefaultPageSize) + }) + + t.Run("page size provided", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + chainID := getValidEthChainID() + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + _ = createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) + testPageSize := 200 + + res, err := k.CctxAll(ctx, &types.QueryAllCctxRequest{ + Pagination: &query.PageRequest{ + Limit: uint64(testPageSize), + }, + }) + require.NoError(t, err) + require.Len(t, res.CrossChainTx, testPageSize) + }) +} diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 82fc1e4d6d..06ca06c843 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -357,6 +357,9 @@ func (ob *Observer) BlockByNumber(blockNumber int) (*ethrpc.Block, error) { if err != nil { return nil, err } + if block == nil { + return nil, fmt.Errorf("block not found: %d", blockNumber) + } for i := range block.Transactions { err := evm.ValidateEvmTransaction(&block.Transactions[i]) if err != nil {