diff --git a/db/migrations/pool/0013.sql b/db/migrations/pool/0013.sql new file mode 100644 index 0000000000..fcf7a58674 --- /dev/null +++ b/db/migrations/pool/0013.sql @@ -0,0 +1,7 @@ +-- +migrate Up +ALTER TABLE pool.transaction + ADD COLUMN reserved_zkcounters jsonb; + +-- +migrate Down +ALTER TABLE pool.transaction + DROP COLUMN reserved_zkcounters; diff --git a/db/migrations/pool/0013_test.go b/db/migrations/pool/0013_test.go new file mode 100644 index 0000000000..e25417a944 --- /dev/null +++ b/db/migrations/pool/0013_test.go @@ -0,0 +1,50 @@ +package pool_migrations_test + +import ( + "database/sql" + "testing" + + "github.com/0xPolygonHermez/zkevm-node/state" + "github.com/stretchr/testify/require" +) + +// this migration adds reserved_zkcounters to the transaction +type migrationTest0013 struct{} + +func (m migrationTest0013) InsertData(db *sql.DB) error { + return nil +} + +func (m migrationTest0013) RunAssertsAfterMigrationUp(t *testing.T, db *sql.DB) { + var reserved_zkcounters = state.ZKCounters{ + GasUsed: 0, + KeccakHashes: 1, + PoseidonHashes: 2, + } + + const insertTx = ` + INSERT INTO pool.transaction (hash, ip, received_at, from_address, reserved_zkcounters) + VALUES ('0x0001', '127.0.0.1', '2023-12-07', '0x0011', $1)` + + _, err := db.Exec(insertTx, reserved_zkcounters) + require.NoError(t, err) +} + +func (m migrationTest0013) RunAssertsAfterMigrationDown(t *testing.T, db *sql.DB) { + var reserved_zkcounters = state.ZKCounters{ + GasUsed: 0, + KeccakHashes: 1, + PoseidonHashes: 2, + } + + const insertTx = ` + INSERT INTO pool.transaction (hash, ip, received_at, from_address, reserved_zkcounters) + VALUES ('0x0001', '127.0.0.1', '2023-12-07', '0x0011', $1)` + + _, err := db.Exec(insertTx, reserved_zkcounters) + require.Error(t, err) +} + +func TestMigration0013(t *testing.T) { + runMigrationTest(t, 13, migrationTest0013{}) +} diff --git a/pool/interfaces.go b/pool/interfaces.go index e61796453a..0544acfe76 100644 --- a/pool/interfaces.go +++ b/pool/interfaces.go @@ -33,7 +33,7 @@ type storage interface { GetTxFromAddressFromByHash(ctx context.Context, hash common.Hash) (common.Address, uint64, error) GetTransactionByHash(ctx context.Context, hash common.Hash) (*Transaction, error) GetTransactionByL2Hash(ctx context.Context, hash common.Hash) (*Transaction, error) - GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, error) + GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, *state.ZKCounters, error) DeleteTransactionByHash(ctx context.Context, hash common.Hash) error MarkWIPTxsAsPending(ctx context.Context) error GetAllAddressesBlocked(ctx context.Context) ([]common.Address, error) diff --git a/pool/pgpoolstorage/pgpoolstorage.go b/pool/pgpoolstorage/pgpoolstorage.go index b930f25a5a..fbc0aaea62 100644 --- a/pool/pgpoolstorage/pgpoolstorage.go +++ b/pool/pgpoolstorage/pgpoolstorage.go @@ -75,10 +75,11 @@ func (p *PostgresPoolStorage) AddTx(ctx context.Context, tx pool.Transaction) er from_address, is_wip, ip, - failed_reason + failed_reason, + reserved_zkcounters ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, NULL) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, NULL, $20) ON CONFLICT (hash) DO UPDATE SET encoded = $2, decoded = $3, @@ -98,7 +99,8 @@ func (p *PostgresPoolStorage) AddTx(ctx context.Context, tx pool.Transaction) er from_address = $17, is_wip = $18, ip = $19, - failed_reason = NULL + failed_reason = NULL, + reserved_zkcounters = $20 ` // Get FromAddress from the JSON data @@ -127,7 +129,8 @@ func (p *PostgresPoolStorage) AddTx(ctx context.Context, tx pool.Transaction) er tx.ReceivedAt, fromAddress, tx.IsWIP, - tx.IP); err != nil { + tx.IP, + tx.ReservedZKCounters); err != nil { return err } return nil @@ -144,11 +147,11 @@ func (p *PostgresPoolStorage) GetTxsByStatus(ctx context.Context, status pool.Tx ) if limit == 0 { sql = `SELECT encoded, status, received_at, is_wip, ip, cumulative_gas_used, used_keccak_hashes, used_poseidon_hashes, used_poseidon_paddings, used_mem_aligns, - used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason FROM pool.transaction WHERE status = $1 ORDER BY gas_price DESC` + used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason, reserved_zkcounters FROM pool.transaction WHERE status = $1 ORDER BY gas_price DESC` rows, err = p.db.Query(ctx, sql, status.String()) } else { sql = `SELECT encoded, status, received_at, is_wip, ip, cumulative_gas_used, used_keccak_hashes, used_poseidon_hashes, used_poseidon_paddings, used_mem_aligns, - used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason FROM pool.transaction WHERE status = $1 ORDER BY gas_price DESC LIMIT $2` + used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason, reserved_zkcounters FROM pool.transaction WHERE status = $1 ORDER BY gas_price DESC LIMIT $2` rows, err = p.db.Query(ctx, sql, status.String(), limit) } if err != nil { @@ -177,7 +180,7 @@ func (p *PostgresPoolStorage) GetNonWIPPendingTxs(ctx context.Context) ([]pool.T ) sql = `SELECT encoded, status, received_at, is_wip, ip, cumulative_gas_used, used_keccak_hashes, used_poseidon_hashes, used_poseidon_paddings, used_mem_aligns, - used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason FROM pool.transaction WHERE is_wip IS FALSE and status = $1` + used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason, reserved_zkcounters FROM pool.transaction WHERE is_wip IS FALSE and status = $1` rows, err = p.db.Query(ctx, sql, pool.TxStatusPending) if err != nil { @@ -236,7 +239,8 @@ func (p *PostgresPoolStorage) GetTxs(ctx context.Context, filterStatus pool.TxSt received_at, nonce, is_wip, - ip + ip, + reserved_zkcounters FROM pool.transaction p1 WHERE @@ -265,7 +269,8 @@ func (p *PostgresPoolStorage) GetTxs(ctx context.Context, filterStatus pool.TxSt received_at, nonce, is_wip, - ip + ip, + reserved_zkcounters FROM pool.transaction p1 WHERE @@ -285,8 +290,9 @@ func (p *PostgresPoolStorage) GetTxs(ctx context.Context, filterStatus pool.TxSt cumulativeGasUsed uint64 usedKeccakHashes, usedPoseidonHashes, usedPoseidonPaddings, usedMemAligns, usedArithmetics, usedBinaries, usedSteps, usedSHA256Hashes uint32 - nonce uint64 - isWIP bool + nonce uint64 + isWIP bool + reservedZKCounters state.ZKCounters ) args := []interface{}{filterStatus, minGasPrice, limit} @@ -316,6 +322,7 @@ func (p *PostgresPoolStorage) GetTxs(ctx context.Context, filterStatus pool.TxSt &nonce, &isWIP, &ip, + &reservedZKCounters, ) if err != nil { @@ -345,6 +352,7 @@ func (p *PostgresPoolStorage) GetTxs(ctx context.Context, filterStatus pool.TxSt } tx.IsWIP = isWIP tx.IP = ip + tx.ReservedZKCounters = reservedZKCounters txs = append(txs, tx) } @@ -511,7 +519,7 @@ func (p *PostgresPoolStorage) IsTxPending(ctx context.Context, hash common.Hash) // GetTxsByFromAndNonce get all the transactions from the pool with the same from and nonce func (p *PostgresPoolStorage) GetTxsByFromAndNonce(ctx context.Context, from common.Address, nonce uint64) ([]pool.Transaction, error) { sql := `SELECT encoded, status, received_at, is_wip, ip, cumulative_gas_used, used_keccak_hashes, used_poseidon_hashes, - used_poseidon_paddings, used_mem_aligns, used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason + used_poseidon_paddings, used_mem_aligns, used_arithmetics, used_binaries, used_steps, used_sha256_hashes, failed_reason, reserved_zkcounters FROM pool.transaction WHERE from_address = $1 AND nonce = $2` @@ -682,10 +690,11 @@ func scanTx(rows pgx.Rows) (*pool.Transaction, error) { usedSteps uint32 usedSHA256Hashes uint32 failedReason *string + reservedZKCounters state.ZKCounters ) if err := rows.Scan(&encoded, &status, &receivedAt, &isWIP, &ip, &cumulativeGasUsed, &usedKeccakHashes, &usedPoseidonHashes, - &usedPoseidonPaddings, &usedMemAligns, &usedArithmetics, &usedBinaries, &usedSteps, &usedSHA256Hashes, &failedReason); err != nil { + &usedPoseidonPaddings, &usedMemAligns, &usedArithmetics, &usedBinaries, &usedSteps, &usedSHA256Hashes, &failedReason, &reservedZKCounters); err != nil { return nil, err } @@ -714,6 +723,7 @@ func scanTx(rows pgx.Rows) (*pool.Transaction, error) { tx.ZKCounters.Steps = usedSteps tx.ZKCounters.Sha256Hashes_V2 = usedSHA256Hashes tx.FailedReason = failedReason + tx.ReservedZKCounters = reservedZKCounters return tx, nil } @@ -728,21 +738,22 @@ func (p *PostgresPoolStorage) DeleteTransactionByHash(ctx context.Context, hash } // GetTxZkCountersByHash gets a transaction zkcounters by its hash -func (p *PostgresPoolStorage) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, error) { - var zkCounters state.ZKCounters +func (p *PostgresPoolStorage) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, *state.ZKCounters, error) { + var usedZKCounters state.ZKCounters + var reservedZKCounters state.ZKCounters sql := `SELECT cumulative_gas_used, used_keccak_hashes, used_poseidon_hashes, used_poseidon_paddings, used_mem_aligns, - used_arithmetics, used_binaries, used_steps, used_sha256_hashes FROM pool.transaction WHERE hash = $1` - err := p.db.QueryRow(ctx, sql, hash.String()).Scan(&zkCounters.GasUsed, &zkCounters.KeccakHashes, - &zkCounters.PoseidonHashes, &zkCounters.PoseidonPaddings, - &zkCounters.MemAligns, &zkCounters.Arithmetics, &zkCounters.Binaries, &zkCounters.Steps, &zkCounters.Sha256Hashes_V2) + used_arithmetics, used_binaries, used_steps, used_sha256_hashes, reserved_zkcounters FROM pool.transaction WHERE hash = $1` + err := p.db.QueryRow(ctx, sql, hash.String()).Scan(&usedZKCounters.GasUsed, &usedZKCounters.KeccakHashes, + &usedZKCounters.PoseidonHashes, &usedZKCounters.PoseidonPaddings, + &usedZKCounters.MemAligns, &usedZKCounters.Arithmetics, &usedZKCounters.Binaries, &usedZKCounters.Steps, &usedZKCounters.Sha256Hashes_V2, &reservedZKCounters) if errors.Is(err, pgx.ErrNoRows) { - return nil, pool.ErrNotFound + return nil, nil, pool.ErrNotFound } else if err != nil { - return nil, err + return nil, nil, err } - return &zkCounters, nil + return &usedZKCounters, &reservedZKCounters, nil } // MarkWIPTxsAsPending updates WIP status to non WIP diff --git a/pool/pool.go b/pool/pool.go index 6f67982665..b15df8ebd2 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -53,7 +53,8 @@ type Pool struct { } type preExecutionResponse struct { - usedZkCounters state.ZKCounters + usedZKCounters state.ZKCounters + reservedZKCounters state.ZKCounters isExecutorLevelError bool OOCError error OOGError error @@ -238,7 +239,8 @@ func (p *Pool) StoreTx(ctx context.Context, tx types.Transaction, ip string, isW } poolTx := NewTransaction(tx, ip, isWIP) - poolTx.ZKCounters = preExecutionResponse.usedZkCounters + poolTx.ZKCounters = preExecutionResponse.usedZKCounters + poolTx.ReservedZKCounters = preExecutionResponse.reservedZKCounters return p.storage.AddTx(ctx, *poolTx) } @@ -292,7 +294,7 @@ func (p *Pool) ValidateBreakEvenGasPrice(ctx context.Context, tx types.Transacti // preExecuteTx executes a transaction to calculate its zkCounters func (p *Pool) preExecuteTx(ctx context.Context, tx types.Transaction) (preExecutionResponse, error) { - response := preExecutionResponse{usedZkCounters: state.ZKCounters{}, OOCError: nil, OOGError: nil, isReverted: false} + response := preExecutionResponse{usedZKCounters: state.ZKCounters{}, reservedZKCounters: state.ZKCounters{}, OOCError: nil, OOGError: nil, isReverted: false} // TODO: Add effectivePercentage = 0xFF to the request (factor of 1) when gRPC message is updated processBatchResponse, err := p.state.PreProcessTransaction(ctx, &tx, nil) @@ -309,7 +311,8 @@ func (p *Pool) preExecuteTx(ctx context.Context, tx types.Transaction) (preExecu response.OOGError = err } if processBatchResponse != nil && processBatchResponse.BlockResponses != nil && len(processBatchResponse.BlockResponses) > 0 { - response.usedZkCounters = processBatchResponse.UsedZkCounters + response.usedZKCounters = processBatchResponse.UsedZkCounters + response.reservedZKCounters = processBatchResponse.ReservedZkCounters response.txResponse = processBatchResponse.BlockResponses[0].TransactionResponses[0] } return response, nil @@ -335,7 +338,8 @@ func (p *Pool) preExecuteTx(ctx context.Context, tx types.Transaction) (preExecu } } - response.usedZkCounters = processBatchResponse.UsedZkCounters + response.usedZKCounters = processBatchResponse.UsedZkCounters + response.reservedZKCounters = processBatchResponse.ReservedZkCounters response.txResponse = processBatchResponse.BlockResponses[0].TransactionResponses[0] } diff --git a/sequencer/interfaces.go b/sequencer/interfaces.go index 21347787c1..9008fbef09 100644 --- a/sequencer/interfaces.go +++ b/sequencer/interfaces.go @@ -22,7 +22,7 @@ type txPool interface { MarkWIPTxsAsPending(ctx context.Context) error GetNonWIPPendingTxs(ctx context.Context) ([]pool.Transaction, error) UpdateTxStatus(ctx context.Context, hash common.Hash, newStatus pool.TxStatus, isWIP bool, failedReason *string) error - GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, error) + GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, *state.ZKCounters, error) UpdateTxWIPStatus(ctx context.Context, hash common.Hash, isWIP bool) error GetGasPrices(ctx context.Context) (pool.GasPrices, error) GetDefaultMinGasPriceAllowed() uint64 diff --git a/sequencer/mock_pool.go b/sequencer/mock_pool.go index 5882c83557..00bc480699 100644 --- a/sequencer/mock_pool.go +++ b/sequencer/mock_pool.go @@ -210,7 +210,7 @@ func (_m *PoolMock) GetNonWIPPendingTxs(ctx context.Context) ([]pool.Transaction } // GetTxZkCountersByHash provides a mock function with given fields: ctx, hash -func (_m *PoolMock) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, error) { +func (_m *PoolMock) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) (*state.ZKCounters, *state.ZKCounters, error) { ret := _m.Called(ctx, hash) if len(ret) == 0 { @@ -218,8 +218,9 @@ func (_m *PoolMock) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) } var r0 *state.ZKCounters - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*state.ZKCounters, error)); ok { + var r1 *state.ZKCounters + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*state.ZKCounters, *state.ZKCounters, error)); ok { return rf(ctx, hash) } if rf, ok := ret.Get(0).(func(context.Context, common.Hash) *state.ZKCounters); ok { @@ -230,13 +231,21 @@ func (_m *PoolMock) GetTxZkCountersByHash(ctx context.Context, hash common.Hash) } } - if rf, ok := ret.Get(1).(func(context.Context, common.Hash) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, common.Hash) *state.ZKCounters); ok { r1 = rf(ctx, hash) } else { - r1 = ret.Error(1) + if ret.Get(1) != nil { + r1 = ret.Get(1).(*state.ZKCounters) + } } - return r0, r1 + if rf, ok := ret.Get(2).(func(context.Context, common.Hash) error); ok { + r2 = rf(ctx, hash) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // MarkWIPTxsAsPending provides a mock function with given fields: ctx diff --git a/synchronizer/l2_sync/l2_shared/mocks/state_sync_trusted_state_executor_selector.go b/synchronizer/l2_sync/l2_shared/mocks/state_sync_trusted_state_executor_selector.go index 443130ad92..3e73051404 100644 --- a/synchronizer/l2_sync/l2_shared/mocks/state_sync_trusted_state_executor_selector.go +++ b/synchronizer/l2_sync/l2_shared/mocks/state_sync_trusted_state_executor_selector.go @@ -20,6 +20,52 @@ func (_m *stateSyncTrustedStateExecutorSelector) EXPECT() *stateSyncTrustedState return &stateSyncTrustedStateExecutorSelector_Expecter{mock: &_m.Mock} } +// GetForkIDByBatchNumber provides a mock function with given fields: batchNumber +func (_m *stateSyncTrustedStateExecutorSelector) GetForkIDByBatchNumber(batchNumber uint64) uint64 { + ret := _m.Called(batchNumber) + + if len(ret) == 0 { + panic("no return value specified for GetForkIDByBatchNumber") + } + + var r0 uint64 + if rf, ok := ret.Get(0).(func(uint64) uint64); ok { + r0 = rf(batchNumber) + } else { + r0 = ret.Get(0).(uint64) + } + + return r0 +} + +// stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForkIDByBatchNumber' +type stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call struct { + *mock.Call +} + +// GetForkIDByBatchNumber is a helper method to define mock.On call +// - batchNumber uint64 +func (_e *stateSyncTrustedStateExecutorSelector_Expecter) GetForkIDByBatchNumber(batchNumber interface{}) *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call { + return &stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call{Call: _e.mock.On("GetForkIDByBatchNumber", batchNumber)} +} + +func (_c *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call) Run(run func(batchNumber uint64)) *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(uint64)) + }) + return _c +} + +func (_c *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call) Return(_a0 uint64) *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call) RunAndReturn(run func(uint64) uint64) *stateSyncTrustedStateExecutorSelector_GetForkIDByBatchNumber_Call { + _c.Call.Return(run) + return _c +} + // GetForkIDInMemory provides a mock function with given fields: forkId func (_m *stateSyncTrustedStateExecutorSelector) GetForkIDInMemory(forkId uint64) *state.ForkIDInterval { ret := _m.Called(forkId)