From 3c1e532c845e75a3c2e1d73293b8ac2364aa27c2 Mon Sep 17 00:00:00 2001 From: wojo Date: Tue, 14 Jan 2025 17:25:05 +0700 Subject: [PATCH] Prevent panic in TransactionByHash for non-existent transactions When searching for a transaction in the pending block, the code would continue to AdaptTransaction even if no matching transaction was found. This could lead to a panic when trying to adapt a nil transaction. Added a nil check and an early break from the loop to ensure we properly handle non-existent transactions with ErrTxnHashNotFound. Changes: - Add break statement to exit loop once matching transaction is found - Add explicit nil check for txn before attempting to adapt it - Return ErrTxnHashNotFound if no matching transaction is found --- rpc/transaction.go | 5 +++++ rpc/transaction_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/rpc/transaction.go b/rpc/transaction.go index 017b388944..01050bf2db 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -440,8 +440,13 @@ func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Erro for _, t := range pendingB.Transactions { if hash.Equal(t.Hash()) { txn = t + break } } + + if txn == nil { + return nil, ErrTxnHashNotFound + } } return AdaptTransaction(txn), nil } diff --git a/rpc/transaction_test.go b/rpc/transaction_test.go index 68a847d7e0..c1adb39894 100644 --- a/rpc/transaction_test.go +++ b/rpc/transaction_test.go @@ -39,6 +39,32 @@ func TestTransactionByHashNotFound(t *testing.T) { assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) } +func TestTransactionByHashNotFoundInPendingBlock(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + + searchTxHash := utils.HexToFelt(t, "0x123456") + + otherTxHash := utils.HexToFelt(t, "0x789abc") + pendingTx := &core.InvokeTransaction{ + TransactionHash: otherTxHash, + Version: new(core.TransactionVersion).SetUint64(1), + } + + mockReader.EXPECT().TransactionByHash(searchTxHash).Return(nil, db.ErrKeyNotFound) + mockSyncReader.EXPECT().PendingBlock().Return(&core.Block{ + Transactions: []core.Transaction{pendingTx}, + }) + + handler := rpc.New(mockReader, mockSyncReader, nil, "", nil) + + tx, rpcErr := handler.TransactionByHash(*searchTxHash) + assert.Nil(t, tx) + assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) +} + func TestTransactionByHash(t *testing.T) { tests := map[string]struct { hash string