From c4eef1ac5f11b5b1d2750d4ee5cbff5e57fa5cc2 Mon Sep 17 00:00:00 2001 From: Ratan Kaliani Date: Mon, 6 Jan 2025 22:24:26 -0800 Subject: [PATCH] feat(proposer): Check if blockhash is checkpointed (#314) --- proposer/op/proposer/driver.go | 62 +++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/proposer/op/proposer/driver.go b/proposer/op/proposer/driver.go index 9e3e9c6a..e2757064 100644 --- a/proposer/op/proposer/driver.go +++ b/proposer/op/proposer/driver.go @@ -551,32 +551,6 @@ func (l *L2OutputSubmitter) sendTransaction(ctx context.Context, output *eth.Out return nil } -// sendCheckpointTransaction sends a transaction to checkpoint the blockhash corresponding to `blockNumber` on the L2OO contract. -func (l *L2OutputSubmitter) sendCheckpointTransaction(ctx context.Context, blockNumber *big.Int) error { - var receipt *types.Receipt - data, err := l.CheckpointBlockHashTxData(blockNumber) - if err != nil { - return err - } - // TODO: This currently blocks the loop while it waits for the transaction to be confirmed. Up to 3 minutes. - receipt, err = l.Txmgr.Send(ctx, txmgr.TxCandidate{ - TxData: data, - To: l.Cfg.L2OutputOracleAddr, - GasLimit: 0, - }) - if err != nil { - return err - } - - if receipt.Status == types.ReceiptStatusFailed { - l.Log.Error("checkpoint blockhash tx successfully published but reverted", "tx_hash", receipt.TxHash) - } else { - l.Log.Info("checkpoint blockhash tx successfully published", - "tx_hash", receipt.TxHash) - } - return nil -} - // loop is responsible for creating & submitting the next outputs // TODO: Look into adding a transaction cache so the loop isn't waiting for the transaction to confirm. This sometimes takes up to 30s. func (l *L2OutputSubmitter) loop() { @@ -744,9 +718,43 @@ func (l *L2OutputSubmitter) checkpointBlockHash(ctx context.Context) (uint64, co blockHash := header.Hash() blockNumber := header.Number - err = l.sendCheckpointTransaction(cCtx, blockNumber) + // Check if the block hash has ALREADY been checkpointed on the L2OO contract. + // If it has, we can skip the checkpointing step. + contract, err := opsuccinctbindings.NewOPSuccinctL2OutputOracleCaller(*l.Cfg.L2OutputOracleAddr, l.L1Client) if err != nil { return 0, common.Hash{}, err } + maybeBlockHash, err := contract.HistoricBlockHashes(&bind.CallOpts{Context: cCtx}, blockNumber) + if err != nil { + return 0, common.Hash{}, err + } + if maybeBlockHash != (common.Hash{}) { + l.Log.Info("Block hash already checkpointed on L2OO contract", "block_number", blockNumber, "block_hash", blockHash) + return blockNumber.Uint64(), blockHash, nil + } + + // If not, send a transaction to checkpoint the blockhash on the L2OO contract. + var receipt *types.Receipt + data, err := l.CheckpointBlockHashTxData(blockNumber) + if err != nil { + return 0, common.Hash{}, err + } + + // TODO: This currently blocks the loop while it waits for the transaction to be confirmed. Up to 3 minutes. + receipt, err = l.Txmgr.Send(ctx, txmgr.TxCandidate{ + TxData: data, + To: l.Cfg.L2OutputOracleAddr, + GasLimit: 0, + }) + if err != nil { + return 0, common.Hash{}, err + } + + if receipt.Status == types.ReceiptStatusFailed { + l.Log.Error("checkpoint blockhash tx successfully published but reverted", "tx_hash", receipt.TxHash) + } else { + l.Log.Info("checkpoint blockhash tx successfully published", + "tx_hash", receipt.TxHash) + } return blockNumber.Uint64(), blockHash, nil }