Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ type Reader interface {

TransactionByHash(hash *felt.Felt) (transaction core.Transaction, err error)
TransactionByBlockNumberAndIndex(blockNumber, index uint64) (transaction core.Transaction, err error)
BlockNumberAndIndexByTxHash(
hash *felt.TransactionHash) (blockNumber uint64, index uint64, err error)

Receipt(hash *felt.Felt) (receipt *core.TransactionReceipt, blockHash *felt.Felt, blockNumber uint64, err error)
ReceiptByBlockNumberAndIndex(
blockNumber, index uint64) (receipt *core.TransactionReceipt, blockHash *felt.Felt, err error)

StateUpdateByNumber(number uint64) (update *core.StateUpdate, err error)
StateUpdateByHash(hash *felt.Felt) (update *core.StateUpdate, err error)
L1HandlerTxnHash(msgHash *common.Hash) (l1HandlerTxnHash felt.Felt, err error)
Expand Down Expand Up @@ -199,6 +205,15 @@ func (b *Blockchain) TransactionByHash(hash *felt.Felt) (core.Transaction, error
return core.GetTxByHash(b.database, (*felt.TransactionHash)(hash))
}

// BlockNumberAndIndexByTxHash gets transaction block number and index by Tx hash
func (b *Blockchain) BlockNumberAndIndexByTxHash(
hash *felt.TransactionHash,
) (uint64, uint64, error) {
b.listener.OnRead("BlockNumberAndIndexByTxHash")
data, err := core.TransactionBlockNumbersAndIndicesByHashBucket.Get(b.database, hash)
return data.Number, data.Index, err
}

// Receipt gets the transaction receipt for a given transaction hash.
// TODO: Return TransactionReceipt instead of *TransactionReceipt.
func (b *Blockchain) Receipt(hash *felt.Felt) (*core.TransactionReceipt, *felt.Felt, uint64, error) {
Expand All @@ -222,6 +237,24 @@ func (b *Blockchain) Receipt(hash *felt.Felt) (*core.TransactionReceipt, *felt.F
return receipt, header.Hash, header.Number, nil
}

func (b *Blockchain) ReceiptByBlockNumberAndIndex(
blockNumber, index uint64,
) (*core.TransactionReceipt, *felt.Felt, error) {
b.listener.OnRead("Receipt")

receipt, err := core.GetReceiptByBlockNumIndex(b.database, blockNumber, index)
if err != nil {
return nil, nil, err
}

header, err := core.GetBlockHeaderByNumber(b.database, blockNumber)
if err != nil {
return nil, nil, err
}

return receipt, header.Hash, nil
}

func (b *Blockchain) SubscribeL1Head() L1HeadSubscription {
return L1HeadSubscription{b.l1HeadFeed.Subscribe()}
}
Expand Down
13 changes: 13 additions & 0 deletions core/accessors.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ func GetReceiptByHash(
return &receipt, nil
}

func GetReceiptByBlockNumIndex(
r db.KeyValueReader, num, index uint64,
) (*TransactionReceipt, error) {
var numIdxKey db.BlockNumIndexKey
numIdxKey.Number = num
numIdxKey.Index = index
receipt, err := ReceiptsByBlockNumberAndIndexBucket.Get(r, numIdxKey)
if err != nil {
return nil, err
}
return &receipt, nil
}

func DeleteTxsAndReceipts(batch db.IndexedBatch, blockNum, numTxs uint64) error {
// remove txs and receipts
for i := range numTxs {
Expand Down
44 changes: 44 additions & 0 deletions mocks/mock_blockchain.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 31 additions & 9 deletions rpc/v10/subscriptions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1021,7 +1021,9 @@ func TestSubscribeTxnStatus(t *testing.T) {
cache := rpccore.NewTransactionCache(cacheEntryTimeOut, cacheSize)
handler := New(mockChain, mockSyncer, nil, log).WithSubmittedTransactionsCache(cache)

mockChain.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound).AnyTimes()
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound).AnyTimes()
mockSyncer.EXPECT().PendingData().Return(nil, core.ErrPendingDataNotFound).AnyTimes()
mockChain.EXPECT().HeadsHeader().Return(nil, db.ErrKeyNotFound).AnyTimes()
mockSyncer.EXPECT().PendingBlock().Return(nil).AnyTimes()
Expand Down Expand Up @@ -1049,7 +1051,9 @@ func TestSubscribeTxnStatus(t *testing.T) {
txHash, err := felt.NewFromString[felt.Felt]("0x1011")
require.NoError(t, err)

mockChain.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)

id, conn := createTestTxStatusWebsocket(t, handler, txHash)
assertNextTxnStatus(
Expand All @@ -1066,7 +1070,9 @@ func TestSubscribeTxnStatus(t *testing.T) {
txHash, err := felt.NewFromString[felt.Felt]("0x1010")
require.NoError(t, err)

mockChain.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
id, conn := createTestTxStatusWebsocket(t, handler, txHash)
assertNextTxnStatus(
t,
Expand Down Expand Up @@ -1127,7 +1133,9 @@ func TestSubscribeTxnStatus(t *testing.T) {
)
require.Nil(t, addErr)
txHash := addRes.TransactionHash
mockChain.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncer.EXPECT().PendingData().Return(nil, core.ErrPendingDataNotFound).Times(2)
mockChain.EXPECT().HeadsHeader().Return(nil, db.ErrKeyNotFound).Times(2)

Expand All @@ -1143,7 +1151,9 @@ func TestSubscribeTxnStatus(t *testing.T) {
"",
)
// Candidate Status
mockChain.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
preConfirmed := &core.PreConfirmed{
Block: &core.Block{
Header: &core.Header{
Expand Down Expand Up @@ -1218,8 +1228,14 @@ func TestSubscribeTxnStatus(t *testing.T) {
nil,
).Times(1)
// Accepted on l2 Status
mockChain.EXPECT().TransactionByHash(txHash).Return(block.Transactions[0], nil)
mockChain.EXPECT().Receipt(txHash).Return(block.Receipts[0], block.Hash, block.Number, nil)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(block.Number, uint64(0), nil)
mockChain.EXPECT().TransactionByBlockNumberAndIndex(
block.Number, uint64(0)).Return(block.Transactions[0], nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: break line

mockChain.EXPECT().ReceiptByBlockNumberAndIndex(block.Number, uint64(0)).Return(
block.Receipts[0], block.Hash, nil,
)
mockChain.EXPECT().L1Head().Return(core.L1Head{}, db.ErrKeyNotFound)

handler.newHeads.Send(block)
Expand All @@ -1238,8 +1254,14 @@ func TestSubscribeTxnStatus(t *testing.T) {
nil,
).Times(1)
l1Head := core.L1Head{BlockNumber: block.Number}
mockChain.EXPECT().TransactionByHash(txHash).Return(block.Transactions[0], nil)
mockChain.EXPECT().Receipt(txHash).Return(block.Receipts[0], block.Hash, block.Number, nil)
mockChain.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(block.Number, uint64(0), nil)
mockChain.EXPECT().TransactionByBlockNumberAndIndex(
block.Number, uint64(0),
).Return(block.Transactions[0], nil)
mockChain.EXPECT().ReceiptByBlockNumberAndIndex(
block.Number, uint64(0)).Return(block.Receipts[0], block.Hash, nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: break line

mockChain.EXPECT().L1Head().Return(l1Head, nil)
handler.l1Heads.Send(&l1Head)
assertNextTxnStatus(
Expand Down
54 changes: 33 additions & 21 deletions rpc/v10/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,15 @@ func TestTransactionReceiptByHash(t *testing.T) {
_, _, _, err := pendingData.ReceiptByHash(transaction.Hash())
if err != nil {
// receipt belong to canonical block mock expectations
mockReader.EXPECT().TransactionByHash(expected.Hash).Return(transaction, nil)
mockReader.EXPECT().Receipt(expected.Hash).Return(
loadedBlock.Receipts[transactionIndex],
expected.BlockHash,
*expected.BlockNumber,
nil,
)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(expected.Hash),
).Return(*expected.BlockNumber, uint64(transactionIndex), nil)
mockReader.EXPECT().TransactionByBlockNumberAndIndex(
*expected.BlockNumber, uint64(transactionIndex),
).Return(transaction, nil)
mockReader.EXPECT().ReceiptByBlockNumberAndIndex(
*expected.BlockNumber, uint64(transactionIndex),
).Return(loadedBlock.Receipts[transactionIndex], expected.BlockHash, nil)
mockReader.EXPECT().L1Head().Return(test.l1Head, nil)
}

Expand All @@ -235,7 +237,9 @@ func TestTransactionReceiptByHash_NotFound(t *testing.T) {
handler := rpcv10.New(mockReader, mockSyncReader, nil, nil)

txHash := felt.NewFromBytes[felt.Felt]([]byte("random hash"))
mockReader.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(txHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingData().Return(nil, core.ErrPendingDataNotFound)
mockReader.EXPECT().HeadsHeader().Return(nil, db.ErrKeyNotFound)

Expand Down Expand Up @@ -274,21 +278,25 @@ func TestTransactionStatus(t *testing.T) {
mockReader *mocks.MockReader,
mockSyncReader *mocks.MockSyncReader,
) {
mockReader.EXPECT().TransactionByHash(tx.Hash()).Return(tx, nil)
mockReader.EXPECT().Receipt(tx.Hash()).Return(
block.Receipts[0],
block.Hash,
block.Number,
nil,
)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(tx.Hash()),
).Return(block.Number, uint64(0), nil)
mockReader.EXPECT().TransactionByBlockNumberAndIndex(
block.Number, uint64(0),
).Return(tx, nil)
mockReader.EXPECT().ReceiptByBlockNumberAndIndex(
block.Number, uint64(0),
).Return(block.Receipts[0], block.Hash, nil)
mockSyncReader.EXPECT().PendingData().Return(&preConfirmedPlaceHolder, nil)
}

mockNotFound := func(
mockReader *mocks.MockReader,
mockSyncReader *mocks.MockSyncReader,
) {
mockReader.EXPECT().TransactionByHash(gomock.Any()).Return(nil, db.ErrKeyNotFound)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
gomock.Any(),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingData().Return(&preConfirmedPlaceHolder, nil).Times(2)
}

Expand Down Expand Up @@ -351,9 +359,9 @@ func TestTransactionStatus(t *testing.T) {
Execution: rpcv9.UnknownExecution,
},
setupMocks: func(mockReader *mocks.MockReader, mockSyncReader *mocks.MockSyncReader) {
mockReader.EXPECT().TransactionByHash(
targetTxnHash,
).Return(nil, db.ErrKeyNotFound)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(targetTxnHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingData().Return(
&core.PreConfirmed{
Block: &core.Block{
Expand Down Expand Up @@ -545,7 +553,9 @@ func TestSubmittedTransactionsCache(t *testing.T) {

res, err := rpcv9Handler.AddTransaction(ctx, broadcastedTxn)
require.Nil(t, err)
mockReader.EXPECT().TransactionByHash(res.TransactionHash).Return(nil, db.ErrKeyNotFound)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(res.TransactionHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingData().Return(&preConfirmedPlaceHolder, nil).Times(2)

status, err := handler.TransactionStatus(ctx, res.TransactionHash)
Expand Down Expand Up @@ -577,7 +587,9 @@ func TestSubmittedTransactionsCache(t *testing.T) {

res, err := rpcv9Handler.AddTransaction(ctx, broadcastedTxn)
require.Nil(t, err)
mockReader.EXPECT().TransactionByHash(res.TransactionHash).Return(nil, db.ErrKeyNotFound)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(res.TransactionHash),
).Return(uint64(0), uint64(0), db.ErrKeyNotFound)
mockSyncReader.EXPECT().PendingData().Return(&preConfirmedPlaceHolder, nil).Times(2)

// Expire cache entry
Expand Down
12 changes: 10 additions & 2 deletions rpc/v10/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,23 @@ func (h *Handler) TransactionReceiptByHash(
return adaptedReceipt, nil
}

txn, err := h.bcReader.TransactionByHash(hash)
blockNumber, idx, err := h.bcReader.BlockNumberAndIndexByTxHash((*felt.TransactionHash)(hash))
if err != nil {
if !errors.Is(err, db.ErrKeyNotFound) {
return nil, rpccore.ErrInternal.CloneWithData(err)
}
return nil, rpccore.ErrTxnHashNotFound
}

receipt, blockHash, blockNumber, err := h.bcReader.Receipt(hash)
txn, err := h.bcReader.TransactionByBlockNumberAndIndex(blockNumber, idx)
if err != nil {
if !errors.Is(err, db.ErrKeyNotFound) {
return nil, rpccore.ErrInternal.CloneWithData(err)
}
return nil, rpccore.ErrTxnHashNotFound
}

receipt, blockHash, err := h.bcReader.ReceiptByBlockNumberAndIndex(blockNumber, idx)
if err != nil {
return nil, rpccore.ErrTxnHashNotFound
}
Expand Down
11 changes: 9 additions & 2 deletions rpc/v8/l1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,15 @@ func TestGetMessageStatus(t *testing.T) {
nil,
)
// Expects for h.TransactionStatus()
mockReader.EXPECT().TransactionByHash(msg.L1HandlerHash).Return(l1handlerTxns[i], nil)
mockReader.EXPECT().Receipt(msg.L1HandlerHash).Return(block.Receipts[0], block.Hash, block.Number, nil)
mockReader.EXPECT().BlockNumberAndIndexByTxHash(
(*felt.TransactionHash)(msg.L1HandlerHash),
).Return(block.Number, uint64(0), nil)
mockReader.EXPECT().TransactionByBlockNumberAndIndex(
block.Number, uint64(0),
).Return(l1handlerTxns[i], nil)
mockReader.EXPECT().ReceiptByBlockNumberAndIndex(
block.Number, uint64(0),
).Return(block.Receipts[0], block.Hash, nil)
mockReader.EXPECT().L1Head().Return(core.L1Head{BlockNumber: uint64(test.l1HeadBlockNum)}, nil)
}
msgStatuses, rpcErr := handler.GetMessageStatus(t.Context(), &test.l1TxnHash)
Expand Down
Loading
Loading