diff --git a/state/interfaces.go b/state/interfaces.go index 6e68dd9ad0..08a246f2ad 100644 --- a/state/interfaces.go +++ b/state/interfaces.go @@ -161,6 +161,7 @@ type storage interface { AddL1InfoTreeRecursiveRootToExitRoot(ctx context.Context, exitRoot *L1InfoTreeRecursiveExitRootStorageEntry, dbTx pgx.Tx) error GetAllL1InfoTreeRecursiveRootEntries(ctx context.Context, dbTx pgx.Tx) ([]L1InfoTreeRecursiveExitRootStorageEntry, error) GetLatestL1InfoTreeRecursiveRoot(ctx context.Context, maxBlockNumber uint64, dbTx pgx.Tx) (L1InfoTreeRecursiveExitRootStorageEntry, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error storeblobsequences } diff --git a/state/mocks/mock_storage.go b/state/mocks/mock_storage.go index 8b2cb5336c..88e5b3d7ad 100644 --- a/state/mocks/mock_storage.go +++ b/state/mocks/mock_storage.go @@ -51,6 +51,10 @@ func (_m *StorageMock) AddAccumulatedInputHash(ctx context.Context, batchNum uin return r0 } +func (_m *StorageMock) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error { + return nil +} + // StorageMock_AddAccumulatedInputHash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddAccumulatedInputHash' type StorageMock_AddAccumulatedInputHash_Call struct { *mock.Call diff --git a/state/pgstatestorage/batch.go b/state/pgstatestorage/batch.go index 8b242dce66..4e3f5d070e 100644 --- a/state/pgstatestorage/batch.go +++ b/state/pgstatestorage/batch.go @@ -1054,3 +1054,11 @@ func (p *PostgresStorage) GetNotCheckedBatches(ctx context.Context, dbTx pgx.Tx) return batches, nil } + +func (p *PostgresStorage) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error { + const updateL2DataSQL = "UPDATE state.batch SET timestamp = $1 WHERE batch_num = $2" + + e := p.getExecQuerier(dbTx) + _, err := e.Exec(ctx, updateL2DataSQL, batchTime.UTC(), batchNumber) + return err +} diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches.go b/synchronizer/actions/etrog/processor_l1_sequence_batches.go index acce3deaa2..ef3ab9f3e5 100644 --- a/synchronizer/actions/etrog/processor_l1_sequence_batches.go +++ b/synchronizer/actions/etrog/processor_l1_sequence_batches.go @@ -32,6 +32,7 @@ type stateProcessSequenceBatches interface { AddVirtualBatch(ctx context.Context, virtualBatch *state.VirtualBatch, dbTx pgx.Tx) error AddTrustedReorg(ctx context.Context, trustedReorg *state.TrustedReorg, dbTx pgx.Tx) error GetL1InfoTreeDataFromBatchL2Data(ctx context.Context, batchL2Data []byte, dbTx pgx.Tx) (map[uint32]state.L1DataV2, common.Hash, common.Hash, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error } type syncProcessSequenceBatchesInterface interface { @@ -276,6 +277,12 @@ func (p *ProcessorL1SequenceBatchesEtrog) ProcessSequenceBatches(ctx context.Con } return err } + + // Update the existing batch with L1's MaxSequenceTimestamp + err = p.updatePermissionLessBatchTimestamp(ctx, batch.BatchNumber, l1BlockTimestamp, dbTx) + if err != nil { + return err + } } // Call the check trusted state method to compare trusted and virtual state @@ -419,3 +426,23 @@ func (p *ProcessorL1SequenceBatchesEtrog) checkTrustedState(ctx context.Context, func (p *ProcessorL1SequenceBatchesEtrog) halt(ctx context.Context, err error) { p.halter.CriticalError(ctx, err) } + +// updatePermissionLessBatchTimestamp updates the batch timestamp for permission less rpc +func (p *ProcessorL1SequenceBatchesEtrog) updatePermissionLessBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error { + if p.sync.IsTrustedSequencer() { + return nil + } + + log.Infof("Permission less rpc updates batch timestamp for batch: %v with new timestamp:%v", batchNumber, batchTime) + err := p.state.UpdateBatchTimestamp(ctx, batchNumber, batchTime, dbTx) + if err != nil { + log.Errorf("error update batch timestamp for batch: %v, batchTime:%v, . Error; %v", batchNumber, batchTime, err) + rollbackErr := dbTx.Rollback(ctx) + if rollbackErr != nil { + log.Errorf("error rolling back state. BatchNumber: %d, batchTime:%v, rollbackErr: %v", batchNumber, batchTime, rollbackErr) + return rollbackErr + } + return err + } + return nil +} diff --git a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go index a97003c2f2..4647a5d6b3 100644 --- a/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go +++ b/synchronizer/actions/etrog/processor_l1_sequence_batches_test.go @@ -99,6 +99,7 @@ func TestL1SequenceBatchesTrustedBatchSequencedThatAlreadyExistsHappyPath(t *tes l1InfoRoot := common.HexToHash(hashExamplesValues[0]) l1Block := newL1Block(mocks, batch, l1InfoRoot) expectationsPreExecution(t, mocks, ctx, batch, nil) + mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(false) executionResponse := newProcessBatchResponseV2(batch) expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) @@ -116,6 +117,7 @@ func TestL1SequenceBatchesPermissionlessBatchSequencedThatAlreadyExistsHappyPath l1Block := newL1Block(mocks, batch, l1InfoRoot) expectationsPreExecution(t, mocks, ctx, batch, nil) executionResponse := newProcessBatchResponseV2(batch) + mocks.Synchronizer.EXPECT().IsTrustedSequencer().Return(false) expectationsForExecution(t, mocks, ctx, l1Block.SequencedBatches[1][0], l1Block.ReceivedAt, executionResponse) mocks.State.EXPECT().AddAccumulatedInputHash(ctx, executionResponse.NewBatchNum, common.BytesToHash(executionResponse.NewAccInputHash), mocks.DbTx).Return(nil) expectationsAddSequencedBatch(t, mocks, ctx, executionResponse) diff --git a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go index e7b6e9b262..2c915957cf 100644 --- a/synchronizer/common/syncinterfaces/mocks/state_full_interface.go +++ b/synchronizer/common/syncinterfaces/mocks/state_full_interface.go @@ -2900,6 +2900,11 @@ func (_m *StateFullInterface) UpdateForkIDBlockNumber(ctx context.Context, forkd return r0 } +// UpdateBatchTimestamp provides a mock function with given fields: ctx, batchNumber, batchTime, dbTx +func (_m *StateFullInterface) UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error { + return nil +} + // StateFullInterface_UpdateForkIDBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateForkIDBlockNumber' type StateFullInterface_UpdateForkIDBlockNumber_Call struct { *mock.Call diff --git a/synchronizer/common/syncinterfaces/state.go b/synchronizer/common/syncinterfaces/state.go index b02be4cd51..2078518e53 100644 --- a/synchronizer/common/syncinterfaces/state.go +++ b/synchronizer/common/syncinterfaces/state.go @@ -86,6 +86,7 @@ type StateFullInterface interface { UpdateForkIDBlockNumber(ctx context.Context, forkdID uint64, newBlockNumber uint64, updateMemCache bool, dbTx pgx.Tx) error GetLastL2BlockNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error) GetL2BlockByNumber(ctx context.Context, blockNumber uint64, dbTx pgx.Tx) (*state.L2Block, error) + UpdateBatchTimestamp(ctx context.Context, batchNumber uint64, batchTime time.Time, dbTx pgx.Tx) error StateBlobSequencerReader StateBlobSequenceWriter }