diff --git a/db/migrations/state/0015.sql b/db/migrations/state/0015.sql new file mode 100644 index 0000000000..05657826cc --- /dev/null +++ b/db/migrations/state/0015.sql @@ -0,0 +1,6 @@ +-- +migrate Up +CREATE INDEX IF NOT EXISTS idx_receipt_tx_index ON state.receipt (block_num, tx_index); + +-- +migrate Down +DROP INDEX IF EXISTS state.idx_receipt_tx_index; + diff --git a/db/migrations/state/0015_test.go b/db/migrations/state/0015_test.go new file mode 100644 index 0000000000..20f34bdbf9 --- /dev/null +++ b/db/migrations/state/0015_test.go @@ -0,0 +1,49 @@ +package migrations_test + +import ( + "database/sql" + "testing" + + "github.com/stretchr/testify/assert" +) + +// this migration changes length of the token name +type migrationTest0015 struct{} + +func (m migrationTest0015) InsertData(db *sql.DB) error { + return nil +} + +func (m migrationTest0015) RunAssertsAfterMigrationUp(t *testing.T, db *sql.DB) { + indexes := []string{ + "idx_receipt_tx_index", + } + // Check indexes adding + for _, idx := range indexes { + // getIndex + const getIndex = `SELECT count(*) FROM pg_indexes WHERE indexname = $1;` + row := db.QueryRow(getIndex, idx) + var result int + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 1, result) + } +} + +func (m migrationTest0015) RunAssertsAfterMigrationDown(t *testing.T, db *sql.DB) { + indexes := []string{ + "idx_receipt_tx_index", + } + // Check indexes removing + for _, idx := range indexes { + // getIndex + const getIndex = `SELECT count(*) FROM pg_indexes WHERE indexname = $1;` + row := db.QueryRow(getIndex, idx) + var result int + assert.NoError(t, row.Scan(&result)) + assert.Equal(t, 0, result) + } +} + +func TestMigration0015(t *testing.T) { + runMigrationTest(t, 15, migrationTest0015{}) +} diff --git a/state/pgstatestorage/transaction.go b/state/pgstatestorage/transaction.go index 5ef4ad9485..9d8fe15efa 100644 --- a/state/pgstatestorage/transaction.go +++ b/state/pgstatestorage/transaction.go @@ -377,7 +377,13 @@ func scanLogs(rows pgx.Rows) ([]*types.Log, error) { // GetTxsByBlockNumber returns all the txs in a given block func (p *PostgresStorage) GetTxsByBlockNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) ([]*types.Transaction, error) { - const getTxsByBlockNumSQL = "SELECT encoded FROM state.transaction WHERE l2_block_num = $1" + const getTxsByBlockNumSQL = `SELECT t.encoded + FROM state.transaction t + JOIN state.receipt r + ON t.hash = r.tx_hash + WHERE t.l2_block_num = $1 + AND r.block_num = $1 + ORDER by r.tx_index ASC` q := p.getExecQuerier(dbTx) rows, err := q.Query(ctx, getTxsByBlockNumSQL, blockNumber) diff --git a/state/trace.go b/state/trace.go index 22cc5b5306..c567343c82 100644 --- a/state/trace.go +++ b/state/trace.go @@ -49,28 +49,23 @@ func (s *State) DebugTransaction(ctx context.Context, transactionHash common.Has return nil, err } - // if tx index is zero, we need to get the state root from the previous block - // else we need to get the state root from the previous tx + // the old state root is the previous block state root var oldStateRoot common.Hash - if receipt.TransactionIndex == 0 { - // get the previous L2 Block - previousL2BlockNumber := uint64(0) - if receipt.BlockNumber.Uint64() > 0 { - previousL2BlockNumber = receipt.BlockNumber.Uint64() - 1 - } - previousL2Block, err := s.GetL2BlockByNumber(ctx, previousL2BlockNumber, dbTx) - if err != nil { - return nil, err - } - oldStateRoot = previousL2Block.Root() - } else { - previousTx := l2Block.Transactions()[receipt.TransactionIndex-1] - // gets the tx receipt - previousReceipt, err := s.GetTransactionReceipt(ctx, previousTx.Hash(), dbTx) - if err != nil { - return nil, err - } - oldStateRoot = common.BytesToHash(previousReceipt.PostState) + previousL2BlockNumber := uint64(0) + if receipt.BlockNumber.Uint64() > 0 { + previousL2BlockNumber = receipt.BlockNumber.Uint64() - 1 + } + previousL2Block, err := s.GetL2BlockByNumber(ctx, previousL2BlockNumber, dbTx) + if err != nil { + return nil, err + } + oldStateRoot = previousL2Block.Root() + + // since the executor only stores the state roots by block, we need to + // execute all the txs in the block until the tx we want to trace + var txsToEncode []types.Transaction + for i := 0; i <= int(receipt.TransactionIndex); i++ { + txsToEncode = append(txsToEncode, *l2Block.Transactions()[i]) } // gets batch that including the l2 block @@ -111,7 +106,7 @@ func (s *State) DebugTransaction(ctx context.Context, transactionHash common.Has } } // generate batch l2 data for the transaction - batchL2Data, err := EncodeTransactions([]types.Transaction{*tx}, []uint8{MaxEffectivePercentage}, forkId) + batchL2Data, err := EncodeTransactions(txsToEncode, []uint8{MaxEffectivePercentage}, forkId) if err != nil { return nil, err } @@ -192,7 +187,7 @@ func (s *State) DebugTransaction(ctx context.Context, transactionHash common.Has deltaTimestamp := uint32(uint64(time.Now().Unix()) - l2Block.Time()) transactions := s.BuildChangeL2Block(deltaTimestamp, uint32(0)) - batchL2Data, err := EncodeTransactions([]types.Transaction{*tx}, []uint8{MaxEffectivePercentage}, forkId) + batchL2Data, err := EncodeTransactions(txsToEncode, []uint8{MaxEffectivePercentage}, forkId) if err != nil { log.Errorf("error encoding transaction ", err) return nil, err