Skip to content

Commit 9f75472

Browse files
authored
Add escape hatch (#330)
1 parent 17c0915 commit 9f75472

8 files changed

+472
-178
lines changed

Diff for: arbnode/batch_poster.go

+72-23
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ import (
5555
"github.com/offchainlabs/nitro/util"
5656
"github.com/offchainlabs/nitro/util/arbmath"
5757
"github.com/offchainlabs/nitro/util/blobs"
58-
"github.com/offchainlabs/nitro/util/dbutil"
5958
"github.com/offchainlabs/nitro/util/headerreader"
6059
"github.com/offchainlabs/nitro/util/redisutil"
6160
"github.com/offchainlabs/nitro/util/stopwaiter"
@@ -185,6 +184,7 @@ type BatchPosterConfig struct {
185184
HotShotUrl string `koanf:"hotshot-url"`
186185
UserDataAttestationFile string `koanf:"user-data-attestation-file"`
187186
QuoteFile string `koanf:"quote-file"`
187+
UseEscapeHatch bool `koanf:"use-escape-hatch"`
188188
}
189189

190190
func (c *BatchPosterConfig) Validate() error {
@@ -239,6 +239,7 @@ func BatchPosterConfigAddOptions(prefix string, f *pflag.FlagSet) {
239239
f.Bool(prefix+".check-batch-correctness", DefaultBatchPosterConfig.CheckBatchCorrectness, "setting this to true will run the batch against an inbox multiplexer and verifies that it produces the correct set of messages")
240240
f.String(prefix+".user-data-attestation-file", DefaultBatchPosterConfig.UserDataAttestationFile, "specifies the file containing the user data attestation")
241241
f.String(prefix+".quote-file", DefaultBatchPosterConfig.QuoteFile, "specifies the file containing the quote")
242+
f.Bool(prefix+".use-escape-hatch", DefaultBatchPosterConfig.UseEscapeHatch, "if true, batches will be posted without doing the espresso verification when hotshot is down. If false, wait for hotshot being up")
242243
redislock.AddConfigOptions(prefix+".redis-lock", f)
243244
dataposter.DataPosterConfigAddOptions(prefix+".data-poster", f, dataposter.DefaultDataPosterConfig)
244245
genericconf.WalletConfigAddOptions(prefix+".parent-chain-wallet", f, DefaultBatchPosterConfig.ParentChainWallet.Pathname)
@@ -272,6 +273,7 @@ var DefaultBatchPosterConfig = BatchPosterConfig{
272273
CheckBatchCorrectness: true,
273274
UserDataAttestationFile: "",
274275
QuoteFile: "",
276+
UseEscapeHatch: false,
275277
}
276278

277279
var DefaultBatchPosterL1WalletConfig = genericconf.WalletConfig{
@@ -303,6 +305,7 @@ var TestBatchPosterConfig = BatchPosterConfig{
303305
UseAccessLists: true,
304306
GasEstimateBaseFeeMultipleBips: arbmath.OneInUBips * 3 / 2,
305307
CheckBatchCorrectness: true,
308+
UseEscapeHatch: false,
306309
}
307310

308311
type BatchPosterOpts struct {
@@ -366,6 +369,8 @@ func NewBatchPoster(ctx context.Context, opts *BatchPosterOpts) (*BatchPoster, e
366369
opts.Streamer.lightClientReader = lightClientReader
367370
}
368371

372+
opts.Streamer.UseEscapeHatch = opts.Config().UseEscapeHatch
373+
369374
b := &BatchPoster{
370375
l1Reader: opts.L1Reader,
371376
inbox: opts.Inbox,
@@ -552,43 +557,63 @@ func (b *BatchPoster) checkEspressoValidation(
552557
return nil
553558
}
554559

555-
arbOSConfig, err := b.arbOSVersionGetter.GetArbOSConfigAtHeight(0)
560+
lastConfirmed, err := b.streamer.getLastConfirmedPos()
556561
if err != nil {
557-
return fmt.Errorf("Failed call to GetArbOSConfigAtHeight: %w", err)
558-
}
559-
if arbOSConfig == nil {
560-
return fmt.Errorf("Cannot use a nil ArbOSConfig")
562+
log.Error("failed call to get last confirmed pos", "err", err)
563+
return err
561564
}
562-
if !arbOSConfig.ArbitrumChainParams.EnableEspresso {
565+
566+
// This message has passed the espresso verification
567+
if lastConfirmed != nil && b.building.msgCount <= *lastConfirmed {
563568
return nil
564569
}
565570

566-
hasNotSubmitted, err := b.streamer.HasNotSubmitted(b.building.msgCount)
567-
if err != nil {
568-
return err
569-
}
570-
if hasNotSubmitted {
571-
// Store the pos in the database to be used later to submit the message
572-
// to hotshot for finalization.
573-
log.Info("submitting pos", "pos", b.building.msgCount)
574-
err = b.streamer.SubmitEspressoTransactionPos(b.building.msgCount, b.streamer.db.NewBatch())
571+
log.Warn("this message has not been finalized on L1 or validated")
572+
573+
if b.streamer.UseEscapeHatch {
574+
skip, err := b.streamer.getSkipVerificationPos()
575575
if err != nil {
576-
log.Error("failed to submit espresso transaction pos", "pos", b.building.msgCount, "err", err)
576+
log.Error("failed call to get skip verification pos", "err", err)
577577
return err
578578
}
579-
return fmt.Errorf("this msg has not been included in hotshot")
579+
580+
// Skip checking espresso validation due to hotshot failure
581+
if skip != nil {
582+
if b.building.msgCount <= *skip {
583+
log.Warn("skipped espresso verification due to hotshot failure", "pos", b.building.msgCount)
584+
return nil
585+
}
586+
// TODO: if current position is greater than the `skip`, should set the
587+
// the skip value to nil. This should contribute to better efficiency.
588+
}
580589
}
581590

582-
lastConfirmed, err := b.streamer.getLastConfirmedPos()
583-
if dbutil.IsErrNotFound(err) {
584-
return fmt.Errorf("no confirmed message has been found")
591+
if b.streamer.HotshotDown && b.streamer.UseEscapeHatch {
592+
log.Warn("skipped espresso verification due to hotshot failure", "pos", b.building.msgCount)
593+
return nil
585594
}
595+
596+
return fmt.Errorf("waiting for espresso finalization, pos: %d", b.building.msgCount)
597+
}
598+
599+
func (b *BatchPoster) submitEspressoTransactionPos(pos arbutil.MessageIndex) error {
600+
hasNotSubmitted, err := b.streamer.HasNotSubmitted(pos)
586601
if err != nil {
587602
return err
588603
}
589-
if lastConfirmed < b.building.msgCount {
590-
return fmt.Errorf("this msg has not been finalized on L1 or validated")
604+
if !hasNotSubmitted {
605+
return nil
606+
}
607+
608+
// Store the pos in the database to be used later to submit the message
609+
// to hotshot for finalization.
610+
log.Info("submitting pos", "pos", pos)
611+
err = b.streamer.SubmitEspressoTransactionPos(pos, b.streamer.db.NewBatch())
612+
if err != nil {
613+
log.Error("failed to submit espresso transaction pos", "pos", pos, "err", err)
614+
return err
591615
}
616+
592617
return nil
593618
}
594619

@@ -1417,6 +1442,30 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error)
14171442
}
14181443
}
14191444

1445+
// Submit message positions to pending queue
1446+
if !b.streamer.UseEscapeHatch || b.streamer.shouldSubmitEspressoTransaction() {
1447+
for p := b.building.msgCount; p < msgCount; p += 1 {
1448+
msg, err := b.streamer.GetMessage(p)
1449+
if err != nil {
1450+
log.Error("error getting message from streamer", "error", err)
1451+
break
1452+
}
1453+
// We only submit the user transactions to hotshot.
1454+
if msg.Message.Header.Kind != arbostypes.L1MessageType_L2Message {
1455+
continue
1456+
}
1457+
kind := msg.Message.L2msg[0]
1458+
if kind != arbos.L2MessageKind_Batch && kind != arbos.L2MessageKind_SignedTx {
1459+
continue
1460+
}
1461+
err = b.submitEspressoTransactionPos(p)
1462+
if err != nil {
1463+
log.Error("error submitting position", "error", err, "pos", p)
1464+
break
1465+
}
1466+
}
1467+
}
1468+
14201469
for b.building.msgCount < msgCount {
14211470
msg, err := b.streamer.GetMessage(b.building.msgCount)
14221471
if err != nil {

Diff for: arbnode/schema.go

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var (
2121
espressoSubmittedHash []byte = []byte("_espressoSubmittedHash") // contains the hash of the last submitted txn
2222
espressoPendingTxnsPositions []byte = []byte("_espressoPendingTxnsPositions") // contains the index of the pending txns that need to be submitted to espresso
2323
espressoLastConfirmedPos []byte = []byte("_espressoLastConfirmedPos") // contains the position of the last confirmed message
24+
espressoSkipVerificationPos []byte = []byte("_espressoSkipVerificationPos") // contains the position of the latest message that should skip the validation due to hotshot liveness failure
2425
)
2526

2627
const currentDbSchemaVersion uint64 = 1

0 commit comments

Comments
 (0)