Skip to content

Commit

Permalink
refactor: Reuse v6 starknet_getTransactionByHash handler for v7 (#2486)
Browse files Browse the repository at this point in the history
  • Loading branch information
hudem1 authored Mar 6, 2025
1 parent 80c2b5c commit a7dbcb8
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 391 deletions.
2 changes: 1 addition & 1 deletion rpc/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen
{
Name: "starknet_getTransactionByHash",
Params: []jsonrpc.Parameter{{Name: "transaction_hash"}},
Handler: h.rpcv7Handler.TransactionByHash,
Handler: h.rpcv6Handler.TransactionByHash,
},
{
Name: "starknet_getTransactionReceipt",
Expand Down
27 changes: 24 additions & 3 deletions rpc/v6/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/NethermindEth/juno/clients/gateway"
"github.com/NethermindEth/juno/core"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/db"
"github.com/NethermindEth/juno/jsonrpc"
rpccore "github.com/NethermindEth/juno/rpc/rpccore"
"github.com/NethermindEth/juno/starknet"
Expand Down Expand Up @@ -434,8 +435,28 @@ func adaptRPCTxToFeederTx(rpcTx *Transaction) *starknet.Transaction {
func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Error) {
txn, err := h.bcReader.TransactionByHash(&hash)
if err != nil {
return nil, rpccore.ErrTxnHashNotFound
if !errors.Is(err, db.ErrKeyNotFound) {
return nil, rpccore.ErrInternal.CloneWithData(err)
}

// check now if tx is in pending block
pendingB := h.syncReader.PendingBlock()
if pendingB == nil {
return nil, rpccore.ErrTxnHashNotFound
}

for _, t := range pendingB.Transactions {
if hash.Equal(t.Hash()) {
txn = t
break
}
}

if txn == nil {
return nil, rpccore.ErrTxnHashNotFound
}
}

return AdaptTransaction(txn), nil
}

Expand Down Expand Up @@ -672,7 +693,7 @@ func AdaptTransaction(t core.Transaction) *Transaction {
case *core.DeclareTransaction:
txn = adaptDeclareTransaction(v)
case *core.DeployAccountTransaction:
txn = adaptDeployAccountTrandaction(v)
txn = adaptDeployAccountTransaction(v)
case *core.L1HandlerTransaction:
nonce := v.Nonce
if nonce == nil {
Expand Down Expand Up @@ -816,7 +837,7 @@ func adaptDeclareTransaction(t *core.DeclareTransaction) *Transaction {
return tx
}

func adaptDeployAccountTrandaction(t *core.DeployAccountTransaction) *Transaction {
func adaptDeployAccountTransaction(t *core.DeployAccountTransaction) *Transaction {
tx := &Transaction{
Hash: t.Hash(),
MaxFee: t.MaxFee,
Expand Down
114 changes: 104 additions & 10 deletions rpc/v6/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,113 @@ import (
)

func TestTransactionByHashNotFound(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockReader := mocks.NewMockReader(mockCtrl)
t.Run("internal error", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockReader := mocks.NewMockReader(mockCtrl)
mockSyncReader := mocks.NewMockSyncReader(mockCtrl)

n := utils.HeapPtr(utils.Mainnet)
txHash := new(felt.Felt).SetBytes([]byte("random hash"))
mockReader.EXPECT().TransactionByHash(txHash).Return(nil, errors.New("tx not found"))
randomTxHash := new(felt.Felt).SetBytes([]byte("random hash"))
mockReader.EXPECT().TransactionByHash(randomTxHash).Return(nil, errors.New("some internal error"))

handler := rpc.New(mockReader, nil, nil, "", n, nil)
n := &utils.Mainnet
handler := rpc.New(mockReader, mockSyncReader, nil, "", n, nil)
tx, rpcErr := handler.TransactionByHash(*randomTxHash)

assert.Nil(t, tx)
assert.Equal(t, rpcErr, rpccore.ErrInternal.CloneWithData(errors.New("some internal error")))
})

t.Run("tx not found and no pending block", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockReader := mocks.NewMockReader(mockCtrl)
mockSyncReader := mocks.NewMockSyncReader(mockCtrl)

randomTxHash := new(felt.Felt).SetBytes([]byte("random hash"))
mockReader.EXPECT().TransactionByHash(randomTxHash).Return(nil, db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingBlock().Return(nil)

n := &utils.Mainnet
handler := rpc.New(mockReader, mockSyncReader, nil, "", n, nil)
tx, rpcErr := handler.TransactionByHash(*randomTxHash)

assert.Nil(t, tx)
assert.Equal(t, rpccore.ErrTxnHashNotFound, rpcErr)
})

t.Run("tx found in pending block", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockReader := mocks.NewMockReader(mockCtrl)
mockSyncReader := mocks.NewMockSyncReader(mockCtrl)

n := &utils.Mainnet
client := feeder.NewTestClient(t, n)
mainnetGw := adaptfeeder.New(client)

block, err := mainnetGw.BlockByNumber(context.Background(), 19199)
require.NoError(t, err)

tx, rpcErr := handler.TransactionByHash(*txHash)
assert.Nil(t, tx)
assert.Equal(t, rpccore.ErrTxnHashNotFound, rpcErr)
txAtIdx1InBlock := utils.HexToFelt(t, "0x5f3d9e538af40474c894820d2c0d0e8f92ee8fef92e2254f0b06e306f88dcc8")
mockReader.EXPECT().TransactionByHash(txAtIdx1InBlock).Return(nil, db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingBlock().Return(block)

handler := rpc.New(mockReader, mockSyncReader, nil, "", n, nil)
tx, rpcErr := handler.TransactionByHash(*txAtIdx1InBlock)

expectedTx := rpc.Transaction{
Type: rpc.TxnInvoke,
Hash: txAtIdx1InBlock,
MaxFee: utils.HexToFelt(t, "0x65d5eabc5218"),
Version: utils.HexToFelt(t, "0x0"),
Signature: &[]*felt.Felt{
utils.HexToFelt(t, "0x2ccb8d2b482d67d8358482832705549d1e5278dc4d04878d9f8256a47423d6a"),
utils.HexToFelt(t, "0x6958e023ab0ffa07a84bd4e79032a5f2312ca4a2937585e49534877d13ea918"),
},
Nonce: nil,
CallData: &[]*felt.Felt{
utils.HexToFelt(t, "0x1"),
utils.HexToFelt(t, "0x4a4479e16bf55ebbe7ccb36f438060d994fac69c75e2edfaf00ae56d45d5796"),
utils.HexToFelt(t, "0x1474f761b9a93b1c727b60fb4cc7aa6c6c1c866ad7f1cd88ec9545ff065ddad"),
utils.HexToFelt(t, "0x0"),
utils.HexToFelt(t, "0x1"),
utils.HexToFelt(t, "0x1"),
utils.HexToFelt(t, "0x6b648b36b074a91eee55730f5f5e075ec19c0a8f9ffb0903cefeee93b6ff328"),
utils.HexToFelt(t, "0x7d1"),
},
ContractAddress: utils.HexToFelt(t, "0x4a4479e16bf55ebbe7ccb36f438060d994fac69c75e2edfaf00ae56d45d5796"),
SenderAddress: nil,
EntryPointSelector: utils.HexToFelt(t, "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad"),
}

assert.Nil(t, rpcErr)
assert.Equal(t, &expectedTx, tx)
})

t.Run("tx not found anywhere", func(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockReader := mocks.NewMockReader(mockCtrl)
mockSyncReader := mocks.NewMockSyncReader(mockCtrl)

n := &utils.Mainnet
client := feeder.NewTestClient(t, n)
mainnetGw := adaptfeeder.New(client)

block, err := mainnetGw.BlockByNumber(context.Background(), 19199)
require.NoError(t, err)

randomTxHash := new(felt.Felt).SetBytes([]byte("random hash"))
mockReader.EXPECT().TransactionByHash(randomTxHash).Return(nil, db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingBlock().Return(block)

handler := rpc.New(mockReader, mockSyncReader, nil, "", n, nil)
tx, rpcErr := handler.TransactionByHash(*randomTxHash)

assert.Nil(t, tx)
assert.Equal(t, rpccore.ErrTxnHashNotFound, rpcErr)
})
}

func TestTransactionByHash(t *testing.T) {
Expand Down
11 changes: 8 additions & 3 deletions rpc/v7/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ func TestBlockWithTxs(t *testing.T) {
n := &utils.Mainnet
handler := rpcv7.New(mockReader, mockSyncReader, nil, "", n, nil)

// Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler
mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl)
mockReaderV6 := mocks.NewMockReader(mockCtrl)
rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil)

client := feeder.NewTestClient(t, n)
gw := adaptfeeder.New(client)

Expand All @@ -267,10 +272,10 @@ func TestBlockWithTxs(t *testing.T) {
assert.Equal(t, len(blockWithTxHashes.TxnHashes), len(blockWithTxs.Transactions))

for i, txnHash := range blockWithTxHashes.TxnHashes {
txn, err := handler.TransactionByHash(*txnHash)
txn, err := rpcv6Handler.TransactionByHash(*txnHash)
require.Nil(t, err)

assert.Equal(t, txn, blockWithTxs.Transactions[i])
assert.Equal(t, adaptV6TxToV7(t, txn), blockWithTxs.Transactions[i])
}
}

Expand All @@ -279,7 +284,7 @@ func TestBlockWithTxs(t *testing.T) {
latestBlockTxMap[*tx.Hash()] = tx
}

mockReader.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) {
mockReaderV6.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) {
if tx, found := latestBlockTxMap[*hash]; found {
return tx, nil
}
Expand Down
30 changes: 0 additions & 30 deletions rpc/v7/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,36 +380,6 @@ func adaptResourceBounds(rb map[core.Resource]core.ResourceBounds) map[Resource]
Transaction Handlers
*****************************************************/

// TransactionByHash returns the details of a transaction identified by the given hash.
//
// It follows the specification defined here:
// https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L158
func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Error) {
txn, err := h.bcReader.TransactionByHash(&hash)
if err != nil {
if !errors.Is(err, db.ErrKeyNotFound) {
return nil, rpccore.ErrInternal.CloneWithData(err)
}

pendingB := h.syncReader.PendingBlock()
if pendingB == nil {
return nil, rpccore.ErrTxnHashNotFound
}

for _, t := range pendingB.Transactions {
if hash.Equal(t.Hash()) {
txn = t
break
}
}

if txn == nil {
return nil, rpccore.ErrTxnHashNotFound
}
}
return AdaptTransaction(txn), nil
}

// TransactionByBlockIDAndIndex returns the details of a transaction identified by the given
// BlockID and index.
//
Expand Down
Loading

0 comments on commit a7dbcb8

Please sign in to comment.