Skip to content

Commit a59f01f

Browse files
ToniRamirezMARR552
andauthored
Halt finalizer in case of full execution error (0xPolygon#1879)
* panic if trusted reorg in synchronizer * fix (0xPolygon#1878) * log * logs * fixes * sync test commented * fix finalizer * fix encodeTransaction * fix encodeTransaction --------- Co-authored-by: Alonso <ARR551@protonmail.com>
1 parent 3f7b785 commit a59f01f

7 files changed

Lines changed: 375 additions & 384 deletions

File tree

sequencer/finalizer.go

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ func (f *finalizer) listenForClosingSignals(ctx context.Context) {
174174
}
175175
f.nextGERMux.Unlock()
176176
// L2Reorg ch
177-
case l2ReorgEvent := <-f.closingSignalCh.L2ReorgCh:
177+
case <-f.closingSignalCh.L2ReorgCh:
178178
log.Debug("finalizer received L2 reorg event")
179179
f.handlingL2Reorg = true
180-
f.worker.HandleL2Reorg(l2ReorgEvent.TxHashes)
180+
f.halt(ctx, fmt.Errorf("L2 reorg event received"))
181181
return
182182
// Too much time without batches in L1 ch
183183
case <-f.closingSignalCh.SendingToL1TimeoutCh:
@@ -203,26 +203,23 @@ func (f *finalizer) finalizeBatches(ctx context.Context) {
203203
log.Debugf("processing tx: %s", tx.Hash.Hex())
204204
err := f.processTransaction(ctx, tx)
205205
if err != nil {
206-
log.Errorf("failed to process transaction in finalizeBatches, Err: %s", err)
206+
log.Errorf("failed to process transaction in finalizeBatches, Err: %v", err)
207207
}
208208

209209
f.sharedResourcesMux.Unlock()
210210
} else {
211-
if f.isBatchAlmostFull() {
212-
// Wait for all transactions to be stored in the DB
213-
log.Infof("Closing batch: %d, because it's almost full.", f.batch.batchNumber)
214-
// The perfect moment to finalize the batch
215-
f.finalizeBatch(ctx)
216-
} else {
217-
// wait for new txs
218-
log.Debugf("no transactions to be processed. Sleeping for %v", f.cfg.SleepDurationInMs.Duration)
219-
if f.cfg.SleepDurationInMs.Duration > 0 {
220-
time.Sleep(f.cfg.SleepDurationInMs.Duration)
221-
}
211+
// wait for new txs
212+
log.Debugf("no transactions to be processed. Sleeping for %v", f.cfg.SleepDurationInMs.Duration)
213+
if f.cfg.SleepDurationInMs.Duration > 0 {
214+
time.Sleep(f.cfg.SleepDurationInMs.Duration)
222215
}
223216
}
224217

225-
if f.isDeadlineEncountered() || f.isBatchFull() {
218+
if f.isDeadlineEncountered() {
219+
log.Infof("Closing batch: %d, because deadline was encountered.", f.batch.batchNumber)
220+
f.finalizeBatch(ctx)
221+
} else if f.isBatchFull() || f.isBatchAlmostFull() {
222+
log.Infof("Closing batch: %d, because it's almost full.", f.batch.batchNumber)
226223
f.finalizeBatch(ctx)
227224
}
228225

@@ -256,6 +253,24 @@ func (f *finalizer) finalizeBatch(ctx context.Context) {
256253
}
257254
}
258255

256+
func (f *finalizer) halt(ctx context.Context, err error) {
257+
debugInfo := &state.DebugInfo{
258+
ErrorType: state.DebugInfoErrorType_FINALIZER_HALT,
259+
Timestamp: time.Now(),
260+
Payload: err.Error(),
261+
}
262+
debugInfoErr := f.dbManager.AddDebugInfo(ctx, debugInfo, nil)
263+
if debugInfoErr != nil {
264+
log.Errorf("error storing finalizer halt debug info: %v", debugInfoErr)
265+
}
266+
267+
for {
268+
log.Errorf("fatal error: %s", err)
269+
log.Error("halting the finalizer")
270+
time.Sleep(5 * time.Second) //nolint:gomnd
271+
}
272+
}
273+
259274
// newWIPBatch closes the current batch and opens a new one, potentially processing forced batches between the batch is closed and the resulting new empty batch
260275
func (f *finalizer) newWIPBatch(ctx context.Context) (*WipBatch, error) {
261276
f.sharedResourcesMux.Lock()
@@ -266,24 +281,23 @@ func (f *finalizer) newWIPBatch(ctx context.Context) (*WipBatch, error) {
266281
return nil, errors.New("state root and local exit root must have value to close batch")
267282
}
268283

284+
// Reprocess full batch as sanity check
285+
processBatchResponse, err := f.reprocessFullBatch(ctx, f.batch.batchNumber, f.batch.stateRoot)
286+
if err != nil || !processBatchResponse.IsBatchProcessed {
287+
log.Info("halting the finalizer because of a reprocessing error")
288+
if err != nil {
289+
f.halt(ctx, fmt.Errorf("failed to reprocess batch, err: %v", err))
290+
} else {
291+
f.halt(ctx, fmt.Errorf("out of counters during reprocessFullBath"))
292+
}
293+
}
294+
295+
// Close the current batch
269296
err = f.closeBatch(ctx)
270297
if err != nil {
271298
return nil, fmt.Errorf("failed to close batch, err: %w", err)
272299
}
273300

274-
// Reprocess full batch to persist the merkle tree
275-
go func() {
276-
processBatchResponse, err := f.reprocessFullBatch(ctx, f.batch.batchNumber, f.batch.stateRoot)
277-
if err != nil || !processBatchResponse.IsBatchProcessed {
278-
log.Info("restarting the sequencer node because of a reprocessing error")
279-
if err != nil {
280-
log.Fatalf("failed to reprocess batch, err: %v", err)
281-
} else {
282-
log.Fatal("Out of counters during reprocessFullBath")
283-
}
284-
}
285-
}()
286-
287301
// Metadata for the next batch
288302
stateRoot := f.batch.stateRoot
289303
lastBatchNumber := f.batch.batchNumber
@@ -691,7 +705,7 @@ func (f *finalizer) openBatch(ctx context.Context, num uint64, ger common.Hash,
691705
func (f *finalizer) reprocessFullBatch(ctx context.Context, batchNum uint64, expectedStateRoot common.Hash) (*state.ProcessBatchResponse, error) {
692706
batch, err := f.dbManager.GetBatchByNumber(ctx, batchNum, nil)
693707
if err != nil {
694-
return nil, fmt.Errorf("failed to get batch by number, err: %w", err)
708+
return nil, fmt.Errorf("failed to get batch by number, err: %v", err)
695709
}
696710
processRequest := state.ProcessRequest{
697711
BatchNumber: batch.BatchNumber,
@@ -705,7 +719,8 @@ func (f *finalizer) reprocessFullBatch(ctx context.Context, batchNum uint64, exp
705719
log.Infof("reprocessFullBatch: BatchNumber: %d, OldStateRoot: %s, Ger: %s", batch.BatchNumber, f.batch.initialStateRoot.String(), batch.GlobalExitRoot.String())
706720
txs, _, err := state.DecodeTxs(batch.BatchL2Data)
707721
if err != nil {
708-
log.Error("reprocessFullBatch: error decoding BatchL2Data before reprocessing full batch: %d. Error: %v", batch.BatchNumber, err)
722+
log.Errorf("reprocessFullBatch: error decoding BatchL2Data before reprocessing full batch: %d. Error: %v", batch.BatchNumber, err)
723+
return nil, fmt.Errorf("reprocessFullBatch: error decoding BatchL2Data before reprocessing full batch: %d. Error: %v", batch.BatchNumber, err)
709724
}
710725
for i, tx := range txs {
711726
log.Infof("reprocessFullBatch: Tx position %d. TxHash: %s", i, tx.Hash())
@@ -739,6 +754,7 @@ func (f *finalizer) reprocessFullBatch(ctx context.Context, batchNum uint64, exp
739754

740755
if result.NewStateRoot != expectedStateRoot {
741756
log.Errorf("batchNumber: %d, reprocessed batch has different state root, expected: %s, got: %s", batch.BatchNumber, expectedStateRoot.Hex(), result.NewStateRoot.Hex())
757+
return nil, fmt.Errorf("batchNumber: %d, reprocessed batch has different state root, expected: %s, got: %s", batch.BatchNumber, expectedStateRoot.Hex(), result.NewStateRoot.Hex())
742758
}
743759

744760
return result, nil

sequencer/worker.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,14 @@ func (w *Worker) UpdateTx(txHash common.Hash, addr common.Address, counters stat
189189
w.workerMutex.Lock()
190190
defer w.workerMutex.Unlock()
191191
log.Infof("UpdateTx tx(%s) addr(%s)", txHash.String(), addr.String())
192-
log.Debugf("UpdateTx counters.CumulativeGasUsed: %s", counters.CumulativeGasUsed)
193-
log.Debugf("UpdateTx counters.UsedKeccakHashes: %s", counters.UsedKeccakHashes)
194-
log.Debugf("UpdateTx counters.UsedPoseidonHashes: %s", counters.UsedPoseidonHashes)
195-
log.Debugf("UpdateTx counters.UsedPoseidonPaddings: %s", counters.UsedPoseidonPaddings)
196-
log.Debugf("UpdateTx counters.UsedMemAligns: %s", counters.UsedMemAligns)
197-
log.Debugf("UpdateTx counters.UsedArithmetics: %s", counters.UsedArithmetics)
198-
log.Debugf("UpdateTx counters.UsedBinaries: %s", counters.UsedBinaries)
199-
log.Debugf("UpdateTx counters.UsedSteps: %s", counters.UsedSteps)
192+
log.Debugf("UpdateTx counters.CumulativeGasUsed: %d", counters.CumulativeGasUsed)
193+
log.Debugf("UpdateTx counters.UsedKeccakHashes: %d", counters.UsedKeccakHashes)
194+
log.Debugf("UpdateTx counters.UsedPoseidonHashes: %d", counters.UsedPoseidonHashes)
195+
log.Debugf("UpdateTx counters.UsedPoseidonPaddings: %d", counters.UsedPoseidonPaddings)
196+
log.Debugf("UpdateTx counters.UsedMemAligns: %d", counters.UsedMemAligns)
197+
log.Debugf("UpdateTx counters.UsedArithmetics: %d", counters.UsedArithmetics)
198+
log.Debugf("UpdateTx counters.UsedBinaries: %d", counters.UsedBinaries)
199+
log.Debugf("UpdateTx counters.UsedSteps: %d", counters.UsedSteps)
200200

201201
addrQueue, found := w.pool[addr.String()]
202202

state/helper.go

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -65,36 +65,8 @@ func EncodeTransactions(txs []types.Transaction) ([]byte, error) {
6565

6666
// EncodeTransaction RLP encodes the given transaction
6767
func EncodeTransaction(tx types.Transaction) ([]byte, error) {
68-
v, r, s := tx.RawSignatureValues()
69-
sign := 1 - (v.Uint64() & 1)
70-
71-
nonce, gasPrice, gas, to, value, data, chainID := tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.ChainId()
72-
log.Debug(nonce, " ", gasPrice, " ", gas, " ", to, " ", value, " ", len(data), " ", chainID)
73-
74-
txCodedRlp, err := rlp.EncodeToBytes([]interface{}{
75-
nonce,
76-
gasPrice,
77-
gas,
78-
to,
79-
value,
80-
data,
81-
chainID, uint(0), uint(0),
82-
})
83-
84-
if err != nil {
85-
return nil, err
86-
}
87-
88-
newV := new(big.Int).Add(big.NewInt(ether155V), big.NewInt(int64(sign)))
89-
newRPadded := fmt.Sprintf("%064s", r.Text(hex.Base))
90-
newSPadded := fmt.Sprintf("%064s", s.Text(hex.Base))
91-
newVPadded := fmt.Sprintf("%02s", newV.Text(hex.Base))
92-
txData, err := hex.DecodeString(hex.EncodeToString(txCodedRlp) + newRPadded + newSPadded + newVPadded)
93-
if err != nil {
94-
return nil, err
95-
}
96-
97-
return txData, nil
68+
transactions := []types.Transaction{tx}
69+
return EncodeTransactions(transactions)
9870
}
9971

10072
// EncodeUnsignedTransaction RLP encodes the given unsigned transaction

state/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ const (
146146
DebugInfoErrorType_OOC_ERROR_ON_REPROCESS_FULL_BATCH = "OOC ON REPROCESS FULL BATCH"
147147
// DebugInfoErrorType_EXECUTOR_RLP_ERROR indicates a error happened decoding the RLP returned by the executor
148148
DebugInfoErrorType_EXECUTOR_RLP_ERROR = "EXECUTOR RLP ERROR"
149+
// DebugInfoErrorType_FINALIZER_HALT indicates a fatal error happened in the finalizer when trying to close a batch
150+
DebugInfoErrorType_FINALIZER_HALT = "FINALIZER HALT"
149151
)
150152

151153
// DebugInfo allows handling runtime debug info

synchronizer/synchronizer.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ func (s *ClientSynchronizer) checkTrustedState(batch state.Batch, tBatch *state.
529529
if reorgReasons.Len() > 0 {
530530
reason := reorgReasons.String()
531531
log.Warnf("Trusted Reorg detected for Batch Number: %d. Reasons: %s", tBatch.BatchNumber, reason)
532+
log.Fatal("TRUSTED REORG DETECTED! Batch: ", batch.BatchNumber)
532533
// Store trusted reorg register
533534
tr := state.TrustedReorg{
534535
BatchNumber: tBatch.BatchNumber,

0 commit comments

Comments
 (0)