diff --git a/adapters/feeder2core/feeder2core.go b/adapters/feeder2core/feeder2core.go index ac3cc1a608..d9a10a580d 100644 --- a/adapters/feeder2core/feeder2core.go +++ b/adapters/feeder2core/feeder2core.go @@ -65,6 +65,17 @@ func AdaptTransactionReceipt(response *feeder.TransactionReceipt) *core.Transact l2ToL1Messages[i] = AdaptL2ToL1Message(msg) } + var es core.ExecutionStatus + switch response.ExecutionStatus { + case feeder.TxnSucceeded: + es = core.TxnSuccess + case feeder.TxnReverted: + es = core.TxnFailure + default: + // Should not happen. + panic("unknown execution status") + } + return &core.TransactionReceipt{ Fee: response.ActualFee, TransactionHash: response.TransactionHash, @@ -72,6 +83,7 @@ func AdaptTransactionReceipt(response *feeder.TransactionReceipt) *core.Transact ExecutionResources: AdaptExecutionResources(response.ExecutionResources), L1ToL2Message: AdaptL1ToL2Message(response.L1ToL2Message), L2ToL1Message: l2ToL1Messages, + ExecutionStatus: es, } } diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 055b9accb8..2f73055838 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -437,7 +437,7 @@ func BlockByNumber(txn db.Transaction, number uint64) (*core.Block, error) { return nil, err } - block.Receipts, err = receiptsByBlockNumber(txn, number) + block.Receipts, err = ReceiptsByBlockNumber(txn, number) if err != nil { return nil, err } @@ -479,7 +479,7 @@ func transactionsByBlockNumber(txn db.Transaction, number uint64) ([]core.Transa return txs, nil } -func receiptsByBlockNumber(txn db.Transaction, number uint64) ([]*core.TransactionReceipt, error) { +func ReceiptsByBlockNumber(txn db.Transaction, number uint64) ([]*core.TransactionReceipt, error) { iterator, err := txn.NewIterator() if err != nil { return nil, err diff --git a/blockchain/event_filter.go b/blockchain/event_filter.go index 15f1457326..40b10425af 100644 --- a/blockchain/event_filter.go +++ b/blockchain/event_filter.go @@ -129,7 +129,7 @@ func (e *EventFilter) Events(cToken *ContinuationToken, chunkSize uint64) ([]*Fi var receipts []*core.TransactionReceipt if curBlock != latest+1 { - receipts, err = receiptsByBlockNumber(e.txn, header.Number) + receipts, err = ReceiptsByBlockNumber(e.txn, header.Number) if err != nil { return nil, nil, err } diff --git a/core/transaction.go b/core/transaction.go index 5e306e1c01..b33ee1494c 100644 --- a/core/transaction.go +++ b/core/transaction.go @@ -15,6 +15,13 @@ import ( "github.com/ethereum/go-ethereum/common" ) +type ExecutionStatus uint8 + +const ( + TxnSuccess ExecutionStatus = iota + 1 + TxnFailure +) + type Event struct { Data []*felt.Felt From *felt.Felt @@ -57,6 +64,7 @@ type TransactionReceipt struct { L1ToL2Message *L1ToL2Message L2ToL1Message []*L2ToL1Message TransactionHash *felt.Felt + ExecutionStatus ExecutionStatus } type Transaction interface { diff --git a/migration/migration.go b/migration/migration.go index a53bf460cf..b6c9ef5da1 100644 --- a/migration/migration.go +++ b/migration/migration.go @@ -23,6 +23,7 @@ var revisions = []revision{ relocateContractStorageRootKeys, recalculateBloomFilters, changeTrieNodeEncoding, + addExecutionStatusSucceeded, } var ErrCallWithNewTransaction = errors.New("call with new transaction") @@ -266,3 +267,68 @@ func changeTrieNodeEncoding(txn db.Transaction) error { } return iterator.Close() } + +// addExecutionStatusSuccess adds the ExecutionStatus field to transaction receipts, which +// was added in Starknet v0.12.1. No failed transactions were included before 0.12.1. +func addExecutionStatusSucceeded(txn db.Transaction) error { + type oldReceipt struct { + Fee *felt.Felt + Events []*core.Event + ExecutionResources *core.ExecutionResources + L1ToL2Message *core.L1ToL2Message + L2ToL1Message []*core.L2ToL1Message + TransactionHash *felt.Felt + ExecutionStatus core.ExecutionStatus + } + + blockchain.RegisterCoreTypesToEncoder() + it, err := txn.NewIterator() + if err != nil { + return err + } + + for blockNumber := uint64(0); ; blockNumber++ { + receipts, err := blockchain.ReceiptsByBlockNumber(txn, blockNumber) + if err != nil { + if errors.Is(err, db.ErrKeyNotFound) { + return nil + } + return err + } + } + + prefix := db.ReceiptsByBlockNumberAndIndex.Key() + var receipt *core.TransactionReceipt + for it.Seek(prefix); it.Valid(); it.Next() { + // Obtain pre-0.12.1 receipt from DB + + key := it.Key() + if !bytes.HasPrefix(key, prefix) { + break + } + + val, err := it.Value() + if err != nil { + return db.CloseAndWrapOnError(it.Close, err) + } + + // Set the execution status and store in DB + + if err := encoder.Unmarshal(val, &receipt); err != nil { + return db.CloseAndWrapOnError(it.Close, err) + } + + receipt.ExecutionStatus = core.TxnSuccess + + receiptBytes, err := encoder.Marshal(receipt) + if err != nil { + return db.CloseAndWrapOnError(it.Close, err) + } + + if err := txn.Set(key, receiptBytes); err != nil { + return db.CloseAndWrapOnError(it.Close, err) + } + } + + return nil +} diff --git a/migration/migration_pkg_test.go b/migration/migration_pkg_test.go index 49e48fe340..eb555ed5a9 100644 --- a/migration/migration_pkg_test.go +++ b/migration/migration_pkg_test.go @@ -153,3 +153,37 @@ func TestChangeTrieNodeEncoding(t *testing.T) { return nil })) } + +func TestAddExecutionStatusSucceeded(t *testing.T) { + testdb := pebble.NewMemTest() + t.Cleanup(func() { + require.NoError(t, testdb.Close()) + }) + + type transactionReceipt struct { + Fee *felt.Felt + Events []*core.Event + ExecutionResources *core.ExecutionResources + L1ToL2Message *core.L1ToL2Message + L2ToL1Message []*core.L2ToL1Message + TransactionHash *felt.Felt + } + + tx := testdb.NewTransaction(true) + receipt := new(transactionReceipt) + receiptBytes, err := encoder.Marshal(receipt) + require.NoError(t, err) + key := db.ReceiptsByBlockNumberAndIndex.Key([]byte{0}, []byte{0}) + err = tx.Set(key, receiptBytes) + require.NoError(t, err) + + require.NoError(t, addExecutionStatusSucceeded(tx)) + + tx.Get(key, func(val []byte) error { + var newReceipt *core.TransactionReceipt + err = encoder.Unmarshal(val, &newReceipt) + require.NoError(t, err) + assert.Equal(t, newReceipt.ExecutionStatus, core.TxnSuccess) + return nil + }) +}