From dca69ce46e45fa08b0b8326f45817d36efbc937c Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:52:37 +0800 Subject: [PATCH 01/25] implement first steps for minimal recovery to permissionlessly produce batches --- rollup/cmd/permissionless_batches/app/app.go | 319 ++++++++++++++++++ rollup/cmd/permissionless_batches/main.go | 7 + rollup/go.mod | 4 +- rollup/go.sum | 4 + .../controller/watcher/chunk_proposer.go | 6 + .../internal/controller/watcher/l2_watcher.go | 4 +- rollup/internal/orm/batch.go | 50 +++ rollup/internal/orm/chunk.go | 39 +++ 8 files changed, 429 insertions(+), 4 deletions(-) create mode 100644 rollup/cmd/permissionless_batches/app/app.go create mode 100644 rollup/cmd/permissionless_batches/main.go diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go new file mode 100644 index 0000000000..4d315ac3ed --- /dev/null +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -0,0 +1,319 @@ +package app + +import ( + "context" + "fmt" + "os" + "os/signal" + + "github.com/prometheus/client_golang/prometheus" + "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/ethclient" + "github.com/scroll-tech/go-ethereum/log" + "github.com/scroll-tech/go-ethereum/rollup/l1" + "github.com/urfave/cli/v2" + "gorm.io/gorm" + + "scroll-tech/common/database" + "scroll-tech/common/observability" + "scroll-tech/common/utils" + "scroll-tech/common/version" + "scroll-tech/database/migrate" + "scroll-tech/rollup/internal/config" + "scroll-tech/rollup/internal/controller/watcher" +) + +var app *cli.App + +func init() { + // Set up rollup-relayer app info. + app = cli.NewApp() + app.Action = action + app.Name = "permissionless-batches" + app.Usage = "The Scroll Rollup Relayer for permissionless batch production" + app.Version = version.Version + app.Flags = append(app.Flags, utils.CommonFlags...) + app.Flags = append(app.Flags, utils.RollupRelayerFlags...) + app.Commands = []*cli.Command{} + app.Before = func(ctx *cli.Context) error { + return utils.LogSetup(ctx) + } +} + +func action(ctx *cli.Context) error { + // Load config file. + cfgFile := ctx.String(utils.ConfigFileFlag.Name) + cfg, err := config.NewConfig(cfgFile) + if err != nil { + log.Crit("failed to load config file", "config file", cfgFile, "error", err) + } + + subCtx, cancel := context.WithCancel(ctx.Context) + defer cancel() + + db, err := initDB(cfg) + if err != nil { + return fmt.Errorf("failed to init db: %w", err) + } + defer func() { + if err = database.CloseDB(db); err != nil { + log.Crit("failed to close db connection", "error", err) + } + }() + + registry := prometheus.DefaultRegisterer + observability.Server(ctx, db) + + // Init l2geth connection + l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) + if err != nil { + log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err) + } + + genesisPath := ctx.String(utils.Genesis.Name) + genesis, err := utils.ReadGenesis(genesisPath) + if err != nil { + log.Crit("failed to read genesis", "genesis file", genesisPath, "error", err) + } + + chunkProposer := watcher.NewChunkProposer(subCtx, cfg.L2Config.ChunkProposerConfig, genesis.Config, db, registry) + ///batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) + //bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) + + l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) + + // Finish start all rollup relayer functions. + log.Info("Start rollup-relayer successfully", "version", version.Version) + + fmt.Println(cfg.L1Config) + fmt.Println(cfg.L2Config) + fmt.Println(cfg.DBConfig) + + if err = restorePreviousState(cfg, db, l2watcher, chunkProposer); err != nil { + log.Crit("failed to recover relayer", "error", err) + } + + // TODO: fetch L2 blocks that will be used to propose the next chunks, batches and bundles. + // x. Get and insert the missing blocks from the last block in the batch to the latest L2 block. + //latestL2Block, err := l2Watcher.Client.BlockNumber(context.Background()) + //if err != nil { + // return fmt.Errorf("failed to get latest L2 block number: %w", err) + //} + + //err = l2Watcher.GetAndStoreBlocks(context.Background(), lastBlockInBatch, latestL2Block) + //if err != nil { + // return fmt.Errorf("failed to get and store blocks: %w", err) + //} + + // TODO: maybe start new goroutine for chunk and batch proposers like usual and stop them once max L2 blocks reached + + // Catch CTRL-C to ensure a graceful shutdown. + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + + // Wait until the interrupt signal is received from an OS signal. + <-interrupt + + return nil +} + +// Run rollup relayer cmd instance. +func Run() { + if err := app.Run(os.Args); err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func initDB(cfg *config.Config) (*gorm.DB, error) { + // init db connection + db, err := database.InitDB(cfg.DBConfig) + if err != nil { + log.Crit("failed to init db connection", "err", err) + } + + // make sure we are starting from a fresh DB + sqlDB, err := db.DB() + if err != nil { + return nil, fmt.Errorf("failed ") + } + + // reset and init DB + var v int64 + err = migrate.Rollback(sqlDB, &v) + if err != nil { + return nil, fmt.Errorf("failed to rollback db: %w", err) + } + + err = migrate.Migrate(sqlDB) + if err != nil { + return nil, fmt.Errorf("failed to migrate db: %w", err) + } + + return db, nil +} + +// restorePreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. +func restorePreviousState(cfg *config.Config, db *gorm.DB, l2Watcher *watcher.L2WatcherClient, chunkProposer *watcher.ChunkProposer) error { + // TODO: make these parameters + scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0") + l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763") + userl1BlockHeight := uint64(4141928) + userBatch := uint64(9705) + + l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) + if err != nil { + return fmt.Errorf("failed to connect to L1 client: %w", err) + } + reader, err := l1.NewReader(context.Background(), l1.Config{ + ScrollChainAddress: scrollChainAddress, + L1MessageQueueAddress: l1MessageQueueAddress, + }, l1Client) + if err != nil { + return fmt.Errorf("failed to create L1 reader: %w", err) + } + + // 1. Sanity check user input: Make sure that the user's L1 block height is not higher than the latest finalized block number. + latestFinalizedBlock, err := reader.GetLatestFinalizedBlockNumber() + if err != nil { + return fmt.Errorf("failed to get latest finalized block number: %w", err) + } + if userl1BlockHeight > latestFinalizedBlock { + return fmt.Errorf("user's L1 block height is higher than the latest finalized block number: %d > %d", userl1BlockHeight, latestFinalizedBlock) + } + + fmt.Println("latestFinalizedBlock", latestFinalizedBlock) + fmt.Println("userl1BlockHeight", userl1BlockHeight) + + // 2. Make sure that the specified batch is indeed finalized on the L1 rollup contract and is the latest finalized batch. + // --- + //events, err := reader.FetchRollupEventsInRange(userl1BlockHeight, latestFinalizedBlock) + //if err != nil { + // return fmt.Errorf("failed to fetch rollup events: %w", err) + //} + //var foundFinalizeEvent bool + //var latestFinalizedBatch uint64 + //var userCommitEvent *l1.CommitBatchEvent + // + //for _, event := range events { + // switch event.Type() { + // case l1.CommitEventType: + // if event.BatchIndex().Uint64() == userBatch { + // userCommitEvent = event.(*l1.CommitBatchEvent) + // } + // + // case l1.FinalizeEventType: + // if event.BatchIndex().Uint64() == userBatch { + // foundFinalizeEvent = true + // } + // if event.BatchIndex().Uint64() > latestFinalizedBatch { + // latestFinalizedBatch = event.BatchIndex().Uint64() + // } + // + // default: + // // ignore revert events + // } + //} + //if userCommitEvent == nil { + // return fmt.Errorf("commit event not found for batch %d", userBatch) + //} + //if !foundFinalizeEvent { + // return fmt.Errorf("finalize event not found for batch %d", userBatch) + //} + //if userBatch != latestFinalizedBatch { + // return fmt.Errorf("batch %d is not the latest finalized batch: %d", userBatch, latestFinalizedBatch) + //} + var foundFinalizeEvent bool + var latestFinalizedBatch uint64 + var userCommitEvent *l1.CommitBatchEvent + { + err = reader.FetchRollupEventsInRangeWithCallback(userl1BlockHeight, latestFinalizedBlock, func(event l1.RollupEvent) bool { + switch event.Type() { + case l1.CommitEventType: + if event.BatchIndex().Uint64() == userBatch { + userCommitEvent = event.(*l1.CommitBatchEvent) + } + + case l1.FinalizeEventType: + if event.BatchIndex().Uint64() == userBatch { + foundFinalizeEvent = true + } + if event.BatchIndex().Uint64() > latestFinalizedBatch { + latestFinalizedBatch = event.BatchIndex().Uint64() + } + + default: + // ignore revert events + } + + if foundFinalizeEvent && userCommitEvent != nil { + return false + } + + return true + }) + } + + // 3. Fetch the commit tx data for latest finalized batch. + args, err := reader.FetchCommitTxData(userCommitEvent) + if err != nil { + return fmt.Errorf("failed to fetch commit tx data: %w", err) + } + + codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + if err != nil { + return fmt.Errorf("failed to get codec: %w", err) + } + + daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + if err != nil { + return fmt.Errorf("failed to decode DA chunks: %w", err) + } + lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] + lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + + // 4. Get the L1 messages count after the latest finalized batch. + l1MessagesCount, err := reader.FinalizedL1MessageQueueIndex(latestFinalizedBlock) + if err != nil { + return fmt.Errorf("failed to get L1 messages count: %w", err) + } + + for i, chunk := range daChunksRawTxs { + fmt.Println("chunk", i) + for j, block := range chunk.Blocks { + fmt.Println("block", j) + fmt.Println("block.Number", block.Number()) + } + } + + // 5. Insert minimal state to DB. + if err = chunkProposer.ChunkORM().InsertChunkRaw(context.Background(), codec.Version(), lastChunk, l1MessagesCount); err != nil { + return fmt.Errorf("failed to insert chunk raw: %w", err) + } + + fmt.Println("l1MessagesCount", l1MessagesCount) + fmt.Println("lastBlockInBatch", lastBlockInBatch) + //fmt.Println("latestL2Block", latestL2Block) + + // TODO: + // - reconstruct latest finalized batch + // - reconstruct latest finalized chunk + // - try to chunkProposer.TryProposeChunk() and batchProposer.TryProposeBatch() + // - instead of proposing bundle, we need to call a special method to propose the bundle that contains only produced batch + + // next steps: chunk size of 1 matches -> now try to get the correct batch hash for the next batch (compare with DB) + // batch.Index = dbParentBatch.Index + 1 + // batch.ParentBatchHash = common.HexToHash(dbParentBatch.Hash) + // batch.TotalL1MessagePoppedBefore = firstUnbatchedChunk.TotalL1MessagesPoppedBefore + // insert this batch to DB -> refactor to be cleaner and based on latest da-codec + // -> come up with a way to test this deterministically + return nil +} + +//docker run --rm -it \ +// -e POSTGRES_HOST_AUTH_METHOD=trust \ +// -e POSTGRES_DB=scroll \ +// -v ${PWD}/db_data:/var/lib/postgresql/data \ +// -p 5432:5432 \ +// postgres diff --git a/rollup/cmd/permissionless_batches/main.go b/rollup/cmd/permissionless_batches/main.go new file mode 100644 index 0000000000..95e157492b --- /dev/null +++ b/rollup/cmd/permissionless_batches/main.go @@ -0,0 +1,7 @@ +package main + +import "scroll-tech/rollup/cmd/permissionless_batches/app" + +func main() { + app.Run() +} diff --git a/rollup/go.mod b/rollup/go.mod index b6ec0474d8..da9c58eec8 100644 --- a/rollup/go.mod +++ b/rollup/go.mod @@ -12,7 +12,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus/client_golang v1.16.0 github.com/scroll-tech/da-codec v0.1.2 - github.com/scroll-tech/go-ethereum v1.10.14-0.20241011150208-4742882675d8 + github.com/scroll-tech/go-ethereum v1.10.24-0.20241023044337-1b5a4f8cde50 github.com/smartystreets/goconvey v1.8.0 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 @@ -23,7 +23,7 @@ require ( require ( github.com/DataDog/zstd v1.4.5 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/VictoriaMetrics/fastcache v1.12.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/btcsuite/btcd v0.20.1-beta // indirect diff --git a/rollup/go.sum b/rollup/go.sum index 7027071b73..7798d59ea0 100644 --- a/rollup/go.sum +++ b/rollup/go.sum @@ -6,6 +6,7 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/agiledragon/gomonkey/v2 v2.12.0 h1:ek0dYu9K1rSV+TgkW5LvNNPRWyDZVIxGMCFI6Pz9o38= github.com/agiledragon/gomonkey/v2 v2.12.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= @@ -269,6 +270,8 @@ github.com/scroll-tech/da-codec v0.1.2 h1:QyJ+dQ4zWVVJwuqxNt4MiKyrymVc6rHe4YPtUR github.com/scroll-tech/da-codec v0.1.2/go.mod h1:odz1ck3umvYccCG03osaQBISAYGinZktZYbpk94fYRE= github.com/scroll-tech/go-ethereum v1.10.14-0.20241011150208-4742882675d8 h1:pEP6+ThQIgSRO5SILiO6iBpWnxAUjoRNBA9Nc6ooOS0= github.com/scroll-tech/go-ethereum v1.10.14-0.20241011150208-4742882675d8/go.mod h1:MBHX2RcAV9KLWblo9DSa/xyPYd1Wpwnt64JSDOy85po= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241023044337-1b5a4f8cde50 h1:Y61q84pOw6MCaZZB5tD6teYSyqdELsMCa+N72VOmIoo= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241023044337-1b5a4f8cde50/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= @@ -385,6 +388,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 99eaca9d44..819efc9e65 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -174,6 +174,10 @@ func (p *ChunkProposer) TryProposeChunk() { } } +func (p *ChunkProposer) ChunkORM() *orm.Chunk { + return p.chunkOrm +} + func (p *ChunkProposer) updateDBChunkInfo(chunk *encoding.Chunk, codecVersion encoding.CodecVersion, metrics *utils.ChunkMetrics) error { if chunk == nil { return nil @@ -246,6 +250,7 @@ func (p *ChunkProposer) updateDBChunkInfo(chunk *encoding.Chunk, codecVersion en func (p *ChunkProposer) proposeChunk() error { // unchunkedBlockHeight >= 1, assuming genesis batch with chunk 0, block 0 is committed. + // TODO: need latest chunk in DB unchunkedBlockHeight, err := p.chunkOrm.GetUnchunkedBlockHeight(p.ctx) if err != nil { return err @@ -254,6 +259,7 @@ func (p *ChunkProposer) proposeChunk() error { maxBlocksThisChunk := p.maxBlockNumPerChunk // select at most maxBlocksThisChunk blocks + // TODO: should be ok if I can get blocks into DB blocks, err := p.l2BlockOrm.GetL2BlocksGEHeight(p.ctx, unchunkedBlockHeight, int(maxBlocksThisChunk)) if err != nil { return err diff --git a/rollup/internal/controller/watcher/l2_watcher.go b/rollup/internal/controller/watcher/l2_watcher.go index 3a8283acd2..805b9bd710 100644 --- a/rollup/internal/controller/watcher/l2_watcher.go +++ b/rollup/internal/controller/watcher/l2_watcher.go @@ -77,7 +77,7 @@ func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) { to = blockHeight } - if err = w.getAndStoreBlocks(w.ctx, from, to); err != nil { + if err = w.GetAndStoreBlocks(w.ctx, from, to); err != nil { log.Error("fail to getAndStoreBlockTraces", "from", from, "to", to, "err", err) return } @@ -122,7 +122,7 @@ func txsToTxsData(txs gethTypes.Transactions) []*gethTypes.TransactionData { return txsData } -func (w *L2WatcherClient) getAndStoreBlocks(ctx context.Context, from, to uint64) error { +func (w *L2WatcherClient) GetAndStoreBlocks(ctx context.Context, from, to uint64) error { var blocks []*encoding.Block for number := from; number <= to; number++ { log.Debug("retrieving block", "height", number) diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index 3aa5157117..7ccc8c4208 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -324,6 +324,56 @@ func (o *Batch) InsertBatch(ctx context.Context, batch *encoding.Batch, codecVer return &newBatch, nil } +func (o *Batch) InsertBatchRaw(ctx context.Context, batch *encoding.DABatch) error { + newBatch := &Batch{ + db: nil, + Index: 0, + Hash: "", + DataHash: "", + StartChunkIndex: 0, + StartChunkHash: "", + EndChunkIndex: 0, + EndChunkHash: "", + StateRoot: "", + WithdrawRoot: "", + ParentBatchHash: "", + BatchHeader: nil, + CodecVersion: 0, + EnableCompress: false, + BlobBytes: nil, + ChunkProofsStatus: 0, + ProvingStatus: 0, + Proof: nil, + ProverAssignedAt: nil, + ProvedAt: nil, + ProofTimeSec: 0, + RollupStatus: 0, + CommitTxHash: "", + CommittedAt: nil, + FinalizeTxHash: "", + FinalizedAt: nil, + OracleStatus: 0, + OracleTxHash: "", + BlobDataProof: nil, + BlobSize: 0, + BundleHash: "", + TotalL1CommitGas: 0, + TotalL1CommitCalldataSize: 0, + CreatedAt: time.Time{}, + UpdatedAt: time.Time{}, + DeletedAt: gorm.DeletedAt{}, + } + + db := o.db.WithContext(ctx) + db = db.Model(&Batch{}) + + if err := db.Create(newBatch).Error; err != nil { + return fmt.Errorf("Batch.InsertBatchRaw error: %w", err) + } + return nil + +} + // UpdateL2GasOracleStatusAndOracleTxHash updates the L2 gas oracle status and transaction hash for a batch. func (o *Batch) UpdateL2GasOracleStatusAndOracleTxHash(ctx context.Context, hash string, status types.GasOracleStatus, txHash string) error { updateFields := make(map[string]interface{}) diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index 893290f757..413587ac36 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -7,6 +7,7 @@ import ( "time" "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/log" "gorm.io/gorm" @@ -254,6 +255,44 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer return &newChunk, nil } +func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) error { + numBlocks := len(chunk.Blocks) + emptyHash := common.Hash{}.Hex() + newChunk := Chunk{ + Index: 0, + Hash: emptyHash, + StartBlockNumber: chunk.Blocks[0].Number(), + StartBlockHash: emptyHash, + EndBlockNumber: chunk.Blocks[numBlocks-1].Number(), + EndBlockHash: emptyHash, + TotalL2TxGas: 0, + TotalL2TxNum: 0, + TotalL1CommitCalldataSize: 0, + TotalL1CommitGas: 0, + StartBlockTime: chunk.Blocks[0].Timestamp(), + TotalL1MessagesPoppedBefore: totalL1MessagePoppedBefore, + TotalL1MessagesPoppedInChunk: 0, + ParentChunkHash: emptyHash, + StateRoot: emptyHash, + ParentChunkStateRoot: emptyHash, + WithdrawRoot: emptyHash, + CodecVersion: int16(codecVersion), + EnableCompress: false, + ProvingStatus: int16(types.ProvingTaskVerified), + CrcMax: 0, + BlobSize: 0, + } + + db := o.db.WithContext(ctx) + db = db.Model(&Chunk{}) + + if err := db.Create(&newChunk).Error; err != nil { + return fmt.Errorf("Chunk.InsertChunk error: %w, chunk hash: %v", err, newChunk.Hash) + } + + return nil +} + // UpdateProvingStatus updates the proving status of a chunk. func (o *Chunk) UpdateProvingStatus(ctx context.Context, hash string, status types.ProvingStatus, dbTX ...*gorm.DB) error { updateFields := make(map[string]interface{}) From 496314fbb3b9d553089752c52c12415c21558bfc Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:40:18 +0800 Subject: [PATCH 02/25] add config for recovery mode --- rollup/internal/config/config.go | 10 ++++++---- rollup/internal/config/recovery.go | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/rollup/internal/config/config.go b/rollup/internal/config/config.go index 725d1e492d..93fd7e88e4 100644 --- a/rollup/internal/config/config.go +++ b/rollup/internal/config/config.go @@ -3,9 +3,10 @@ package config import ( "fmt" "reflect" - "scroll-tech/common/database" "strings" + "scroll-tech/common/database" + "github.com/mitchellh/mapstructure" "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/rpc" @@ -14,9 +15,10 @@ import ( // Config load configuration items. type Config struct { - L1Config *L1Config `json:"l1_config"` - L2Config *L2Config `json:"l2_config"` - DBConfig *database.Config `json:"db_config"` + L1Config *L1Config `json:"l1_config"` + L2Config *L2Config `json:"l2_config"` + DBConfig *database.Config `json:"db_config"` + RecoveryConfig *RecoveryConfig `json:"recovery_config"` } // NewConfig returns a new instance of Config. diff --git a/rollup/internal/config/recovery.go b/rollup/internal/config/recovery.go index d912156bec..4ed9c0a850 100644 --- a/rollup/internal/config/recovery.go +++ b/rollup/internal/config/recovery.go @@ -1 +1,11 @@ package config + +// L1Config loads l1eth configuration items. +type RecoveryConfig struct { + Enable bool `json:"enable"` + + LatestFinalizedBatch uint64 `json:"latest_finalized_batch"` + L1BlockHeight uint64 `json:"l1_block_height"` + + L2BlockHeightLimit uint64 `json:"l2_block_height_limit"` +} From c12d3809de6e4b0fc6300874df948d28db832b06 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:41:08 +0800 Subject: [PATCH 03/25] structure code and implement restoreMinimalPreviousState and fetchL2Blocks --- rollup/cmd/permissionless_batches/app/app.go | 241 ++++++++---------- rollup/go.mod | 2 +- rollup/go.sum | 2 + .../controller/watcher/batch_proposer.go | 4 + rollup/internal/orm/batch.go | 35 ++- rollup/internal/orm/chunk.go | 23 +- 6 files changed, 149 insertions(+), 158 deletions(-) diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index 4d315ac3ed..9b5a3f15e8 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -9,6 +9,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/core" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/rollup/l1" @@ -22,6 +23,7 @@ import ( "scroll-tech/database/migrate" "scroll-tech/rollup/internal/config" "scroll-tech/rollup/internal/controller/watcher" + "scroll-tech/rollup/internal/orm" ) var app *cli.App @@ -65,12 +67,6 @@ func action(ctx *cli.Context) error { registry := prometheus.DefaultRegisterer observability.Server(ctx, db) - // Init l2geth connection - l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) - if err != nil { - log.Crit("failed to connect l2 geth", "config file", cfgFile, "error", err) - } - genesisPath := ctx.String(utils.Genesis.Name) genesis, err := utils.ReadGenesis(genesisPath) if err != nil { @@ -78,33 +74,30 @@ func action(ctx *cli.Context) error { } chunkProposer := watcher.NewChunkProposer(subCtx, cfg.L2Config.ChunkProposerConfig, genesis.Config, db, registry) - ///batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) + batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) //bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) - l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) - // Finish start all rollup relayer functions. log.Info("Start rollup-relayer successfully", "version", version.Version) fmt.Println(cfg.L1Config) fmt.Println(cfg.L2Config) fmt.Println(cfg.DBConfig) + fmt.Println(cfg.RecoveryConfig) - if err = restorePreviousState(cfg, db, l2watcher, chunkProposer); err != nil { - log.Crit("failed to recover relayer", "error", err) + chunk, batch, err := restoreMinimalPreviousState(cfg, chunkProposer, batchProposer) + if err != nil { + return fmt.Errorf("failed to restore minimal previous state: %w", err) } - // TODO: fetch L2 blocks that will be used to propose the next chunks, batches and bundles. - // x. Get and insert the missing blocks from the last block in the batch to the latest L2 block. - //latestL2Block, err := l2Watcher.Client.BlockNumber(context.Background()) - //if err != nil { - // return fmt.Errorf("failed to get latest L2 block number: %w", err) - //} + // Fetch and insert the missing blocks from the last block in the batch to the latest L2 block. + fromBlock := chunk.EndBlockNumber + 1 + toBlock, err := fetchL2Blocks(subCtx, cfg, genesis, db, registry, fromBlock, cfg.RecoveryConfig.L2BlockHeightLimit) + if err != nil { + return fmt.Errorf("failed to fetch L2 blocks: %w", err) + } - //err = l2Watcher.GetAndStoreBlocks(context.Background(), lastBlockInBatch, latestL2Block) - //if err != nil { - // return fmt.Errorf("failed to get and store blocks: %w", err) - //} + fmt.Println(chunk.Index, batch.Index, fromBlock, toBlock) // TODO: maybe start new goroutine for chunk and batch proposers like usual and stop them once max L2 blocks reached @@ -154,161 +147,145 @@ func initDB(cfg *config.Config) (*gorm.DB, error) { return db, nil } -// restorePreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. -func restorePreviousState(cfg *config.Config, db *gorm.DB, l2Watcher *watcher.L2WatcherClient, chunkProposer *watcher.ChunkProposer) error { - // TODO: make these parameters +func fetchL2Blocks(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, registry prometheus.Registerer, fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) { + if l2BlockHeightLimit > 0 && fromBlock > l2BlockHeightLimit { + return 0, fmt.Errorf("fromBlock (latest finalized L2 block) is higher than specified L2BlockHeightLimit: %d > %d", fromBlock, l2BlockHeightLimit) + } + + log.Info("Fetching L2 blocks with", "fromBlock", fromBlock, "l2BlockHeightLimit", l2BlockHeightLimit) + + // Init l2geth connection + l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) + if err != nil { + return 0, fmt.Errorf("failed to connect to L2geth at RPC=%s: %w", cfg.L2Config.Endpoint, err) + } + + l2Watcher := watcher.NewL2WatcherClient(ctx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) + + // Fetch and insert the missing blocks from the last block in the batch to the latest L2 block. + latestL2Block, err := l2Watcher.Client.BlockNumber(context.Background()) + if err != nil { + return 0, fmt.Errorf("failed to get latest L2 block number: %w", err) + } + + log.Info("Latest L2 block number", "latest L2 block", latestL2Block) + + if l2BlockHeightLimit > latestL2Block { + return 0, fmt.Errorf("l2BlockHeightLimit is higher than the latest L2 block number, not all blocks are available in L2geth: %d > %d", l2BlockHeightLimit, latestL2Block) + } + + toBlock := latestL2Block + if l2BlockHeightLimit > 0 { + toBlock = l2BlockHeightLimit + } + + err = l2Watcher.GetAndStoreBlocks(context.Background(), fromBlock, toBlock) + if err != nil { + return 0, fmt.Errorf("failed to get and store blocks: %w", err) + } + + log.Info("Fetched L2 blocks from", "fromBlock", fromBlock, "toBlock", toBlock) + + return toBlock, nil +} + +// restoreMinimalPreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. +func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer) (*orm.Chunk, *orm.Batch, error) { + log.Info("Restoring previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) + + // TODO: make these parameters -> part of genesis config? scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0") l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763") - userl1BlockHeight := uint64(4141928) - userBatch := uint64(9705) l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) if err != nil { - return fmt.Errorf("failed to connect to L1 client: %w", err) + return nil, nil, fmt.Errorf("failed to connect to L1 client: %w", err) } reader, err := l1.NewReader(context.Background(), l1.Config{ ScrollChainAddress: scrollChainAddress, L1MessageQueueAddress: l1MessageQueueAddress, }, l1Client) if err != nil { - return fmt.Errorf("failed to create L1 reader: %w", err) + return nil, nil, fmt.Errorf("failed to create L1 reader: %w", err) } // 1. Sanity check user input: Make sure that the user's L1 block height is not higher than the latest finalized block number. - latestFinalizedBlock, err := reader.GetLatestFinalizedBlockNumber() + latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() if err != nil { - return fmt.Errorf("failed to get latest finalized block number: %w", err) + return nil, nil, fmt.Errorf("failed to get latest finalized L1 block number: %w", err) } - if userl1BlockHeight > latestFinalizedBlock { - return fmt.Errorf("user's L1 block height is higher than the latest finalized block number: %d > %d", userl1BlockHeight, latestFinalizedBlock) + if cfg.RecoveryConfig.L1BlockHeight > latestFinalizedL1Block { + return nil, nil, fmt.Errorf("specified L1 block height is higher than the latest finalized block number: %d > %d", cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block) } - fmt.Println("latestFinalizedBlock", latestFinalizedBlock) - fmt.Println("userl1BlockHeight", userl1BlockHeight) + log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) // 2. Make sure that the specified batch is indeed finalized on the L1 rollup contract and is the latest finalized batch. - // --- - //events, err := reader.FetchRollupEventsInRange(userl1BlockHeight, latestFinalizedBlock) - //if err != nil { - // return fmt.Errorf("failed to fetch rollup events: %w", err) - //} - //var foundFinalizeEvent bool - //var latestFinalizedBatch uint64 - //var userCommitEvent *l1.CommitBatchEvent - // - //for _, event := range events { - // switch event.Type() { - // case l1.CommitEventType: - // if event.BatchIndex().Uint64() == userBatch { - // userCommitEvent = event.(*l1.CommitBatchEvent) - // } - // - // case l1.FinalizeEventType: - // if event.BatchIndex().Uint64() == userBatch { - // foundFinalizeEvent = true - // } - // if event.BatchIndex().Uint64() > latestFinalizedBatch { - // latestFinalizedBatch = event.BatchIndex().Uint64() - // } - // - // default: - // // ignore revert events - // } - //} - //if userCommitEvent == nil { - // return fmt.Errorf("commit event not found for batch %d", userBatch) + // TODO: enable check + //latestFinalizedBatch, err := reader.LatestFinalizedBatch(latestFinalizedL1Block) + //if cfg.RecoveryConfig.LatestFinalizedBatch != latestFinalizedBatch { + // return nil, nil, fmt.Errorf("batch %d is not the latest finalized batch: %d", cfg.RecoveryConfig.LatestFinalizedBatch, latestFinalizedBatch) //} - //if !foundFinalizeEvent { - // return fmt.Errorf("finalize event not found for batch %d", userBatch) - //} - //if userBatch != latestFinalizedBatch { - // return fmt.Errorf("batch %d is not the latest finalized batch: %d", userBatch, latestFinalizedBatch) - //} - var foundFinalizeEvent bool - var latestFinalizedBatch uint64 - var userCommitEvent *l1.CommitBatchEvent - { - err = reader.FetchRollupEventsInRangeWithCallback(userl1BlockHeight, latestFinalizedBlock, func(event l1.RollupEvent) bool { - switch event.Type() { - case l1.CommitEventType: - if event.BatchIndex().Uint64() == userBatch { - userCommitEvent = event.(*l1.CommitBatchEvent) - } - - case l1.FinalizeEventType: - if event.BatchIndex().Uint64() == userBatch { - foundFinalizeEvent = true - } - if event.BatchIndex().Uint64() > latestFinalizedBatch { - latestFinalizedBatch = event.BatchIndex().Uint64() - } - - default: - // ignore revert events - } - - if foundFinalizeEvent && userCommitEvent != nil { - return false - } - - return true - }) + + var batchCommitEvent *l1.CommitBatchEvent + err = reader.FetchRollupEventsInRangeWithCallback(cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block, func(event l1.RollupEvent) bool { + if event.Type() == l1.CommitEventType && event.BatchIndex().Uint64() == cfg.RecoveryConfig.LatestFinalizedBatch { + batchCommitEvent = event.(*l1.CommitBatchEvent) + return false + } + + return true + }) + if batchCommitEvent == nil { + return nil, nil, fmt.Errorf("commit event not found for batch %d", cfg.RecoveryConfig.LatestFinalizedBatch) } - // 3. Fetch the commit tx data for latest finalized batch. - args, err := reader.FetchCommitTxData(userCommitEvent) + log.Info("Found commit event for batch", "batch", batchCommitEvent.BatchIndex(), "hash", batchCommitEvent.BatchHash(), "L1 block height", batchCommitEvent.BlockNumber(), "L1 tx hash", batchCommitEvent.TxHash()) + + // 3. Fetch commit tx data for latest finalized batch. + args, err := reader.FetchCommitTxData(batchCommitEvent) if err != nil { - return fmt.Errorf("failed to fetch commit tx data: %w", err) + return nil, nil, fmt.Errorf("failed to fetch commit tx data: %w", err) } codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) if err != nil { - return fmt.Errorf("failed to get codec: %w", err) + return nil, nil, fmt.Errorf("failed to get codec: %w", err) } daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) if err != nil { - return fmt.Errorf("failed to decode DA chunks: %w", err) + return nil, nil, fmt.Errorf("failed to decode DA chunks: %w", err) } lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + log.Info("Last L2 block in batch", "batch", batchCommitEvent.BatchIndex(), "L2 block", lastBlockInBatch) + // 4. Get the L1 messages count after the latest finalized batch. - l1MessagesCount, err := reader.FinalizedL1MessageQueueIndex(latestFinalizedBlock) + l1MessagesCount, err := reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) if err != nil { - return fmt.Errorf("failed to get L1 messages count: %w", err) + return nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) } - for i, chunk := range daChunksRawTxs { - fmt.Println("chunk", i) - for j, block := range chunk.Blocks { - fmt.Println("block", j) - fmt.Println("block.Number", block.Number()) - } - } + log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) // 5. Insert minimal state to DB. - if err = chunkProposer.ChunkORM().InsertChunkRaw(context.Background(), codec.Version(), lastChunk, l1MessagesCount); err != nil { - return fmt.Errorf("failed to insert chunk raw: %w", err) + chunk, err := chunkProposer.ChunkORM().InsertChunkRaw(context.Background(), codec.Version(), lastChunk, l1MessagesCount) + if err != nil { + return nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) } - fmt.Println("l1MessagesCount", l1MessagesCount) - fmt.Println("lastBlockInBatch", lastBlockInBatch) - //fmt.Println("latestL2Block", latestL2Block) - - // TODO: - // - reconstruct latest finalized batch - // - reconstruct latest finalized chunk - // - try to chunkProposer.TryProposeChunk() and batchProposer.TryProposeBatch() - // - instead of proposing bundle, we need to call a special method to propose the bundle that contains only produced batch - - // next steps: chunk size of 1 matches -> now try to get the correct batch hash for the next batch (compare with DB) - // batch.Index = dbParentBatch.Index + 1 - // batch.ParentBatchHash = common.HexToHash(dbParentBatch.Hash) - // batch.TotalL1MessagePoppedBefore = firstUnbatchedChunk.TotalL1MessagesPoppedBefore - // insert this batch to DB -> refactor to be cleaner and based on latest da-codec - // -> come up with a way to test this deterministically - return nil + log.Info("Inserted last finalized chunk to DB", "chunk", chunk.Index, "hash", chunk.Hash, "StartBlockNumber", chunk.StartBlockNumber, "EndBlockNumber", chunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", chunk.TotalL1MessagesPoppedBefore) + + batch, err := batchProposer.BatchORM().InsertBatchRaw(context.Background(), batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) + if err != nil { + return nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) + } + + log.Info("Inserted last finalized batch to DB", "batch", batch.Index, "hash", batch.Hash) + + return chunk, batch, nil } //docker run --rm -it \ diff --git a/rollup/go.mod b/rollup/go.mod index 757c044828..b48023d85c 100644 --- a/rollup/go.mod +++ b/rollup/go.mod @@ -12,7 +12,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus/client_golang v1.16.0 github.com/scroll-tech/da-codec v0.1.2 - github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d + github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d github.com/smartystreets/goconvey v1.8.0 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 diff --git a/rollup/go.sum b/rollup/go.sum index 6702af8578..937aa61c61 100644 --- a/rollup/go.sum +++ b/rollup/go.sum @@ -269,6 +269,8 @@ github.com/scroll-tech/da-codec v0.1.2 h1:QyJ+dQ4zWVVJwuqxNt4MiKyrymVc6rHe4YPtUR github.com/scroll-tech/da-codec v0.1.2/go.mod h1:odz1ck3umvYccCG03osaQBISAYGinZktZYbpk94fYRE= github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d h1:vuv7fGKEDtoeetI6RkKt8RAByJsYZBWk9Vo6gShv65c= github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d h1:ZxRzFWs1VvAGqkeUyjgkEkUHyWlGUHXibqCpLr81KZI= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index ec25c8f247..e565d88f31 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -149,6 +149,10 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, chai return p } +func (p *BatchProposer) BatchORM() *orm.Batch { + return p.batchOrm +} + // TryProposeBatch tries to propose a new batches. func (p *BatchProposer) TryProposeBatch() { p.batchProposerCircleTotal.Inc() diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index 6b812f67bc..4b5c9f904e 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -5,9 +5,11 @@ import ( "encoding/json" "errors" "fmt" + "math/big" "time" "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/log" "gorm.io/gorm" @@ -324,34 +326,34 @@ func (o *Batch) InsertBatch(ctx context.Context, batch *encoding.Batch, codecVer return &newBatch, nil } -func (o *Batch) InsertBatchRaw(ctx context.Context, batch *encoding.DABatch) error { +func (o *Batch) InsertBatchRaw(ctx context.Context, batchIndex *big.Int, batchHash common.Hash, codecVersion encoding.CodecVersion, chunk *Chunk) (*Batch, error) { + now := time.Now() newBatch := &Batch{ - db: nil, - Index: 0, - Hash: "", + Index: batchIndex.Uint64(), + Hash: batchHash.Hex(), DataHash: "", - StartChunkIndex: 0, - StartChunkHash: "", - EndChunkIndex: 0, - EndChunkHash: "", + StartChunkIndex: chunk.Index, + StartChunkHash: chunk.Hash, + EndChunkIndex: chunk.Index, + EndChunkHash: chunk.Hash, StateRoot: "", WithdrawRoot: "", ParentBatchHash: "", - BatchHeader: nil, - CodecVersion: 0, + BatchHeader: []byte{1, 2, 3}, + CodecVersion: int16(codecVersion), EnableCompress: false, BlobBytes: nil, ChunkProofsStatus: 0, - ProvingStatus: 0, + ProvingStatus: int16(types.ProvingTaskVerified), Proof: nil, ProverAssignedAt: nil, - ProvedAt: nil, + ProvedAt: &now, ProofTimeSec: 0, RollupStatus: 0, CommitTxHash: "", CommittedAt: nil, FinalizeTxHash: "", - FinalizedAt: nil, + FinalizedAt: &now, OracleStatus: 0, OracleTxHash: "", BlobDataProof: nil, @@ -359,19 +361,16 @@ func (o *Batch) InsertBatchRaw(ctx context.Context, batch *encoding.DABatch) err BundleHash: "", TotalL1CommitGas: 0, TotalL1CommitCalldataSize: 0, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - DeletedAt: gorm.DeletedAt{}, } db := o.db.WithContext(ctx) db = db.Model(&Batch{}) if err := db.Create(newBatch).Error; err != nil { - return fmt.Errorf("Batch.InsertBatchRaw error: %w", err) + return nil, fmt.Errorf("Batch.InsertBatchRaw error: %w", err) } - return nil + return newBatch, nil } // UpdateL2GasOracleStatusAndOracleTxHash updates the L2 gas oracle status and transaction hash for a batch. diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index 413587ac36..b13e7e2608 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -8,6 +8,7 @@ import ( "github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/crypto" "github.com/scroll-tech/go-ethereum/log" "gorm.io/gorm" @@ -255,12 +256,20 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer return &newChunk, nil } -func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) error { +func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) (*Chunk, error) { + // Create some unique identifier. It is not really used for anything except in DB. + var chunkBytes []byte + for _, block := range chunk.Blocks { + blockBytes := block.Encode() + chunkBytes = append(chunkBytes, blockBytes...) + } + hash := crypto.Keccak256Hash(chunkBytes) + numBlocks := len(chunk.Blocks) emptyHash := common.Hash{}.Hex() - newChunk := Chunk{ - Index: 0, - Hash: emptyHash, + newChunk := &Chunk{ + Index: 1337, + Hash: hash.Hex(), StartBlockNumber: chunk.Blocks[0].Number(), StartBlockHash: emptyHash, EndBlockNumber: chunk.Blocks[numBlocks-1].Number(), @@ -286,11 +295,11 @@ func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecV db := o.db.WithContext(ctx) db = db.Model(&Chunk{}) - if err := db.Create(&newChunk).Error; err != nil { - return fmt.Errorf("Chunk.InsertChunk error: %w, chunk hash: %v", err, newChunk.Hash) + if err := db.Create(newChunk).Error; err != nil { + return nil, fmt.Errorf("Chunk.InsertChunk error: %w, chunk hash: %v", err, newChunk.Hash) } - return nil + return newChunk, nil } // UpdateProvingStatus updates the proving status of a chunk. From c329959c8d43fc69a1ff2eccbaab988aac5495e0 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:36:39 +0800 Subject: [PATCH 04/25] produce chunks from specified L2 blocks and batch from chunks --- rollup/cmd/permissionless_batches/app/app.go | 55 ++++++++++++++++--- .../controller/watcher/chunk_proposer.go | 6 +- rollup/internal/orm/chunk.go | 9 +-- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index 9b5a3f15e8..983248a72a 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -77,29 +77,66 @@ func action(ctx *cli.Context) error { batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) //bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) - // Finish start all rollup relayer functions. - log.Info("Start rollup-relayer successfully", "version", version.Version) - fmt.Println(cfg.L1Config) fmt.Println(cfg.L2Config) fmt.Println(cfg.DBConfig) fmt.Println(cfg.RecoveryConfig) - chunk, batch, err := restoreMinimalPreviousState(cfg, chunkProposer, batchProposer) + // Restore minimal previous state required to be able to create new chunks, batches and bundles. + latestFinalizedChunk, latestFinalizedBatch, err := restoreMinimalPreviousState(cfg, chunkProposer, batchProposer) if err != nil { return fmt.Errorf("failed to restore minimal previous state: %w", err) } - // Fetch and insert the missing blocks from the last block in the batch to the latest L2 block. - fromBlock := chunk.EndBlockNumber + 1 + // Fetch and insert the missing blocks from the last block in the latestFinalizedBatch to the latest L2 block. + fromBlock := latestFinalizedChunk.EndBlockNumber + 1 toBlock, err := fetchL2Blocks(subCtx, cfg, genesis, db, registry, fromBlock, cfg.RecoveryConfig.L2BlockHeightLimit) if err != nil { return fmt.Errorf("failed to fetch L2 blocks: %w", err) } - fmt.Println(chunk.Index, batch.Index, fromBlock, toBlock) + fmt.Println(latestFinalizedChunk.Index, latestFinalizedBatch.Index, fromBlock, toBlock) + + // Create chunks for L2 blocks. + log.Info("Creating chunks for L2 blocks", "from", fromBlock, "to", toBlock) + + var latestChunk *orm.Chunk + var count int + for { + if err = chunkProposer.ProposeChunk(); err != nil { + return fmt.Errorf("failed to propose chunk: %w", err) + } + count++ + + latestChunk, err = chunkProposer.ChunkORM().GetLatestChunk(subCtx) + if err != nil { + return fmt.Errorf("failed to get latest latestFinalizedChunk: %w", err) + } + + log.Info("Chunk created", "index", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) + + // We have created chunks for all available L2 blocks. + if latestChunk.EndBlockNumber >= toBlock { + break + } + } + + log.Info("Chunks created", "count", count, "latest latestFinalizedChunk", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) + + // Create batch for the created chunks. We only allow 1 batch it needs to be submitted (and finalized) with a proof in a single step. + log.Info("Creating batch for chunks", "from", latestFinalizedChunk.Index+1, "to", latestChunk.Index) + + batchProposer.TryProposeBatch() + latestBatch, err := batchProposer.BatchORM().GetLatestBatch(subCtx) + if err != nil { + return fmt.Errorf("failed to get latest latestFinalizedBatch: %w", err) + } + + if latestBatch.EndChunkIndex != latestChunk.Index { + return fmt.Errorf("latest chunk in produced batch %d != %d, too many L2 blocks - specify less L2 blocks and retry again", latestBatch.EndChunkIndex, latestChunk.Index) + } - // TODO: maybe start new goroutine for chunk and batch proposers like usual and stop them once max L2 blocks reached + log.Info("Batch created", "index", latestBatch.Index, "hash", latestBatch.Hash, "StartChunkIndex", latestBatch.StartChunkIndex, "EndChunkIndex", latestBatch.EndChunkIndex) // Catch CTRL-C to ensure a graceful shutdown. interrupt := make(chan os.Signal, 1) @@ -267,6 +304,8 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun if err != nil { return nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) } + // TODO: remove this. only for testing + l1MessagesCount = 220853 log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 819efc9e65..03cd3c25fc 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -167,7 +167,7 @@ func NewChunkProposer(ctx context.Context, cfg *config.ChunkProposerConfig, chai // TryProposeChunk tries to propose a new chunk. func (p *ChunkProposer) TryProposeChunk() { p.chunkProposerCircleTotal.Inc() - if err := p.proposeChunk(); err != nil { + if err := p.ProposeChunk(); err != nil { p.proposeChunkFailureTotal.Inc() log.Error("propose new chunk failed", "err", err) return @@ -248,9 +248,8 @@ func (p *ChunkProposer) updateDBChunkInfo(chunk *encoding.Chunk, codecVersion en return nil } -func (p *ChunkProposer) proposeChunk() error { +func (p *ChunkProposer) ProposeChunk() error { // unchunkedBlockHeight >= 1, assuming genesis batch with chunk 0, block 0 is committed. - // TODO: need latest chunk in DB unchunkedBlockHeight, err := p.chunkOrm.GetUnchunkedBlockHeight(p.ctx) if err != nil { return err @@ -259,7 +258,6 @@ func (p *ChunkProposer) proposeChunk() error { maxBlocksThisChunk := p.maxBlockNumPerChunk // select at most maxBlocksThisChunk blocks - // TODO: should be ok if I can get blocks into DB blocks, err := p.l2BlockOrm.GetL2BlocksGEHeight(p.ctx, unchunkedBlockHeight, int(maxBlocksThisChunk)) if err != nil { return err diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index b13e7e2608..e24e7a35b0 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -98,8 +98,8 @@ func (o *Chunk) GetChunksInRange(ctx context.Context, startIndex uint64, endInde return chunks, nil } -// getLatestChunk retrieves the latest chunk from the database. -func (o *Chunk) getLatestChunk(ctx context.Context) (*Chunk, error) { +// GetLatestChunk retrieves the latest chunk from the database. +func (o *Chunk) GetLatestChunk(ctx context.Context) (*Chunk, error) { db := o.db.WithContext(ctx) db = db.Model(&Chunk{}) db = db.Order("index desc") @@ -117,7 +117,7 @@ func (o *Chunk) getLatestChunk(ctx context.Context) (*Chunk, error) { // GetUnchunkedBlockHeight retrieves the first unchunked block number. func (o *Chunk) GetUnchunkedBlockHeight(ctx context.Context) (uint64, error) { // Get the latest chunk - latestChunk, err := o.getLatestChunk(ctx) + latestChunk, err := o.GetLatestChunk(ctx) if err != nil { return 0, fmt.Errorf("Chunk.GetUnchunkedBlockHeight error: %w", err) } @@ -188,7 +188,7 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer var totalL1MessagePoppedBefore uint64 var parentChunkHash string var parentChunkStateRoot string - parentChunk, err := o.getLatestChunk(ctx) + parentChunk, err := o.GetLatestChunk(ctx) if err != nil { log.Error("failed to get latest chunk", "err", err) return nil, fmt.Errorf("Chunk.InsertChunk error: %w", err) @@ -204,6 +204,7 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer parentChunkStateRoot = parentChunk.StateRoot } + fmt.Println("insertChunk", totalL1MessagePoppedBefore, chunkIndex, parentChunkHash) chunkHash, err := utils.GetChunkHash(chunk, totalL1MessagePoppedBefore, codecVersion) if err != nil { log.Error("failed to get chunk hash", "err", err) From 71f240b87cc8323ac3db37fd6041be5c92243277 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:51:53 +0800 Subject: [PATCH 05/25] start implementation of restoring full previous state for relayer --- rollup/cmd/rollup_relayer/app/app.go | 181 ++++++++++++++++++++++++++- 1 file changed, 180 insertions(+), 1 deletion(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 939d4b7798..c238cf917d 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -8,15 +8,17 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" + "github.com/scroll-tech/go-ethereum/rollup/l1" "github.com/urfave/cli/v2" "scroll-tech/common/database" "scroll-tech/common/observability" "scroll-tech/common/utils" "scroll-tech/common/version" - "scroll-tech/rollup/internal/config" "scroll-tech/rollup/internal/controller/relayer" "scroll-tech/rollup/internal/controller/watcher" @@ -90,6 +92,16 @@ func action(ctx *cli.Context) error { l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) + if cfg.RecoveryConfig.Enable { + log.Info("Starting rollup-relayer in recovery mode", "version", version.Version) + + if err = restoreFullPreviousState(cfg, chunkProposer, batchProposer); err != nil { + log.Crit("failed to restore full previous state", "error", err) + } + + return nil + } + // Watcher loop to fetch missing blocks go utils.LoopWithContext(subCtx, 2*time.Second, func(ctx context.Context) { number, loopErr := butils.GetLatestConfirmedBlockNumber(ctx, l2client, cfg.L2Config.Confirmations) @@ -132,3 +144,170 @@ func Run() { os.Exit(1) } } + +func restoreFullPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer) error { + log.Info("Restoring full previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) + + // DB state should be clean: the latest batch in the DB should be finalized on L1. This function will + // restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1. + + // 1. Get latest finalized batch stored in DB + // 2. Get latest finalized L1 block + // 3. Get latest finalized batch from contract (at latest finalized L1 block) + // 4. Get batches one by one from stored in DB to latest finalized batch + // - reproduce chunks / batches + + // 1. Get latest finalized batch stored in DB + latestDBBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) + fmt.Println("latestDBBatch", latestDBBatch) + + // TODO: + // 1. what if it is a fresh start? -> latest batch is nil + //latestDBBatch.CommitTxHash + + log.Info("Latest finalized batch in DB", "batch", latestDBBatch.Index, "hash", latestDBBatch.Hash) + + // TODO: make these parameters -> part of genesis config? + scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0") + l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763") + + l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) + if err != nil { + return fmt.Errorf("failed to connect to L1 client: %w", err) + } + reader, err := l1.NewReader(context.Background(), l1.Config{ + ScrollChainAddress: scrollChainAddress, + L1MessageQueueAddress: l1MessageQueueAddress, + }, l1Client) + if err != nil { + return fmt.Errorf("failed to create L1 reader: %w", err) + } + + // 2. Get latest finalized L1 block + latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() + if err != nil { + return fmt.Errorf("failed to get latest finalized L1 block number: %w", err) + } + + log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) + + // 3. Get latest finalized batch from contract (at latest finalized L1 block) + latestFinalizedBatch, err := reader.LatestFinalizedBatch(latestFinalizedL1Block) + if err != nil { + return fmt.Errorf("failed to get latest finalized batch: %w", err) + } + + log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatch, "at latest finalized L1 block", latestFinalizedL1Block) + + // 4. Get batches one by one from stored in DB to latest finalized batch. + // TODO: replace with this after testing: common.HexToHash(latestDBBatch.CommitTxHash) + hash := common.HexToHash("0x7c5ed6c542cbd5a2e59a3e9c35df49f16ff99d8dc01830f14c61d4b97c4f70f8") + receipt, err := l1Client.TransactionReceipt(context.Background(), hash) + if err != nil { + return fmt.Errorf("failed to get transaction receipt of latest DB batch finalization transaction: %w", err) + } + fromBlock := receipt.BlockNumber.Uint64() + + log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatch) + + batchEventsHeap := common.NewHeap[*batchEvents]() + commitEvents := common.NewShrinkingMap[uint64, *l1.CommitBatchEvent](1000) + var innerErr error + count := 0 + err = reader.FetchRollupEventsInRangeWithCallback(fromBlock, latestFinalizedL1Block, func(event l1.RollupEvent) bool { + // We're only interested in batches that are newer than the latest finalized batch in the DB. + if event.BatchIndex().Uint64() <= latestDBBatch.Index { + return true + } + + switch event.Type() { + case l1.CommitEventType: + commitEvent := event.(*l1.CommitBatchEvent) + commitEvents.Set(commitEvent.BatchIndex().Uint64(), commitEvent) + + case l1.FinalizeEventType: + // TODO: this needs to be the same as in d + finalizeEvent := event.(*l1.FinalizeBatchEvent) + commitEvent, exists := commitEvents.Get(finalizeEvent.BatchIndex().Uint64()) + if !exists { + innerErr = fmt.Errorf("commit event not found for finalize event %d", finalizeEvent.BatchIndex().Uint64()) + return false + } + + batchEventsHeap.Push(newBatchEvents(commitEvent, finalizeEvent)) + + // Stop fetching rollup events if we reached the latest finalized batch. + if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatch { + return false + } + + if count >= 100 { + return false + } + count++ + + case l1.RevertEventType: + // We ignore reverted batches. + commitEvents.Delete(event.BatchIndex().Uint64()) + } + + return true + }) + if innerErr != nil { + return fmt.Errorf("failed to fetch rollup events (inner): %w", innerErr) + } + if err != nil { + return fmt.Errorf("failed to fetch rollup events: %w", err) + } + + // 5. Process all finalized batches: fetch L2 blocks and reproduce chunks and batches. + for batchEventsHeap.Len() > 0 { + nextBatch := batchEventsHeap.Pop().Value() + + // 5.1. Fetch commit tx data for batch (via commit event). + args, err := reader.FetchCommitTxData(nextBatch.commit) + if err != nil { + return fmt.Errorf("failed to fetch commit tx data: %w", err) + } + + codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + if err != nil { + return fmt.Errorf("failed to get codec: %w", err) + } + + daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + if err != nil { + return fmt.Errorf("failed to decode DA chunks: %w", err) + } + lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] + lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + + log.Info("Last L2 block in batch", "batch", nextBatch.commit.BatchIndex(), "L2 block", lastBlockInBatch) + + // 5.2. Fetch L2 blocks for each chunk. + // re-create encoding.Chunk and call InsertChunk + // same with encoding.Batch and call InsertBatch + } + + return nil +} + +type batchEvents struct { + commit *l1.CommitBatchEvent + finalize *l1.FinalizeBatchEvent +} + +func newBatchEvents(commit *l1.CommitBatchEvent, finalize *l1.FinalizeBatchEvent) *batchEvents { + if commit.BatchIndex().Uint64() != finalize.BatchIndex().Uint64() { + panic("commit and finalize batch indexes do not match") + } + + return &batchEvents{ + commit: commit, + finalize: finalize, + } +} + +func (e *batchEvents) CompareTo(other *batchEvents) int { + return e.commit.BatchIndex().Cmp(other.commit.BatchIndex()) +} From acc7083dd2f9d2aec6a36de341b9cac9cef1b8fa Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Mon, 28 Oct 2024 16:22:03 +0800 Subject: [PATCH 06/25] implement processFinalizedBatch --- rollup/cmd/rollup_relayer/app/app.go | 154 ++++++++++++++++-- .../internal/controller/watcher/l2_watcher.go | 13 +- rollup/internal/orm/batch.go | 23 +++ 3 files changed, 171 insertions(+), 19 deletions(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index c238cf917d..19c0b67a65 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -14,14 +14,17 @@ import ( "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/rollup/l1" "github.com/urfave/cli/v2" + "gorm.io/gorm" "scroll-tech/common/database" "scroll-tech/common/observability" + "scroll-tech/common/types" "scroll-tech/common/utils" "scroll-tech/common/version" "scroll-tech/rollup/internal/config" "scroll-tech/rollup/internal/controller/relayer" "scroll-tech/rollup/internal/controller/watcher" + "scroll-tech/rollup/internal/orm" butils "scroll-tech/rollup/internal/utils" ) @@ -95,7 +98,7 @@ func action(ctx *cli.Context) error { if cfg.RecoveryConfig.Enable { log.Info("Starting rollup-relayer in recovery mode", "version", version.Version) - if err = restoreFullPreviousState(cfg, chunkProposer, batchProposer); err != nil { + if err = restoreFullPreviousState(cfg, db, chunkProposer, batchProposer, l2watcher); err != nil { log.Crit("failed to restore full previous state", "error", err) } @@ -145,7 +148,7 @@ func Run() { } } -func restoreFullPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer) error { +func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, l2Watcher *watcher.L2WatcherClient) error { log.Info("Restoring full previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) // DB state should be clean: the latest batch in the DB should be finalized on L1. This function will @@ -159,6 +162,9 @@ func restoreFullPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkPr // 1. Get latest finalized batch stored in DB latestDBBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) + if err != nil { + return fmt.Errorf("failed to get latest batch from DB: %w", err) + } fmt.Println("latestDBBatch", latestDBBatch) // TODO: @@ -226,7 +232,7 @@ func restoreFullPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkPr commitEvents.Set(commitEvent.BatchIndex().Uint64(), commitEvent) case l1.FinalizeEventType: - // TODO: this needs to be the same as in d + // TODO: this needs to be the same as in da syncer finalizeEvent := event.(*l1.FinalizeBatchEvent) commitEvent, exists := commitEvents.Get(finalizeEvent.BatchIndex().Uint64()) if !exists { @@ -261,32 +267,148 @@ func restoreFullPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkPr } // 5. Process all finalized batches: fetch L2 blocks and reproduce chunks and batches. + count = 0 + //var prev uint64 for batchEventsHeap.Len() > 0 { nextBatch := batchEventsHeap.Pop().Value() + fmt.Println("nextBatch", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), nextBatch.finalize.BatchIndex(), nextBatch.finalize.BatchHash()) + //fmt.Println("nextBatch", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), nextBatch.finalize.BatchIndex(), nextBatch.finalize.BatchHash()) + //if prev == nextBatch.commit.BatchIndex().Uint64() { + // fmt.Println("prev == nextBatch.commit.BatchIndex().Uint64()") + // continue + //} + // + //prev = nextBatch.commit.BatchIndex().Uint64() + //if err = processFinalizedBatch(db, reader, nextBatch, chunkProposer, batchProposer, l2Watcher); err != nil { + // return fmt.Errorf("failed to process finalized batch %d %s: %w", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), err) + //} + + //log.Info("Processed finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) + + //count++ + //if count >= 10 { + // break + //} + } + + return nil +} + +func processFinalizedBatch(db *gorm.DB, reader *l1.Reader, nextBatch *batchEvents, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, l2Watcher *watcher.L2WatcherClient) error { + log.Info("Processing finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) + + // 5.1. Fetch commit tx data for batch (via commit event). + args, err := reader.FetchCommitTxData(nextBatch.commit) + if err != nil { + return fmt.Errorf("failed to fetch commit tx data: %w", err) + } + + codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + if err != nil { + return fmt.Errorf("failed to get codec: %w", err) + } + + daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + if err != nil { + return fmt.Errorf("failed to decode DA chunks: %w", err) + } + lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] + lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + + log.Info("Fetching L2 blocks from l2geth", "batch", nextBatch.commit.BatchIndex(), "last L2 block in batch", lastBlockInBatch) + + // 5.2. Fetch L2 blocks for the entire batch. + if err = l2Watcher.TryFetchRunningMissingBlocks(lastBlockInBatch); err != nil { + return fmt.Errorf("failed to fetch L2 blocks: %w", err) + } + + // 5.3. Reproduce chunks. + daChunks := make([]*encoding.Chunk, 0, len(daChunksRawTxs)) + dbChunks := make([]*orm.Chunk, 0, len(daChunksRawTxs)) + for _, daChunkRawTxs := range daChunksRawTxs { + start := daChunkRawTxs.Blocks[0].Number() + end := daChunkRawTxs.Blocks[len(daChunkRawTxs.Blocks)-1].Number() + + blocks, err := l2Watcher.BlockORM().GetL2BlocksInRange(context.Background(), start, end) + if err != nil { + return fmt.Errorf("failed to get L2 blocks in range: %w", err) + } + + log.Info("Reproducing chunk", "start block", start, "end block", end) - // 5.1. Fetch commit tx data for batch (via commit event). - args, err := reader.FetchCommitTxData(nextBatch.commit) + var chunk encoding.Chunk + for _, block := range blocks { + chunk.Blocks = append(chunk.Blocks, block) + } + + metrics, err := butils.CalculateChunkMetrics(&chunk, codec.Version()) if err != nil { - return fmt.Errorf("failed to fetch commit tx data: %w", err) + return fmt.Errorf("failed to calculate chunk metrics: %w", err) } - codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + err = db.Transaction(func(dbTX *gorm.DB) error { + dbChunk, err := chunkProposer.ChunkORM().InsertChunk(context.Background(), &chunk, codec.Version(), *metrics, dbTX) + if err != nil { + return fmt.Errorf("failed to insert chunk to DB: %w", err) + } + if err := l2Watcher.BlockORM().UpdateChunkHashInRange(context.Background(), dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, dbChunk.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update chunk_hash for l2_blocks (chunk hash: %s, start block: %d, end block: %d): %w", dbChunk.Hash, dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, err) + } + + if err = chunkProposer.ChunkORM().UpdateProvingStatus(context.Background(), dbChunk.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for chunk %s: %w", dbChunk.Hash, err) + } + + daChunks = append(daChunks, &chunk) + dbChunks = append(dbChunks, dbChunk) + + return nil + }) if err != nil { - return fmt.Errorf("failed to get codec: %w", err) + return fmt.Errorf("failed to insert chunk in DB transaction: %w", err) } + } + + // 5.4 Reproduce batch. + dbParentBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) + if err != nil { + return fmt.Errorf("failed to get latest batch from DB: %w", err) + } - daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + var batch encoding.Batch + batch.Index = dbParentBatch.Index + 1 + batch.ParentBatchHash = common.HexToHash(dbParentBatch.Hash) + batch.TotalL1MessagePoppedBefore = dbChunks[0].TotalL1MessagesPoppedBefore + + for _, chunk := range daChunks { + batch.Chunks = append(batch.Chunks, chunk) + } + + metrics, err := butils.CalculateBatchMetrics(&batch, codec.Version()) + if err != nil { + return fmt.Errorf("failed to calculate batch metrics: %w", err) + } + + err = db.Transaction(func(dbTX *gorm.DB) error { + dbBatch, err := batchProposer.BatchORM().InsertBatch(context.Background(), &batch, codec.Version(), *metrics, dbTX) if err != nil { - return fmt.Errorf("failed to decode DA chunks: %w", err) + return fmt.Errorf("failed to insert batch to DB: %w", err) + } + if err = chunkProposer.ChunkORM().UpdateBatchHashInRange(context.Background(), dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, dbBatch.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update batch_hash for chunks (batch hash: %s, start chunk: %d, end chunk: %d): %w", dbBatch.Hash, dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, err) } - lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] - lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() - log.Info("Last L2 block in batch", "batch", nextBatch.commit.BatchIndex(), "L2 block", lastBlockInBatch) + if err = batchProposer.BatchORM().UpdateProvingStatus(context.Background(), dbBatch.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for batch %s: %w", dbBatch.Hash, err) + } + if err = batchProposer.BatchORM().UpdateRollupStatusCommitAndFinalizeTxHash(context.Background(), dbBatch.Hash, types.RollupFinalized, nextBatch.commit.TxHash().Hex(), nextBatch.finalize.TxHash().Hex(), dbTX); err != nil { + return fmt.Errorf("failed to update rollup status for batch %s: %w", dbBatch.Hash, err) + } - // 5.2. Fetch L2 blocks for each chunk. - // re-create encoding.Chunk and call InsertChunk - // same with encoding.Batch and call InsertBatch + return nil + }) + if err != nil { + return fmt.Errorf("failed to insert batch in DB transaction: %w", err) } return nil diff --git a/rollup/internal/controller/watcher/l2_watcher.go b/rollup/internal/controller/watcher/l2_watcher.go index 805b9bd710..ebeb23dc6a 100644 --- a/rollup/internal/controller/watcher/l2_watcher.go +++ b/rollup/internal/controller/watcher/l2_watcher.go @@ -60,13 +60,18 @@ func NewL2WatcherClient(ctx context.Context, client *ethclient.Client, confirmat const blocksFetchLimit = uint64(10) +func (w *L2WatcherClient) BlockORM() *orm.L2Block { + return w.l2BlockOrm +} + // TryFetchRunningMissingBlocks attempts to fetch and store block traces for any missing blocks. -func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) { +func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) error { w.metrics.fetchRunningMissingBlocksTotal.Inc() heightInDB, err := w.l2BlockOrm.GetL2BlocksLatestHeight(w.ctx) + fmt.Println("heightInDB", heightInDB) if err != nil { log.Error("failed to GetL2BlocksLatestHeight", "err", err) - return + return fmt.Errorf("failed to GetL2BlocksLatestHeight: %w", err) } // Fetch and store block traces for missing blocks @@ -79,11 +84,13 @@ func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) { if err = w.GetAndStoreBlocks(w.ctx, from, to); err != nil { log.Error("fail to getAndStoreBlockTraces", "from", from, "to", to, "err", err) - return + return fmt.Errorf("fail to getAndStoreBlockTraces: %w", err) } w.metrics.fetchRunningMissingBlocksHeight.Set(float64(to)) w.metrics.rollupL2BlocksFetchedGap.Set(float64(blockHeight - to)) } + + return nil } func txsToTxsData(txs gethTypes.Transactions) []*gethTypes.TransactionData { diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index 4b5c9f904e..c7f5b3cf57 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -417,6 +417,29 @@ func (o *Batch) UpdateProvingStatus(ctx context.Context, hash string, status typ return nil } +func (o *Batch) UpdateRollupStatusCommitAndFinalizeTxHash(ctx context.Context, hash string, status types.RollupStatus, commitTxHash string, finalizeTxHash string, dbTX ...*gorm.DB) error { + updateFields := make(map[string]interface{}) + updateFields["commit_tx_hash"] = commitTxHash + updateFields["committed_at"] = utils.NowUTC() + updateFields["finalize_tx_hash"] = finalizeTxHash + updateFields["finalized_at"] = time.Now() + + updateFields["rollup_status"] = int(status) + + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&Batch{}) + db = db.Where("hash", hash) + + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("Batch.UpdateRollupStatusCommitAndFinalizeTxHash error: %w, batch hash: %v, status: %v, commitTxHash: %v, finalizeTxHash: %v", err, hash, status.String(), commitTxHash, finalizeTxHash) + } + return nil +} + // UpdateRollupStatus updates the rollup status of a batch. func (o *Batch) UpdateRollupStatus(ctx context.Context, hash string, status types.RollupStatus, dbTX ...*gorm.DB) error { updateFields := make(map[string]interface{}) From 59ea99108a9bcd580559d348f44075c73c7b72b0 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:59:37 +0800 Subject: [PATCH 07/25] handle batches --- rollup/cmd/rollup_relayer/app/app.go | 131 +++++++++++------- .../controller/watcher/bundle_proposer.go | 4 + .../internal/controller/watcher/l2_watcher.go | 1 - rollup/internal/orm/bundle.go | 8 +- 4 files changed, 91 insertions(+), 53 deletions(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 19c0b67a65..bd4a81a2ff 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -98,7 +98,7 @@ func action(ctx *cli.Context) error { if cfg.RecoveryConfig.Enable { log.Info("Starting rollup-relayer in recovery mode", "version", version.Version) - if err = restoreFullPreviousState(cfg, db, chunkProposer, batchProposer, l2watcher); err != nil { + if err = restoreFullPreviousState(cfg, db, chunkProposer, batchProposer, bundleProposer, l2watcher); err != nil { log.Crit("failed to restore full previous state", "error", err) } @@ -112,7 +112,8 @@ func action(ctx *cli.Context) error { log.Error("failed to get block number", "err", loopErr) return } - l2watcher.TryFetchRunningMissingBlocks(number) + // errors are logged in the try method as well + _ = l2watcher.TryFetchRunningMissingBlocks(number) }) go utils.Loop(subCtx, time.Duration(cfg.L2Config.ChunkProposerConfig.ProposeIntervalMilliseconds)*time.Millisecond, chunkProposer.TryProposeChunk) @@ -148,18 +149,12 @@ func Run() { } } -func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, l2Watcher *watcher.L2WatcherClient) error { +func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) error { log.Info("Restoring full previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) // DB state should be clean: the latest batch in the DB should be finalized on L1. This function will // restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1. - // 1. Get latest finalized batch stored in DB - // 2. Get latest finalized L1 block - // 3. Get latest finalized batch from contract (at latest finalized L1 block) - // 4. Get batches one by one from stored in DB to latest finalized batch - // - reproduce chunks / batches - // 1. Get latest finalized batch stored in DB latestDBBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) if err != nil { @@ -206,9 +201,7 @@ func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *wa log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatch, "at latest finalized L1 block", latestFinalizedL1Block) // 4. Get batches one by one from stored in DB to latest finalized batch. - // TODO: replace with this after testing: common.HexToHash(latestDBBatch.CommitTxHash) - hash := common.HexToHash("0x7c5ed6c542cbd5a2e59a3e9c35df49f16ff99d8dc01830f14c61d4b97c4f70f8") - receipt, err := l1Client.TransactionReceipt(context.Background(), hash) + receipt, err := l1Client.TransactionReceipt(context.Background(), common.HexToHash(latestDBBatch.CommitTxHash)) if err != nil { return fmt.Errorf("failed to get transaction receipt of latest DB batch finalization transaction: %w", err) } @@ -216,10 +209,12 @@ func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *wa log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatch) + commitsHeapMap := common.NewHeapMap[uint64, *l1.CommitBatchEvent](func(event *l1.CommitBatchEvent) uint64 { + return event.BatchIndex().Uint64() + }) batchEventsHeap := common.NewHeap[*batchEvents]() - commitEvents := common.NewShrinkingMap[uint64, *l1.CommitBatchEvent](1000) - var innerErr error - count := 0 + var bundles [][]*batchEvents + err = reader.FetchRollupEventsInRangeWithCallback(fromBlock, latestFinalizedL1Block, func(event l1.RollupEvent) bool { // We're only interested in batches that are newer than the latest finalized batch in the DB. if event.BatchIndex().Uint64() <= latestDBBatch.Index { @@ -229,66 +224,102 @@ func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *wa switch event.Type() { case l1.CommitEventType: commitEvent := event.(*l1.CommitBatchEvent) - commitEvents.Set(commitEvent.BatchIndex().Uint64(), commitEvent) + commitsHeapMap.Push(commitEvent) case l1.FinalizeEventType: - // TODO: this needs to be the same as in da syncer finalizeEvent := event.(*l1.FinalizeBatchEvent) - commitEvent, exists := commitEvents.Get(finalizeEvent.BatchIndex().Uint64()) - if !exists { - innerErr = fmt.Errorf("commit event not found for finalize event %d", finalizeEvent.BatchIndex().Uint64()) - return false + + var bundle []*batchEvents + + // with bundles all commited batches until this finalized batch are finalized in the same bundle + for commitsHeapMap.Len() > 0 { + commitEvent := commitsHeapMap.Peek() + if commitEvent.BatchIndex().Uint64() > finalizeEvent.BatchIndex().Uint64() { + break + } + + bEvents := newBatchEvents(commitEvent, finalizeEvent) + commitsHeapMap.Pop() + batchEventsHeap.Push(bEvents) + bundle = append(bundle, bEvents) } - batchEventsHeap.Push(newBatchEvents(commitEvent, finalizeEvent)) + bundles = append(bundles, bundle) // Stop fetching rollup events if we reached the latest finalized batch. if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatch { return false } - if count >= 100 { - return false - } - count++ - case l1.RevertEventType: // We ignore reverted batches. - commitEvents.Delete(event.BatchIndex().Uint64()) + commitsHeapMap.RemoveByKey(event.BatchIndex().Uint64()) } return true }) - if innerErr != nil { - return fmt.Errorf("failed to fetch rollup events (inner): %w", innerErr) - } if err != nil { return fmt.Errorf("failed to fetch rollup events: %w", err) } // 5. Process all finalized batches: fetch L2 blocks and reproduce chunks and batches. - count = 0 - //var prev uint64 for batchEventsHeap.Len() > 0 { nextBatch := batchEventsHeap.Pop().Value() fmt.Println("nextBatch", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), nextBatch.finalize.BatchIndex(), nextBatch.finalize.BatchHash()) - //fmt.Println("nextBatch", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), nextBatch.finalize.BatchIndex(), nextBatch.finalize.BatchHash()) - //if prev == nextBatch.commit.BatchIndex().Uint64() { - // fmt.Println("prev == nextBatch.commit.BatchIndex().Uint64()") - // continue - //} - // - //prev = nextBatch.commit.BatchIndex().Uint64() - //if err = processFinalizedBatch(db, reader, nextBatch, chunkProposer, batchProposer, l2Watcher); err != nil { - // return fmt.Errorf("failed to process finalized batch %d %s: %w", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), err) - //} - - //log.Info("Processed finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) - - //count++ - //if count >= 10 { - // break - //} + if err = processFinalizedBatch(db, reader, nextBatch, chunkProposer, batchProposer, l2Watcher); err != nil { + return fmt.Errorf("failed to process finalized batch %d %s: %w", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), err) + } + + log.Info("Processed finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) + } + + // 6. Create bundles if needed. + for _, bundle := range bundles { + var dbBatches []*orm.Batch + var lastBatchInBundle *orm.Batch + + for _, batch := range bundle { + dbBatch, err := batchProposer.BatchORM().GetBatchByIndex(context.Background(), batch.commit.BatchIndex().Uint64()) + if err != nil { + return fmt.Errorf("failed to get batch by index for bundle generation: %w", err) + } + // Bundles are only supported for codec version 3 and above. + if encoding.CodecVersion(dbBatch.CodecVersion) < encoding.CodecV3 { + break + } + + dbBatches = append(dbBatches, dbBatch) + lastBatchInBundle = dbBatch + } + + if len(dbBatches) == 0 { + continue + } + + err = db.Transaction(func(dbTX *gorm.DB) error { + newBundle, err := bundleProposer.BundleORM().InsertBundle(context.Background(), dbBatches, encoding.CodecVersion(lastBatchInBundle.CodecVersion), dbTX) + if err != nil { + return fmt.Errorf("failed to insert bundle to DB: %w", err) + } + if err = batchProposer.BatchORM().UpdateBundleHashInRange(context.Background(), newBundle.StartBatchIndex, newBundle.EndBatchIndex, newBundle.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update bundle_hash %s for batches (%d to %d): %w", newBundle.Hash, newBundle.StartBatchIndex, newBundle.EndBatchIndex, err) + } + + if err = bundleProposer.BundleORM().UpdateFinalizeTxHashAndRollupStatus(context.Background(), newBundle.Hash, lastBatchInBundle.FinalizeTxHash, types.RollupFinalized, dbTX); err != nil { + return fmt.Errorf("failed to update finalize tx hash and rollup status for bundle %s: %w", newBundle.Hash, err) + } + + if err = bundleProposer.BundleORM().UpdateProvingStatus(context.Background(), newBundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for bundle %s: %w", newBundle.Hash, err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to insert bundle in DB transaction: %w", err) + } + + fmt.Println("bundle", len(bundle), bundle[0].commit.BatchIndex()) } return nil diff --git a/rollup/internal/controller/watcher/bundle_proposer.go b/rollup/internal/controller/watcher/bundle_proposer.go index 686ad580c0..ca53da3909 100644 --- a/rollup/internal/controller/watcher/bundle_proposer.go +++ b/rollup/internal/controller/watcher/bundle_proposer.go @@ -86,6 +86,10 @@ func NewBundleProposer(ctx context.Context, cfg *config.BundleProposerConfig, ch return p } +func (p *BundleProposer) BundleORM() *orm.Bundle { + return p.bundleOrm +} + // TryProposeBundle tries to propose a new bundle. func (p *BundleProposer) TryProposeBundle() { p.bundleProposerCircleTotal.Inc() diff --git a/rollup/internal/controller/watcher/l2_watcher.go b/rollup/internal/controller/watcher/l2_watcher.go index ebeb23dc6a..2ceba4d049 100644 --- a/rollup/internal/controller/watcher/l2_watcher.go +++ b/rollup/internal/controller/watcher/l2_watcher.go @@ -68,7 +68,6 @@ func (w *L2WatcherClient) BlockORM() *orm.L2Block { func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) error { w.metrics.fetchRunningMissingBlocksTotal.Inc() heightInDB, err := w.l2BlockOrm.GetL2BlocksLatestHeight(w.ctx) - fmt.Println("heightInDB", heightInDB) if err != nil { log.Error("failed to GetL2BlocksLatestHeight", "err", err) return fmt.Errorf("failed to GetL2BlocksLatestHeight: %w", err) diff --git a/rollup/internal/orm/bundle.go b/rollup/internal/orm/bundle.go index 6965f6dfae..3d35be29db 100644 --- a/rollup/internal/orm/bundle.go +++ b/rollup/internal/orm/bundle.go @@ -189,7 +189,7 @@ func (o *Bundle) InsertBundle(ctx context.Context, batches []*Batch, codecVersio } // UpdateFinalizeTxHashAndRollupStatus updates the finalize transaction hash and rollup status for a bundle. -func (o *Bundle) UpdateFinalizeTxHashAndRollupStatus(ctx context.Context, hash string, finalizeTxHash string, status types.RollupStatus) error { +func (o *Bundle) UpdateFinalizeTxHashAndRollupStatus(ctx context.Context, hash string, finalizeTxHash string, status types.RollupStatus, dbTX ...*gorm.DB) error { updateFields := make(map[string]interface{}) updateFields["finalize_tx_hash"] = finalizeTxHash updateFields["rollup_status"] = int(status) @@ -197,7 +197,11 @@ func (o *Bundle) UpdateFinalizeTxHashAndRollupStatus(ctx context.Context, hash s updateFields["finalized_at"] = time.Now() } - db := o.db.WithContext(ctx) + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) db = db.Model(&Bundle{}) db = db.Where("hash", hash) From 2df07a9de3fd8faa8e356255269565689e8ca913 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:53:22 +0800 Subject: [PATCH 08/25] introduce ForceL1MessageCount to config to be able to set a custom L1 message amount. this is mainly for testing purposes --- go.work | 1 + go.work.sum | 249 ++++++++++++++++++- rollup/cmd/permissionless_batches/app/app.go | 21 +- rollup/go.mod | 2 +- rollup/go.sum | 2 + rollup/internal/config/recovery.go | 4 +- 6 files changed, 259 insertions(+), 20 deletions(-) diff --git a/go.work b/go.work index cc287e9be6..fcb531e98e 100644 --- a/go.work +++ b/go.work @@ -7,4 +7,5 @@ use ( ./database ./rollup ./tests/integration-test + //../go-ethereum ) diff --git a/go.work.sum b/go.work.sum index 68035f0823..1da712d685 100644 --- a/go.work.sum +++ b/go.work.sum @@ -19,54 +19,71 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= cloud.google.com/go/accessapproval v1.7.4 h1:ZvLvJ952zK8pFHINjpMBY5k7LTAp/6pBf50RDMRgBUI= cloud.google.com/go/accessapproval v1.7.4/go.mod h1:/aTEh45LzplQgFYdQdwPMR9YdX0UlhBmvB84uAmQKUc= +cloud.google.com/go/accessapproval v1.7.5 h1:uzmAMSgYcnlHa9X9YSQZ4Q1wlfl4NNkZyQgho1Z6p04= cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= cloud.google.com/go/accesscontextmanager v1.8.4 h1:Yo4g2XrBETBCqyWIibN3NHNPQKUfQqti0lI+70rubeE= cloud.google.com/go/accesscontextmanager v1.8.4/go.mod h1:ParU+WbMpD34s5JFEnGAnPBYAgUHozaTmDJU7aCU9+M= +cloud.google.com/go/accesscontextmanager v1.8.5 h1:2GLNaNu9KRJhJBFTIVRoPwk6xE5mUDgD47abBq4Zp/I= cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= cloud.google.com/go/aiplatform v1.54.0 h1:wH7OYl9Vq/5tupok0BPTFY9xaTLb0GxkReHtB5PF7cI= cloud.google.com/go/aiplatform v1.54.0/go.mod h1:pwZMGvqe0JRkI1GWSZCtnAfrR4K1bv65IHILGA//VEU= +cloud.google.com/go/aiplatform v1.60.0 h1:0cSrii1ZeLr16MbBoocyy5KVnrSdiQ3KN/vtrTe7RqE= cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= cloud.google.com/go/analytics v0.21.6 h1:fnV7B8lqyEYxCU0LKk+vUL7mTlqRAq4uFlIthIdr/iA= cloud.google.com/go/analytics v0.21.6/go.mod h1:eiROFQKosh4hMaNhF85Oc9WO97Cpa7RggD40e/RBy8w= +cloud.google.com/go/analytics v0.23.0 h1:Q+y94XH84jM8SK8O7qiY/PJRexb6n7dRbQ6PiUa4YGM= cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= cloud.google.com/go/apigateway v1.6.4 h1:VVIxCtVerchHienSlaGzV6XJGtEM9828Erzyr3miUGs= cloud.google.com/go/apigateway v1.6.4/go.mod h1:0EpJlVGH5HwAN4VF4Iec8TAzGN1aQgbxAWGJsnPCGGY= +cloud.google.com/go/apigateway v1.6.5 h1:sPXnpk+6TneKIrjCjcpX5YGsAKy3PTdpIchoj8/74OE= cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= cloud.google.com/go/apigeeconnect v1.6.4 h1:jSoGITWKgAj/ssVogNE9SdsTqcXnryPzsulENSRlusI= cloud.google.com/go/apigeeconnect v1.6.4/go.mod h1:CapQCWZ8TCjnU0d7PobxhpOdVz/OVJ2Hr/Zcuu1xFx0= +cloud.google.com/go/apigeeconnect v1.6.5 h1:CrfIKv9Go3fh/QfQgisU3MeP90Ww7l/sVGmr3TpECo8= cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= cloud.google.com/go/apigeeregistry v0.8.2 h1:DSaD1iiqvELag+lV4VnnqUUFd8GXELu01tKVdWZrviE= cloud.google.com/go/apigeeregistry v0.8.2/go.mod h1:h4v11TDGdeXJDJvImtgK2AFVvMIgGWjSb0HRnBSjcX8= +cloud.google.com/go/apigeeregistry v0.8.3 h1:C+QU2K+DzDjk4g074ouwHQGkoff1h5OMQp6sblCVreQ= cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= cloud.google.com/go/appengine v1.8.4 h1:Qub3fqR7iA1daJWdzjp/Q0Jz0fUG0JbMc7Ui4E9IX/E= cloud.google.com/go/appengine v1.8.4/go.mod h1:TZ24v+wXBujtkK77CXCpjZbnuTvsFNT41MUaZ28D6vg= +cloud.google.com/go/appengine v1.8.5 h1:l2SviT44zWQiOv8bPoMBzW0vOcMO22iO0s+nVtVhdts= cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= cloud.google.com/go/area120 v0.8.4 h1:YnSO8m02pOIo6AEOgiOoUDVbw4pf+bg2KLHi4rky320= cloud.google.com/go/area120 v0.8.4/go.mod h1:jfawXjxf29wyBXr48+W+GyX/f8fflxp642D/bb9v68M= +cloud.google.com/go/area120 v0.8.5 h1:vTs08KPLN/iMzTbxpu5ciL06KcsrVPMjz4IwcQyZ4uY= cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= cloud.google.com/go/artifactregistry v1.14.6 h1:/hQaadYytMdA5zBh+RciIrXZQBWK4vN7EUsrQHG+/t8= cloud.google.com/go/artifactregistry v1.14.6/go.mod h1:np9LSFotNWHcjnOgh8UVK0RFPCTUGbO0ve3384xyHfE= +cloud.google.com/go/artifactregistry v1.14.7 h1:W9sVlyb1VRcUf83w7aM3yMsnp4HS4PoyGqYQNG0O5lI= cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= cloud.google.com/go/asset v1.15.3 h1:uI8Bdm81s0esVWbWrTHcjFDFKNOa9aB7rI1vud1hO84= cloud.google.com/go/asset v1.15.3/go.mod h1:yYLfUD4wL4X589A9tYrv4rFrba0QlDeag0CMcM5ggXU= +cloud.google.com/go/asset v1.17.2 h1:xgFnBP3luSbUcC9RWJvb3Zkt+y/wW6PKwPHr3ssnIP8= cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= cloud.google.com/go/assuredworkloads v1.11.4 h1:FsLSkmYYeNuzDm8L4YPfLWV+lQaUrJmH5OuD37t1k20= cloud.google.com/go/assuredworkloads v1.11.4/go.mod h1:4pwwGNwy1RP0m+y12ef3Q/8PaiWrIDQ6nD2E8kvWI9U= +cloud.google.com/go/assuredworkloads v1.11.5 h1:gCrN3IyvqY3cP0wh2h43d99CgH3G+WYs9CeuFVKChR8= cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= cloud.google.com/go/automl v1.13.4 h1:i9tOKXX+1gE7+rHpWKjiuPfGBVIYoWvLNIGpWgPtF58= cloud.google.com/go/automl v1.13.4/go.mod h1:ULqwX/OLZ4hBVfKQaMtxMSTlPx0GqGbWN8uA/1EqCP8= +cloud.google.com/go/automl v1.13.5 h1:ijiJy9sYWh75WrqImXsfWc1e3HR3iO+ef9fvW03Ig/4= cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= cloud.google.com/go/baremetalsolution v1.2.3 h1:oQiFYYCe0vwp7J8ZmF6siVKEumWtiPFJMJcGuyDVRUk= cloud.google.com/go/baremetalsolution v1.2.3/go.mod h1:/UAQ5xG3faDdy180rCUv47e0jvpp3BFxT+Cl0PFjw5g= +cloud.google.com/go/baremetalsolution v1.2.4 h1:LFydisRmS7hQk9P/YhekwuZGqb45TW4QavcrMToWo5A= cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= cloud.google.com/go/batch v1.6.3 h1:mPiIH20a5NU02rucbAmLeO4sLPO9hrTK0BLjdHyW8xw= cloud.google.com/go/batch v1.6.3/go.mod h1:J64gD4vsNSA2O5TtDB5AAux3nJ9iV8U3ilg3JDBYejU= +cloud.google.com/go/batch v1.8.0 h1:2HK4JerwVaIcCh/lJiHwh6+uswPthiMMWhiSWLELayk= cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= cloud.google.com/go/beyondcorp v1.0.3 h1:VXf9SnrnSmj2BF2cHkoTHvOUp8gjsz1KJFOMW7czdsY= cloud.google.com/go/beyondcorp v1.0.3/go.mod h1:HcBvnEd7eYr+HGDd5ZbuVmBYX019C6CEXBonXbCVwJo= +cloud.google.com/go/beyondcorp v1.0.4 h1:qs0J0O9Ol2h1yA0AU+r7l3hOCPzs2MjE1d6d/kaHIKo= cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= @@ -76,69 +93,89 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.57.1 h1:FiULdbbzUxWD0Y4ZGPSVCDLvqRSyCIO6zKV7E2nf5uA= cloud.google.com/go/bigquery v1.57.1/go.mod h1:iYzC0tGVWt1jqSzBHqCr3lrRn0u13E8e+AqowBsDgug= +cloud.google.com/go/bigquery v1.59.1 h1:CpT+/njKuKT3CEmswm6IbhNu9u35zt5dO4yPDLW+nG4= cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= cloud.google.com/go/bigtable v1.2.0 h1:F4cCmA4nuV84V5zYQ3MKY+M1Cw1avHDuf3S/LcZPA9c= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/billing v1.17.4 h1:77/4kCqzH6Ou5CCDzNmqmboE+WvbwFBJmw1QZQz19AI= cloud.google.com/go/billing v1.17.4/go.mod h1:5DOYQStCxquGprqfuid/7haD7th74kyMBHkjO/OvDtk= +cloud.google.com/go/billing v1.18.2 h1:oWUEQvuC4JvtnqLZ35zgzdbuHt4Itbftvzbe6aEyFdE= cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= cloud.google.com/go/binaryauthorization v1.7.3 h1:3R6WYn1JKIaVicBmo18jXubu7xh4mMkmbIgsTXk0cBA= cloud.google.com/go/binaryauthorization v1.7.3/go.mod h1:VQ/nUGRKhrStlGr+8GMS8f6/vznYLkdK5vaKfdCIpvU= +cloud.google.com/go/binaryauthorization v1.8.1 h1:1jcyh2uIUwSZkJ/JmL8kd5SUkL/Krbv8zmYLEbAz6kY= cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= cloud.google.com/go/certificatemanager v1.7.4 h1:5YMQ3Q+dqGpwUZ9X5sipsOQ1fLPsxod9HNq0+nrqc6I= cloud.google.com/go/certificatemanager v1.7.4/go.mod h1:FHAylPe/6IIKuaRmHbjbdLhGhVQ+CWHSD5Jq0k4+cCE= +cloud.google.com/go/certificatemanager v1.7.5 h1:UMBr/twXvH3jcT5J5/YjRxf2tvwTYIfrpemTebe0txc= cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= cloud.google.com/go/channel v1.17.3 h1:Rd4+fBrjiN6tZ4TR8R/38elkyEkz6oogGDr7jDyjmMY= cloud.google.com/go/channel v1.17.3/go.mod h1:QcEBuZLGGrUMm7kNj9IbU1ZfmJq2apotsV83hbxX7eE= +cloud.google.com/go/channel v1.17.5 h1:/omiBnyFjm4S1ETHoOmJbL7LH7Ljcei4rYG6Sj3hc80= cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= cloud.google.com/go/cloudbuild v1.15.0 h1:9IHfEMWdCklJ1cwouoiQrnxmP0q3pH7JUt8Hqx4Qbck= cloud.google.com/go/cloudbuild v1.15.0/go.mod h1:eIXYWmRt3UtggLnFGx4JvXcMj4kShhVzGndL1LwleEM= +cloud.google.com/go/cloudbuild v1.15.1 h1:ZB6oOmJo+MTov9n629fiCrO9YZPOg25FZvQ7gIHu5ng= cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= cloud.google.com/go/clouddms v1.7.3 h1:xe/wJKz55VO1+L891a1EG9lVUgfHr9Ju/I3xh1nwF84= cloud.google.com/go/clouddms v1.7.3/go.mod h1:fkN2HQQNUYInAU3NQ3vRLkV2iWs8lIdmBKOx4nrL6Hc= +cloud.google.com/go/clouddms v1.7.4 h1:Sr0Zo5EAcPQiCBgHWICg3VGkcdS/LLP1d9SR7qQBM/s= cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= cloud.google.com/go/cloudtasks v1.12.4 h1:5xXuFfAjg0Z5Wb81j2GAbB3e0bwroCeSF+5jBn/L650= cloud.google.com/go/cloudtasks v1.12.4/go.mod h1:BEPu0Gtt2dU6FxZHNqqNdGqIG86qyWKBPGnsb7udGY0= +cloud.google.com/go/cloudtasks v1.12.6 h1:EUt1hIZ9bLv8Iz9yWaCrqgMnIU+Tdh0yXM1MMVGhjfE= cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/contactcenterinsights v1.12.0 h1:wP41IUA4ucMVooj/TP53jd7vbNjWrDkAPOeulVJGT5U= cloud.google.com/go/contactcenterinsights v1.12.0/go.mod h1:HHX5wrz5LHVAwfI2smIotQG9x8Qd6gYilaHcLLLmNis= +cloud.google.com/go/contactcenterinsights v1.13.0 h1:6Vs/YnDG5STGjlWMEjN/xtmft7MrOTOnOZYUZtGTx0w= cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= cloud.google.com/go/container v1.28.0 h1:/o82CFWXIYnT9p/07SnRgybqL3Pmmu86jYIlzlJVUBY= cloud.google.com/go/container v1.28.0/go.mod h1:b1A1gJeTBXVLQ6GGw9/9M4FG94BEGsqJ5+t4d/3N7O4= +cloud.google.com/go/container v1.31.0 h1:MAaNH7VRNPWEhvqOypq2j+7ONJKrKzon4v9nS3nLZe0= cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= cloud.google.com/go/containeranalysis v0.11.3 h1:5rhYLX+3a01drpREqBZVXR9YmWH45RnML++8NsCtuD8= cloud.google.com/go/containeranalysis v0.11.3/go.mod h1:kMeST7yWFQMGjiG9K7Eov+fPNQcGhb8mXj/UcTiWw9U= +cloud.google.com/go/containeranalysis v0.11.4 h1:doJ0M1ljS4hS0D2UbHywlHGwB7sQLNrt9vFk9Zyi7vY= cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= cloud.google.com/go/datacatalog v1.19.0 h1:rbYNmHwvAOOwnW2FPXYkaK3Mf1MmGqRzK0mMiIEyLdo= cloud.google.com/go/datacatalog v1.19.0/go.mod h1:5FR6ZIF8RZrtml0VUao22FxhdjkoG+a0866rEnObryM= +cloud.google.com/go/datacatalog v1.19.3 h1:A0vKYCQdxQuV4Pi0LL9p39Vwvg4jH5yYveMv50gU5Tw= cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= cloud.google.com/go/dataflow v0.9.4 h1:7VmCNWcPJBS/srN2QnStTB6nu4Eb5TMcpkmtaPVhRt4= cloud.google.com/go/dataflow v0.9.4/go.mod h1:4G8vAkHYCSzU8b/kmsoR2lWyHJD85oMJPHMtan40K8w= +cloud.google.com/go/dataflow v0.9.5 h1:RYHtcPhmE664+F0Je46p+NvFbG8z//KCXp+uEqB4jZU= cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= cloud.google.com/go/dataform v0.9.1 h1:jV+EsDamGX6cE127+QAcCR/lergVeeZdEQ6DdrxW3sQ= cloud.google.com/go/dataform v0.9.1/go.mod h1:pWTg+zGQ7i16pyn0bS1ruqIE91SdL2FDMvEYu/8oQxs= +cloud.google.com/go/dataform v0.9.2 h1:5e4eqGrd0iDTCg4Q+VlAao5j2naKAA7xRurNtwmUknU= cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= cloud.google.com/go/datafusion v1.7.4 h1:Q90alBEYlMi66zL5gMSGQHfbZLB55mOAg03DhwTTfsk= cloud.google.com/go/datafusion v1.7.4/go.mod h1:BBs78WTOLYkT4GVZIXQCZT3GFpkpDN4aBY4NDX/jVlM= +cloud.google.com/go/datafusion v1.7.5 h1:HQ/BUOP8OIGJxuztpYvNvlb+/U+/Bfs9SO8tQbh61fk= cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= cloud.google.com/go/datalabeling v0.8.4 h1:zrq4uMmunf2KFDl/7dS6iCDBBAxBnKVDyw6+ajz3yu0= cloud.google.com/go/datalabeling v0.8.4/go.mod h1:Z1z3E6LHtffBGrNUkKwbwbDxTiXEApLzIgmymj8A3S8= +cloud.google.com/go/datalabeling v0.8.5 h1:GpIFRdm0qIZNsxqURFJwHt0ZBJZ0nF/mUVEigR7PH/8= cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= cloud.google.com/go/dataplex v1.11.2 h1:AfFFR15Ifh4U+Me1IBztrSd5CrasTODzy3x8KtDyHdc= cloud.google.com/go/dataplex v1.11.2/go.mod h1:mHJYQQ2VEJHsyoC0OdNyy988DvEbPhqFs5OOLffLX0c= +cloud.google.com/go/dataplex v1.14.2 h1:fxIfdU8fxzR3clhOoNI7XFppvAmndxDu1AMH+qX9WKQ= cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= cloud.google.com/go/dataproc/v2 v2.3.0 h1:tTVP9tTxmc8fixxOd/8s6Q6Pz/+yzn7r7XdZHretQH0= cloud.google.com/go/dataproc/v2 v2.3.0/go.mod h1:G5R6GBc9r36SXv/RtZIVfB8SipI+xVn0bX5SxUzVYbY= +cloud.google.com/go/dataproc/v2 v2.4.0 h1:/u81Fd+BvCLp+xjctI1DiWVJn6cn9/s3Akc8xPH02yk= cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= cloud.google.com/go/dataqna v0.8.4 h1:NJnu1kAPamZDs/if3bJ3+Wb6tjADHKL83NUWsaIp2zg= cloud.google.com/go/dataqna v0.8.4/go.mod h1:mySRKjKg5Lz784P6sCov3p1QD+RZQONRMRjzGNcFd0c= +cloud.google.com/go/dataqna v0.8.5 h1:9ybXs3nr9BzxSGC04SsvtuXaHY0qmJSLIpIAbZo9GqQ= cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= @@ -146,140 +183,185 @@ cloud.google.com/go/datastore v1.15.0 h1:0P9WcsQeTWjuD1H14JIY7XQscIPQ4Laje8ti96I cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= cloud.google.com/go/datastream v1.10.3 h1:Z2sKPIB7bT2kMW5Uhxy44ZgdJzxzE5uKjavoW+EuHEE= cloud.google.com/go/datastream v1.10.3/go.mod h1:YR0USzgjhqA/Id0Ycu1VvZe8hEWwrkjuXrGbzeDOSEA= +cloud.google.com/go/datastream v1.10.4 h1:o1QDKMo/hk0FN7vhoUQURREuA0rgKmnYapB+1M+7Qz4= cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= cloud.google.com/go/deploy v1.15.0 h1:ZdmYzRMTGkVyP1nXEUat9FpbJGJemDcNcx82RSSOElc= cloud.google.com/go/deploy v1.15.0/go.mod h1:e5XOUI5D+YGldyLNZ21wbp9S8otJbBE4i88PtO9x/2g= +cloud.google.com/go/deploy v1.17.1 h1:m27Ojwj03gvpJqCbodLYiVmE9x4/LrHGGMjzc0LBfM4= cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= cloud.google.com/go/dialogflow v1.44.3 h1:cK/f88KX+YVR4tLH4clMQlvrLWD2qmKJQziusjGPjmc= cloud.google.com/go/dialogflow v1.44.3/go.mod h1:mHly4vU7cPXVweuB5R0zsYKPMzy240aQdAu06SqBbAQ= +cloud.google.com/go/dialogflow v1.49.0 h1:KqG0oxGE71qo0lRVyAoeBozefCvsMfcDzDjoLYSY0F4= cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= cloud.google.com/go/dlp v1.11.1 h1:OFlXedmPP/5//X1hBEeq3D9kUVm9fb6ywYANlpv/EsQ= cloud.google.com/go/dlp v1.11.1/go.mod h1:/PA2EnioBeXTL/0hInwgj0rfsQb3lpE3R8XUJxqUNKI= +cloud.google.com/go/dlp v1.11.2 h1:lTipOuJaSjlYnnotPMbEhKURLC6GzCMDDzVbJAEbmYM= cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= cloud.google.com/go/documentai v1.23.5 h1:KAlzT+q8qvRxAmhsJUvLtfFHH0PNvz3M79H6CgVBKL8= cloud.google.com/go/documentai v1.23.5/go.mod h1:ghzBsyVTiVdkfKaUCum/9bGBEyBjDO4GfooEcYKhN+g= +cloud.google.com/go/documentai v1.25.0 h1:lI62GMEEPO6vXJI9hj+G9WjOvnR0hEjvjokrnex4cxA= cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= cloud.google.com/go/domains v0.9.4 h1:ua4GvsDztZ5F3xqjeLKVRDeOvJshf5QFgWGg1CKti3A= cloud.google.com/go/domains v0.9.4/go.mod h1:27jmJGShuXYdUNjyDG0SodTfT5RwLi7xmH334Gvi3fY= +cloud.google.com/go/domains v0.9.5 h1:Mml/R6s3vQQvFPpi/9oX3O5dRirgjyJ8cksK8N19Y7g= cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= cloud.google.com/go/edgecontainer v1.1.4 h1:Szy3Q/N6bqgQGyxqjI+6xJZbmvPvnFHp3UZr95DKcQ0= cloud.google.com/go/edgecontainer v1.1.4/go.mod h1:AvFdVuZuVGdgaE5YvlL1faAoa1ndRR/5XhXZvPBHbsE= +cloud.google.com/go/edgecontainer v1.1.5 h1:tBY32km78ScpK2aOP84JoW/+wtpx5WluyPUSEE3270U= cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= cloud.google.com/go/essentialcontacts v1.6.5 h1:S2if6wkjR4JCEAfDtIiYtD+sTz/oXjh2NUG4cgT1y/Q= cloud.google.com/go/essentialcontacts v1.6.5/go.mod h1:jjYbPzw0x+yglXC890l6ECJWdYeZ5dlYACTFL0U/VuM= +cloud.google.com/go/essentialcontacts v1.6.6 h1:13eHn5qBnsawxI7mIrv4jRIEmQ1xg0Ztqw5ZGqtUNfA= cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= cloud.google.com/go/eventarc v1.13.3 h1:+pFmO4eu4dOVipSaFBLkmqrRYG94Xl/TQZFOeohkuqU= cloud.google.com/go/eventarc v1.13.3/go.mod h1:RWH10IAZIRcj1s/vClXkBgMHwh59ts7hSWcqD3kaclg= +cloud.google.com/go/eventarc v1.13.4 h1:ORkd6/UV5FIdA8KZQDLNZYKS7BBOrj0p01DXPmT4tE4= cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= cloud.google.com/go/filestore v1.8.0 h1:/+wUEGwk3x3Kxomi2cP5dsR8+SIXxo7M0THDjreFSYo= cloud.google.com/go/filestore v1.8.0/go.mod h1:S5JCxIbFjeBhWMTfIYH2Jx24J6BqjwpkkPl+nBA5DlI= +cloud.google.com/go/filestore v1.8.1 h1:X5G4y/vrUo1B8Nsz93qSWTMAcM8LXbGUldq33OdcdCw= cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/firestore v1.15.0 h1:/k8ppuWOtNuDHt2tsRV42yI21uaGnKDEQnRFeBpbFF8= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= cloud.google.com/go/functions v1.15.4 h1:ZjdiV3MyumRM6++1Ixu6N0VV9LAGlCX4AhW6Yjr1t+U= cloud.google.com/go/functions v1.15.4/go.mod h1:CAsTc3VlRMVvx+XqXxKqVevguqJpnVip4DdonFsX28I= +cloud.google.com/go/functions v1.16.0 h1:IWVylmK5F6hJ3R5zaRW7jI5PrWhCvtBVU4axQLmXSo4= cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= cloud.google.com/go/gkebackup v1.3.4 h1:KhnOrr9A1tXYIYeXKqCKbCI8TL2ZNGiD3dm+d7BDUBg= cloud.google.com/go/gkebackup v1.3.4/go.mod h1:gLVlbM8h/nHIs09ns1qx3q3eaXcGSELgNu1DWXYz1HI= +cloud.google.com/go/gkebackup v1.3.5 h1:iuE8KNtTsPOc79qeWoNS8zOWoXPD9SAdOmwgxtlCmh8= cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= cloud.google.com/go/gkeconnect v0.8.4 h1:1JLpZl31YhQDQeJ98tK6QiwTpgHFYRJwpntggpQQWis= cloud.google.com/go/gkeconnect v0.8.4/go.mod h1:84hZz4UMlDCKl8ifVW8layK4WHlMAFeq8vbzjU0yJkw= +cloud.google.com/go/gkeconnect v0.8.5 h1:17d+ZSSXKqG/RwZCq3oFMIWLPI8Zw3b8+a9/BEVlwH0= cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= cloud.google.com/go/gkehub v0.14.4 h1:J5tYUtb3r0cl2mM7+YHvV32eL+uZQ7lONyUZnPikCEo= cloud.google.com/go/gkehub v0.14.4/go.mod h1:Xispfu2MqnnFt8rV/2/3o73SK1snL8s9dYJ9G2oQMfc= +cloud.google.com/go/gkehub v0.14.5 h1:RboLNFzf9wEMSo7DrKVBlf+YhK/A/jrLN454L5Tz99Q= cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= cloud.google.com/go/gkemulticloud v1.0.3 h1:NmJsNX9uQ2CT78957xnjXZb26TDIMvv+d5W2vVUt0Pg= cloud.google.com/go/gkemulticloud v1.0.3/go.mod h1:7NpJBN94U6DY1xHIbsDqB2+TFZUfjLUKLjUX8NGLor0= +cloud.google.com/go/gkemulticloud v1.1.1 h1:rsSZAGLhyjyE/bE2ToT5fqo1qSW7S+Ubsc9jFOcbhSI= cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= cloud.google.com/go/grafeas v0.3.0 h1:oyTL/KjiUeBs9eYLw/40cpSZglUC+0F7X4iu/8t7NWs= cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= +cloud.google.com/go/grafeas v0.3.4 h1:D4x32R/cHX3MTofKwirz015uEdVk4uAxvZkZCZkOrF4= cloud.google.com/go/grafeas v0.3.4/go.mod h1:A5m316hcG+AulafjAbPKXBO/+I5itU4LOdKO2R/uDIc= cloud.google.com/go/gsuiteaddons v1.6.4 h1:uuw2Xd37yHftViSI8J2hUcCS8S7SH3ZWH09sUDLW30Q= cloud.google.com/go/gsuiteaddons v1.6.4/go.mod h1:rxtstw7Fx22uLOXBpsvb9DUbC+fiXs7rF4U29KHM/pE= +cloud.google.com/go/gsuiteaddons v1.6.5 h1:CZEbaBwmbYdhFw21Fwbo+C35HMe36fTE0FBSR4KSfWg= cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/iap v1.9.3 h1:M4vDbQ4TLXdaljXVZSwW7XtxpwXUUarY2lIs66m0aCM= cloud.google.com/go/iap v1.9.3/go.mod h1:DTdutSZBqkkOm2HEOTBzhZxh2mwwxshfD/h3yofAiCw= +cloud.google.com/go/iap v1.9.4 h1:94zirc2r4t6KzhAMW0R6Dme005eTP6yf7g6vN4IhRrA= cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= cloud.google.com/go/ids v1.4.4 h1:VuFqv2ctf/A7AyKlNxVvlHTzjrEvumWaZflUzBPz/M4= cloud.google.com/go/ids v1.4.4/go.mod h1:z+WUc2eEl6S/1aZWzwtVNWoSZslgzPxAboS0lZX0HjI= +cloud.google.com/go/ids v1.4.5 h1:xd4U7pgl3GHV+MABnv1BF4/Vy/zBF7CYC8XngkOLzag= cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= cloud.google.com/go/iot v1.7.4 h1:m1WljtkZnvLTIRYW1YTOv5A6H1yKgLHR6nU7O8yf27w= cloud.google.com/go/iot v1.7.4/go.mod h1:3TWqDVvsddYBG++nHSZmluoCAVGr1hAcabbWZNKEZLk= +cloud.google.com/go/iot v1.7.5 h1:munTeBlbqI33iuTYgXy7S8lW2TCgi5l1hA4roSIY+EE= cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= cloud.google.com/go/kms v1.15.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= cloud.google.com/go/language v1.12.2 h1:zg9uq2yS9PGIOdc0Kz/l+zMtOlxKWonZjjo5w5YPG2A= cloud.google.com/go/language v1.12.2/go.mod h1:9idWapzr/JKXBBQ4lWqVX/hcadxB194ry20m/bTrhWc= +cloud.google.com/go/language v1.12.3 h1:iaJZg6K4j/2PvZZVcjeO/btcWWIllVRBhuTFjGO4LXs= cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= cloud.google.com/go/lifesciences v0.9.4 h1:rZEI/UxcxVKEzyoRS/kdJ1VoolNItRWjNN0Uk9tfexg= cloud.google.com/go/lifesciences v0.9.4/go.mod h1:bhm64duKhMi7s9jR9WYJYvjAFJwRqNj+Nia7hF0Z7JA= +cloud.google.com/go/lifesciences v0.9.5 h1:gXvN70m2p+4zgJFzaz6gMKaxTuF9WJ0USYoMLWAOm8g= cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= cloud.google.com/go/logging v1.8.1 h1:26skQWPeYhvIasWKm48+Eq7oUqdcdbwsCVwz5Ys0FvU= cloud.google.com/go/logging v1.8.1/go.mod h1:TJjR+SimHwuC8MZ9cjByQulAMgni+RkXeI3wwctHJEI= +cloud.google.com/go/logging v1.9.0 h1:iEIOXFO9EmSiTjDmfpbRjOxECO7R8C7b8IXUGOj7xZw= cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= cloud.google.com/go/managedidentities v1.6.4 h1:SF/u1IJduMqQQdJA4MDyivlIQ4SrV5qAawkr/ZEREkY= cloud.google.com/go/managedidentities v1.6.4/go.mod h1:WgyaECfHmF00t/1Uk8Oun3CQ2PGUtjc3e9Alh79wyiM= +cloud.google.com/go/managedidentities v1.6.5 h1:+bpih1piZVLxla/XBqeSUzJBp8gv9plGHIMAI7DLpDM= cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= cloud.google.com/go/maps v1.6.1 h1:2+eMp/1MvMPp5qrSOd3vtnLKa/pylt+krVRqET3jWsM= cloud.google.com/go/maps v1.6.1/go.mod h1:4+buOHhYXFBp58Zj/K+Lc1rCmJssxxF4pJ5CJnhdz18= +cloud.google.com/go/maps v1.6.4 h1:EVCZAiDvog9So46460BGbCasPhi613exoaQbpilMVlk= cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= cloud.google.com/go/mediatranslation v0.8.4 h1:VRCQfZB4s6jN0CSy7+cO3m4ewNwgVnaePanVCQh/9Z4= cloud.google.com/go/mediatranslation v0.8.4/go.mod h1:9WstgtNVAdN53m6TQa5GjIjLqKQPXe74hwSCxUP6nj4= +cloud.google.com/go/mediatranslation v0.8.5 h1:c76KdIXljQHSCb/Cy47S8H4s05A4zbK3pAFGzwcczZo= cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= cloud.google.com/go/memcache v1.10.4 h1:cdex/ayDd294XBj2cGeMe6Y+H1JvhN8y78B9UW7pxuQ= cloud.google.com/go/memcache v1.10.4/go.mod h1:v/d8PuC8d1gD6Yn5+I3INzLR01IDn0N4Ym56RgikSI0= +cloud.google.com/go/memcache v1.10.5 h1:yeDv5qxRedFosvpMSEswrqUsJM5OdWvssPHFliNFTc4= cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= cloud.google.com/go/metastore v1.13.3 h1:94l/Yxg9oBZjin2bzI79oK05feYefieDq0o5fjLSkC8= cloud.google.com/go/metastore v1.13.3/go.mod h1:K+wdjXdtkdk7AQg4+sXS8bRrQa9gcOr+foOMF2tqINE= +cloud.google.com/go/metastore v1.13.4 h1:dR7vqWXlK6IYR8Wbu9mdFfwlVjodIBhd1JRrpZftTEg= cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= cloud.google.com/go/monitoring v1.16.3 h1:mf2SN9qSoBtIgiMA4R/y4VADPWZA7VCNJA079qLaZQ8= cloud.google.com/go/monitoring v1.16.3/go.mod h1:KwSsX5+8PnXv5NJnICZzW2R8pWTis8ypC4zmdRD63Tw= +cloud.google.com/go/monitoring v1.18.0 h1:NfkDLQDG2UR3WYZVQE8kwSbUIEyIqJUPl+aOQdFH1T4= cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= cloud.google.com/go/networkconnectivity v1.14.3 h1:e9lUkCe2BexsqsUc2bjV8+gFBpQa54J+/F3qKVtW+wA= cloud.google.com/go/networkconnectivity v1.14.3/go.mod h1:4aoeFdrJpYEXNvrnfyD5kIzs8YtHg945Og4koAjHQek= +cloud.google.com/go/networkconnectivity v1.14.4 h1:GBfXFhLyPspnaBE3nI/BRjdhW8vcbpT9QjE/4kDCDdc= cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= cloud.google.com/go/networkmanagement v1.9.3 h1:HsQk4FNKJUX04k3OI6gUsoveiHMGvDRqlaFM2xGyvqU= cloud.google.com/go/networkmanagement v1.9.3/go.mod h1:y7WMO1bRLaP5h3Obm4tey+NquUvB93Co1oh4wpL+XcU= +cloud.google.com/go/networkmanagement v1.9.4 h1:aLV5GcosBNmd6M8+a0ekB0XlLRexv4fvnJJrYnqeBcg= cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= cloud.google.com/go/networksecurity v0.9.4 h1:947tNIPnj1bMGTIEBo3fc4QrrFKS5hh0bFVsHmFm4Vo= cloud.google.com/go/networksecurity v0.9.4/go.mod h1:E9CeMZ2zDsNBkr8axKSYm8XyTqNhiCHf1JO/Vb8mD1w= +cloud.google.com/go/networksecurity v0.9.5 h1:+caSxBTj0E8OYVh/5wElFdjEMO1S/rZtE1152Cepchc= cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= cloud.google.com/go/notebooks v1.11.2 h1:eTOTfNL1yM6L/PCtquJwjWg7ZZGR0URFaFgbs8kllbM= cloud.google.com/go/notebooks v1.11.2/go.mod h1:z0tlHI/lREXC8BS2mIsUeR3agM1AkgLiS+Isov3SS70= +cloud.google.com/go/notebooks v1.11.3 h1:FH48boYmrWVQ6k0Mx/WrnNafXncT5iSYxA8CNyWTgy0= cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= cloud.google.com/go/optimization v1.6.2 h1:iFsoexcp13cGT3k/Hv8PA5aK+FP7FnbhwDO9llnruas= cloud.google.com/go/optimization v1.6.2/go.mod h1:mWNZ7B9/EyMCcwNl1frUGEuY6CPijSkz88Fz2vwKPOY= +cloud.google.com/go/optimization v1.6.3 h1:63NZaWyN+5rZEKHPX4ACpw3BjgyeuY8+rCehiCMaGPY= cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= cloud.google.com/go/orchestration v1.8.4 h1:kgwZ2f6qMMYIVBtUGGoU8yjYWwMTHDanLwM/CQCFaoQ= cloud.google.com/go/orchestration v1.8.4/go.mod h1:d0lywZSVYtIoSZXb0iFjv9SaL13PGyVOKDxqGxEf/qI= +cloud.google.com/go/orchestration v1.8.5 h1:YHgWMlrPttIVGItgGfuvO2KM7x+y9ivN/Yk92pMm1a4= cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= cloud.google.com/go/orgpolicy v1.11.4 h1:RWuXQDr9GDYhjmrredQJC7aY7cbyqP9ZuLbq5GJGves= cloud.google.com/go/orgpolicy v1.11.4/go.mod h1:0+aNV/nrfoTQ4Mytv+Aw+stBDBjNf4d8fYRA9herfJI= +cloud.google.com/go/orgpolicy v1.12.1 h1:2JbXigqBJVp8Dx5dONUttFqewu4fP0p3pgOdIZAhpYU= cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= cloud.google.com/go/osconfig v1.12.4 h1:OrRCIYEAbrbXdhm13/JINn9pQchvTTIzgmOCA7uJw8I= cloud.google.com/go/osconfig v1.12.4/go.mod h1:B1qEwJ/jzqSRslvdOCI8Kdnp0gSng0xW4LOnIebQomA= +cloud.google.com/go/osconfig v1.12.5 h1:Mo5jGAxOMKH/PmDY7fgY19yFcVbvwREb5D5zMPQjFfo= cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= cloud.google.com/go/oslogin v1.12.2 h1:NP/KgsD9+0r9hmHC5wKye0vJXVwdciv219DtYKYjgqE= cloud.google.com/go/oslogin v1.12.2/go.mod h1:CQ3V8Jvw4Qo4WRhNPF0o+HAM4DiLuE27Ul9CX9g2QdY= +cloud.google.com/go/oslogin v1.13.1 h1:1K4nOT5VEZNt7XkhaTXupBYos5HjzvJMfhvyD2wWdFs= cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= cloud.google.com/go/phishingprotection v0.8.4 h1:sPLUQkHq6b4AL0czSJZ0jd6vL55GSTHz2B3Md+TCZI0= cloud.google.com/go/phishingprotection v0.8.4/go.mod h1:6b3kNPAc2AQ6jZfFHioZKg9MQNybDg4ixFd4RPZZ2nE= +cloud.google.com/go/phishingprotection v0.8.5 h1:DH3WFLzEoJdW/6xgsmoDqOwT1xddFi7gKu0QGZQhpGU= cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= cloud.google.com/go/policytroubleshooter v1.10.2 h1:sq+ScLP83d7GJy9+wpwYJVnY+q6xNTXwOdRIuYjvHT4= cloud.google.com/go/policytroubleshooter v1.10.2/go.mod h1:m4uF3f6LseVEnMV6nknlN2vYGRb+75ylQwJdnOXfnv0= +cloud.google.com/go/policytroubleshooter v1.10.3 h1:c0WOzC6hz964QWNBkyKfna8A2jOIx1zzZa43Gx/P09o= cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= cloud.google.com/go/privatecatalog v0.9.4 h1:Vo10IpWKbNvc/z/QZPVXgCiwfjpWoZ/wbgful4Uh/4E= cloud.google.com/go/privatecatalog v0.9.4/go.mod h1:SOjm93f+5hp/U3PqMZAHTtBtluqLygrDrVO8X8tYtG0= +cloud.google.com/go/privatecatalog v0.9.5 h1:UZ0assTnATXSggoxUIh61RjTQ4P9zCMk/kEMbn0nMYA= cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= @@ -287,56 +369,73 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= cloud.google.com/go/pubsublite v1.8.1 h1:pX+idpWMIH30/K7c0epN6V703xpIcMXWRjKJsz0tYGY= cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= cloud.google.com/go/recaptchaenterprise/v2 v2.8.4 h1:KOlLHLv3h3HwcZAkx91ubM3Oztz3JtT3ZacAJhWDorQ= cloud.google.com/go/recaptchaenterprise/v2 v2.8.4/go.mod h1:Dak54rw6lC2gBY8FBznpOCAR58wKf+R+ZSJRoeJok4w= +cloud.google.com/go/recaptchaenterprise/v2 v2.9.2 h1:U3Wfq12X9cVMuTpsWDSURnXF0Z9hSPTHj+xsnXDRLsw= cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= cloud.google.com/go/recommendationengine v0.8.4 h1:JRiwe4hvu3auuh2hujiTc2qNgPPfVp+Q8KOpsXlEzKQ= cloud.google.com/go/recommendationengine v0.8.4/go.mod h1:GEteCf1PATl5v5ZsQ60sTClUE0phbWmo3rQ1Js8louU= +cloud.google.com/go/recommendationengine v0.8.5 h1:ineqLswaCSBY0csYv5/wuXJMBlxATK6Xc5jJkpiTEdM= cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= cloud.google.com/go/recommender v1.11.3 h1:VndmgyS/J3+izR8V8BHa7HV/uun8//ivQ3k5eVKKyyM= cloud.google.com/go/recommender v1.11.3/go.mod h1:+FJosKKJSId1MBFeJ/TTyoGQZiEelQQIZMKYYD8ruK4= +cloud.google.com/go/recommender v1.12.1 h1:LVLYS3r3u0MSCxQSDUtLSkporEGi9OAE6hGvayrZNPs= cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= cloud.google.com/go/redis v1.14.1 h1:J9cEHxG9YLmA9o4jTSvWt/RuVEn6MTrPlYSCRHujxDQ= cloud.google.com/go/redis v1.14.1/go.mod h1:MbmBxN8bEnQI4doZPC1BzADU4HGocHBk2de3SbgOkqs= +cloud.google.com/go/redis v1.14.2 h1:QF0maEdVv0Fj/2roU8sX3NpiDBzP9ICYTO+5F32gQNo= cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= cloud.google.com/go/resourcemanager v1.9.4 h1:JwZ7Ggle54XQ/FVYSBrMLOQIKoIT/uer8mmNvNLK51k= cloud.google.com/go/resourcemanager v1.9.4/go.mod h1:N1dhP9RFvo3lUfwtfLWVxfUWq8+KUQ+XLlHLH3BoFJ0= +cloud.google.com/go/resourcemanager v1.9.5 h1:AZWr1vWVDKGwfLsVhcN+vcwOz3xqqYxtmMa0aABCMms= cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= cloud.google.com/go/resourcesettings v1.6.4 h1:yTIL2CsZswmMfFyx2Ic77oLVzfBFoWBYgpkgiSPnC4Y= cloud.google.com/go/resourcesettings v1.6.4/go.mod h1:pYTTkWdv2lmQcjsthbZLNBP4QW140cs7wqA3DuqErVI= +cloud.google.com/go/resourcesettings v1.6.5 h1:BTr5MVykJwClASci/7Og4Qfx70aQ4n3epsNLj94ZYgw= cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= cloud.google.com/go/retail v1.14.4 h1:geqdX1FNqqL2p0ADXjPpw8lq986iv5GrVcieTYafuJQ= cloud.google.com/go/retail v1.14.4/go.mod h1:l/N7cMtY78yRnJqp5JW8emy7MB1nz8E4t2yfOmklYfg= +cloud.google.com/go/retail v1.16.0 h1:Fn1GuAua1c6crCGqfJ1qMxG1Xh10Tg/x5EUODEHMqkw= cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= cloud.google.com/go/run v1.3.3 h1:qdfZteAm+vgzN1iXzILo3nJFQbzziudkJrvd9wCf3FQ= cloud.google.com/go/run v1.3.3/go.mod h1:WSM5pGyJ7cfYyYbONVQBN4buz42zFqwG67Q3ch07iK4= +cloud.google.com/go/run v1.3.4 h1:m9WDA7DzTpczhZggwYlZcBWgCRb+kgSIisWn1sbw2rQ= cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= cloud.google.com/go/scheduler v1.10.5 h1:eMEettHlFhG5pXsoHouIM5nRT+k+zU4+GUvRtnxhuVI= cloud.google.com/go/scheduler v1.10.5/go.mod h1:MTuXcrJC9tqOHhixdbHDFSIuh7xZF2IysiINDuiq6NI= +cloud.google.com/go/scheduler v1.10.6 h1:5U8iXLoQ03qOB+ZXlAecU7fiE33+u3QiM9nh4cd0eTE= cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= cloud.google.com/go/secretmanager v1.11.4 h1:krnX9qpG2kR2fJ+u+uNyNo+ACVhplIAS4Pu7u+4gd+k= cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= +cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/security v1.15.4 h1:sdnh4Islb1ljaNhpIXlIPgb3eYj70QWgPVDKOUYvzJc= cloud.google.com/go/security v1.15.4/go.mod h1:oN7C2uIZKhxCLiAAijKUCuHLZbIt/ghYEo8MqwD/Ty4= +cloud.google.com/go/security v1.15.5 h1:wTKJQ10j8EYgvE8Y+KhovxDRVDk2iv/OsxZ6GrLP3kE= cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= cloud.google.com/go/securitycenter v1.24.2 h1:qCEyXoJoxNKKA1bDywBjjqCB7ODXazzHnVWnG5Uqd1M= cloud.google.com/go/securitycenter v1.24.2/go.mod h1:l1XejOngggzqwr4Fa2Cn+iWZGf+aBLTXtB/vXjy5vXM= +cloud.google.com/go/securitycenter v1.24.4 h1:/5jjkZ+uGe8hZ7pvd7pO30VW/a+pT2MrrdgOqjyucKQ= cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= cloud.google.com/go/servicedirectory v1.11.3 h1:5niCMfkw+jifmFtbBrtRedbXkJm3fubSR/KHbxSJZVM= cloud.google.com/go/servicedirectory v1.11.3/go.mod h1:LV+cHkomRLr67YoQy3Xq2tUXBGOs5z5bPofdq7qtiAw= +cloud.google.com/go/servicedirectory v1.11.4 h1:da7HFI1229kyzIyuVEzHXip0cw0d+E0s8mjQby0WN+k= cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= cloud.google.com/go/shell v1.7.4 h1:nurhlJcSVFZneoRZgkBEHumTYf/kFJptCK2eBUq/88M= cloud.google.com/go/shell v1.7.4/go.mod h1:yLeXB8eKLxw0dpEmXQ/FjriYrBijNsONpwnWsdPqlKM= +cloud.google.com/go/shell v1.7.5 h1:3Fq2hzO0ZSyaqBboJrFkwwf/qMufDtqwwA6ep8EZxEI= cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= cloud.google.com/go/spanner v1.53.0 h1:/NzWQJ1MEhdRcffiutRKbW/AIGVKhcTeivWTDjEyCCo= cloud.google.com/go/spanner v1.53.0/go.mod h1:liG4iCeLqm5L3fFLU5whFITqP0e0orsAW1uUSrd4rws= +cloud.google.com/go/spanner v1.56.0 h1:o/Cv7/zZ1WgRXVCd5g3Nc23ZI39p/1pWFqFwvg6Wcu8= cloud.google.com/go/spanner v1.56.0/go.mod h1:DndqtUKQAt3VLuV2Le+9Y3WTnq5cNKrnLb/Piqcj+h0= cloud.google.com/go/speech v1.21.0 h1:qkxNao58oF8ghAHE1Eghen7XepawYEN5zuZXYWaUTA4= cloud.google.com/go/speech v1.21.0/go.mod h1:wwolycgONvfz2EDU8rKuHRW3+wc9ILPsAWoikBEWavY= +cloud.google.com/go/speech v1.21.1 h1:nuFc+Kj5B8de75nN4FdPyUbI2SiBoHZG6BLurXL56Q0= cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= @@ -345,51 +444,67 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= cloud.google.com/go/storagetransfer v1.10.3 h1:YM1dnj5gLjfL6aDldO2s4GeU8JoAvH1xyIwXre63KmI= cloud.google.com/go/storagetransfer v1.10.3/go.mod h1:Up8LY2p6X68SZ+WToswpQbQHnJpOty/ACcMafuey8gc= +cloud.google.com/go/storagetransfer v1.10.4 h1:dy4fL3wO0VABvzM05ycMUPFHxTPbJz9Em8ikAJVqSbI= cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= cloud.google.com/go/talent v1.6.5 h1:LnRJhhYkODDBoTwf6BeYkiJHFw9k+1mAFNyArwZUZAs= cloud.google.com/go/talent v1.6.5/go.mod h1:Mf5cma696HmE+P2BWJ/ZwYqeJXEeU0UqjHFXVLadEDI= +cloud.google.com/go/talent v1.6.6 h1:JssV0CE3FNujuSWn7SkosOzg7qrMxVnt6txOfGcMSa4= cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= cloud.google.com/go/texttospeech v1.7.4 h1:ahrzTgr7uAbvebuhkBAAVU6kRwVD0HWsmDsvMhtad5Q= cloud.google.com/go/texttospeech v1.7.4/go.mod h1:vgv0002WvR4liGuSd5BJbWy4nDn5Ozco0uJymY5+U74= +cloud.google.com/go/texttospeech v1.7.5 h1:dxY2Q5mHCbrGa3oPR2O3PCicdnvKa1JmwGQK36EFLOw= cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= cloud.google.com/go/tpu v1.6.4 h1:XIEH5c0WeYGaVy9H+UueiTaf3NI6XNdB4/v6TFQJxtE= cloud.google.com/go/tpu v1.6.4/go.mod h1:NAm9q3Rq2wIlGnOhpYICNI7+bpBebMJbh0yyp3aNw1Y= +cloud.google.com/go/tpu v1.6.5 h1:C8YyYda8WtNdBoCgFwwBzZd+S6+EScHOxM/z1h0NNp8= cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= cloud.google.com/go/trace v1.10.4 h1:2qOAuAzNezwW3QN+t41BtkDJOG42HywL73q8x/f6fnM= cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGmE6TXNWY= +cloud.google.com/go/trace v1.10.5 h1:0pr4lIKJ5XZFYD9GtxXEWr0KkVeigc3wlGpZco0X1oA= cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= cloud.google.com/go/translate v1.9.3 h1:t5WXTqlrk8VVJu/i3WrYQACjzYJiff5szARHiyqqPzI= cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0= +cloud.google.com/go/translate v1.10.1 h1:upovZ0wRMdzZvXnu+RPam41B0mRJ+coRXFP2cYFJ7ew= cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= cloud.google.com/go/video v1.20.3 h1:Xrpbm2S9UFQ1pZEeJt9Vqm5t2T/z9y/M3rNXhFoo8Is= cloud.google.com/go/video v1.20.3/go.mod h1:TnH/mNZKVHeNtpamsSPygSR0iHtvrR/cW1/GDjN5+GU= +cloud.google.com/go/video v1.20.4 h1:TXwotxkShP1OqgKsbd+b8N5hrIHavSyLGvYnLGCZ7xc= cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= cloud.google.com/go/videointelligence v1.11.4 h1:YS4j7lY0zxYyneTFXjBJUj2r4CFe/UoIi/PJG0Zt/Rg= cloud.google.com/go/videointelligence v1.11.4/go.mod h1:kPBMAYsTPFiQxMLmmjpcZUMklJp3nC9+ipJJtprccD8= +cloud.google.com/go/videointelligence v1.11.5 h1:mYaWH8uhUCXLJCN3gdXswKzRa2+lK0zN6/KsIubm6pE= cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= cloud.google.com/go/vision/v2 v2.7.5 h1:T/ujUghvEaTb+YnFY/jiYwVAkMbIC8EieK0CJo6B4vg= cloud.google.com/go/vision/v2 v2.7.5/go.mod h1:GcviprJLFfK9OLf0z8Gm6lQb6ZFUulvpZws+mm6yPLM= +cloud.google.com/go/vision/v2 v2.8.0 h1:W52z1b6LdGI66MVhE70g/NFty9zCYYcjdKuycqmlhtg= cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= cloud.google.com/go/vmmigration v1.7.4 h1:qPNdab4aGgtaRX+51jCOtJxlJp6P26qua4o1xxUDjpc= cloud.google.com/go/vmmigration v1.7.4/go.mod h1:yBXCmiLaB99hEl/G9ZooNx2GyzgsjKnw5fWcINRgD70= +cloud.google.com/go/vmmigration v1.7.5 h1:5v9RT2vWyuw3pK2ox0HQpkoftO7Q7/8591dTxxQc79g= cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= cloud.google.com/go/vmwareengine v1.0.3 h1:WY526PqM6QNmFHSqe2sRfK6gRpzWjmL98UFkql2+JDM= cloud.google.com/go/vmwareengine v1.0.3/go.mod h1:QSpdZ1stlbfKtyt6Iu19M6XRxjmXO+vb5a/R6Fvy2y4= +cloud.google.com/go/vmwareengine v1.1.1 h1:EGdDi9QbqThfZq3ILcDK5g+m9jTevc34AY5tACx5v7k= cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= cloud.google.com/go/vpcaccess v1.7.4 h1:zbs3V+9ux45KYq8lxxn/wgXole6SlBHHKKyZhNJoS+8= cloud.google.com/go/vpcaccess v1.7.4/go.mod h1:lA0KTvhtEOb/VOdnH/gwPuOzGgM+CWsmGu6bb4IoMKk= +cloud.google.com/go/vpcaccess v1.7.5 h1:XyL6hTLtEM/eE4F1GEge8xUN9ZCkiVWn44K/YA7z1rQ= cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= cloud.google.com/go/webrisk v1.9.4 h1:iceR3k0BCRZgf2D/NiKviVMFfuNC9LmeNLtxUFRB/wI= cloud.google.com/go/webrisk v1.9.4/go.mod h1:w7m4Ib4C+OseSr2GL66m0zMBywdrVNTDKsdEsfMl7X0= +cloud.google.com/go/webrisk v1.9.5 h1:251MvGuC8wisNN7+jqu9DDDZAi38KiMXxOpA/EWy4dE= cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= cloud.google.com/go/websecurityscanner v1.6.4 h1:5Gp7h5j7jywxLUp6NTpjNPkgZb3ngl0tUSw6ICWvtJQ= cloud.google.com/go/websecurityscanner v1.6.4/go.mod h1:mUiyMQ+dGpPPRkHgknIZeCzSHJ45+fY4F52nZFDHm2o= +cloud.google.com/go/websecurityscanner v1.6.5 h1:YqWZrZYabG88TZt7364XWRJGhxmxhony2ZUyZEYMF2k= cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= cloud.google.com/go/workflows v1.12.3 h1:qocsqETmLAl34mSa01hKZjcqAvt699gaoFbooGGMvaM= cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= +cloud.google.com/go/workflows v1.12.4 h1:uHNmUiatTbPQ4H1pabwfzpfEYD4BBnqDHqMm2IesOh4= cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= collectd.org v0.3.0 h1:iNBHGw1VvPJxH2B6RiFWFZ+vsjo1lCdRszBeOuwGi00= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= @@ -400,16 +515,21 @@ github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.0 h1:Ut0ZGdOwJDw0npYEg+TLlPls3Pq6JiZaP2/aGKir7Zw= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 h1:gggzg0SUMs6SQbEw+3LoSsYf9YMjkupeAnHMX8O9mmY= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= github.com/Azure/azure-storage-blob-go v0.7.0 h1:MuueVOYkufCxJw5YZzF842DY2MBsp+hLuh2apKY0mck= github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= @@ -427,14 +547,19 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/AzureAD/microsoft-authentication-library-for-go v0.6.0 h1:XMEdVDFxgulDDl0lQmAZS6j8gRQ/0pJ+ZpXH2FHVtDc= github.com/AzureAD/microsoft-authentication-library-for-go v0.6.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v6 v6.1.0 h1:hvO96X345XagdH1fAoBjpBYG4a1ghhL/QzalkduPuXk= github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -445,11 +570,11 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794 h1:xlwdaKcTNVW4PtpQb8aKA4Pjy0CdJHEqvFbAnvR5m2g= github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY= github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= @@ -463,6 +588,7 @@ github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxk github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= @@ -478,6 +604,7 @@ github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db h1:nxAtV4Vaj github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc= github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= +github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw= github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= @@ -490,8 +617,10 @@ github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloD github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -514,14 +643,18 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24 h1:i4RH8DLv/BHY0 github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.24/go.mod h1:N8X45/o2cngvjCYi2ZnvI0P4mU4ZRJfEYC3maCSsPyw= github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1 h1:cKr6St+CtC3/dl/rEBJvlk7A/IN5D5F02GNkGzfbtVU= github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= +github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 h1:/RPQNjh1sDIezpXaFIkZb7MlXnSyAqjVdAwcJuGYTqg= github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2/go.mod h1:TQZBt/WaQy+zTHoW++rnl8JBrmZ0VO6EUbVua1+foCA= github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6 h1:zzTm99krKsFcF4N7pu2z17yCcAZpQYZ7jnJZPIgEMXE= github.com/aws/aws-sdk-go-v2/service/s3 v1.30.6/go.mod h1:PudwVKUTApfm0nYaPutOXaKdPKTlZYClGBQpVIRdcbs= github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= @@ -535,6 +668,7 @@ github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= @@ -552,22 +686,28 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/logex v1.2.0 h1:+eqR0HfOetur4tgnC8ftU5imRnhi4te+BadWS95c5AM= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/readline v1.5.0 h1:lSwwFrbNviGePhkewF1az4oLmcwqCZijQ2/Wi3BGHAI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v0.0.0-20210722231415-061457976a23 h1:dZ0/VyGgQdVGAss6Ju0dt5P0QltE0SFY5Woh6hbIfiQ= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a h1:8d1CEOF1xldesKds5tRG3tExBsMOgWYownMHNCsev54= github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= github.com/cloudflare/cloudflare-go v0.14.0 h1:gFqGlGl/5f9UGXAaKapCGUfaTCgRKKnzu2VvzMZlOFA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= +github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M= github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= github.com/cloudflare/redoctober v0.0.0-20211013234631-6a74ccc611f6 h1:QKzett0dn5FhjcIHNKSClEilabfhWCnsdijq3ftm9Ms= github.com/cloudflare/redoctober v0.0.0-20211013234631-6a74ccc611f6/go.mod h1:Ikt4Wfpln1YOrak+auA8BNxgiilj0Y2y7nO+aN2eMzk= @@ -575,8 +715,11 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2 h1:IKgmqgMQlVJIZj19CdocBeSfSaiCbEBZGKODaixqtHM= github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/compose-spec/compose-go v1.20.0 h1:h4ZKOst1EF/DwZp7dWkb+wbTVE4nEyT9Lc89to84Ol4= github.com/compose-spec/compose-go v1.20.0/go.mod h1:+MdqXV4RA7wdFsahh/Kb8U0pAJqkg7mr4PM9tFKU8RM= @@ -622,6 +765,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80 h1:DuBDHVjgGMPki7bAyh91+3cF1Vh34sAEdH8JQgbc2R0= github.com/crate-crypto/go-ipa v0.0.0-20230601170251-1830d0757c80/go.mod h1:gzbVz57IDJgQ9rLQwfSk696JGWof8ftznEL9GoAv3NI= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c h1:/ovYnF02fwL0kvspmy9AuyKg1JhdTRUgPw4nUxd9oZM= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -645,7 +789,9 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli-docs-tool v0.6.0 h1:Z9x10SaZgFaB6jHgz3OWooynhSa40CsWkpe5hEnG/qA= github.com/docker/cli-docs-tool v0.6.0/go.mod h1:zMjqTFCU361PRh8apiXzeAZ1Q/xupbIwTusYpzCXS/o= @@ -657,18 +803,23 @@ github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRP github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5RVoRccG8a5DhOdWdQ4zN62zzo= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7 h1:tYwu/z8Y0NkkzGEh3z21mSWggMg4LwLRFucLS7TjARg= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d h1:W1n4DvpzZGOISgp7wWNtraLcHtnmnTwBlJidqtMIuwQ= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae h1:UTOyRlLeWJrZx+ynml6q6qzZ1uDkJe/0Z5CMZRbEIJg= github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/ethereum/c-kzg-4844/bindings/go v0.0.0-20230126171313-363c7d7593b4 h1:B2mpK+MNqgPqk2/KNi1LbqwtZDy5F7iy0mynQiBr8VA= @@ -681,12 +832,16 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= +github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90 h1:WXb3TSNmHp2vHoCroCIB1foO/yQ36swABL8aOVeDpgg= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -696,12 +851,15 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 h1:IZqZOB2fydHte3kUgxrzK5E1fW7RQGeDwE8F/ZZnUYc= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b h1:vMT47RYsrftsHSTQhqXwC3BYflo38OLC3Y4LtXtLyU0= github.com/gballet/go-verkle v0.0.0-20230607174250-df487255f46b/go.mod h1:CDncRYVRSDqwakm282WEkjfaAj1hxU/v5RXxk5nXOiI= +github.com/getkin/kin-openapi v0.53.0 h1:7WzP+MZRRe7YQz2Kc74Ley3dukJmXDvifVbElGmQfoA= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0 h1:6awGqF5nG5zkVpMsAih1QH4VgzS8phTxECUWIFo7zko= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9 h1:r5GgOLGbza2wVHRzK7aAj6lWZjfbAwiu/RDCVOKjRyM= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04MMPyLHj/QwZuMJ5+7tJcBr1AQjpiAK/rZWRrQT7o= @@ -714,6 +872,7 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -722,6 +881,7 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= @@ -735,6 +895,7 @@ github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/status v1.1.0 h1:+eIkrewn5q6b30y+g/BJINVVdi2xH7je5MPJ3ZPK3JA= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -773,6 +934,7 @@ github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25ol github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -782,7 +944,9 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw= github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk= +github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9 h1:OF1IPgv+F4NmqmJ98KTjdN97Vs1JxDPB3vbmYzV2dpk= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= @@ -817,8 +981,11 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gotestyourself/gotestyourself v1.4.0 h1:CDSlSIuRL/Fsc72Ln5lMybtrCvSRDddsHsDRG/nP7Rg= @@ -832,51 +999,69 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/guptarohit/asciigraph v0.5.5 h1:ccFnUF8xYIOUPPY3tmdvRyHqmn1MYI9iv1pLKX+/ZkQ= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= github.com/hanwen/go-fuse/v2 v2.2.0 h1:jo5QZYmBLNcl9ovypWaQ5yXMSSV+Ch68xoC3rtZvvBM= github.com/hanwen/go-fuse/v2 v2.2.0/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc= +github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992 h1:fYOrSfO5C9PmFGtmRWSYGqq52SOoE2dXMtAn2Xzh1LQ= github.com/hashicorp/go-cty-funcs v0.0.0-20230405223818-a090f58aa992/go.mod h1:Abjk0jbRkDaNCzsRhOv2iDCofYpX1eVsjozoiK63qLA= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/hydrogen18/memlistener v1.0.0 h1:JR7eDj8HD6eXrc5fWLbSUnfcQFL06PYvCc0DKQnWfaU= github.com/hydrogen18/memlistener v1.0.0/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 h1:rcanfLhLDA8nozr/K289V1zcntHr3V+SHlXwzz1ZI2g= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= github.com/influxdata/flux v0.65.1 h1:77BcVUCzvN5HMm8+j9PRBQ4iZcu98Dl4Y9rf+J5vhnc= @@ -904,11 +1089,14 @@ github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368 h1:+TUUmaF github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= github.com/intel/goresctrl v0.3.0 h1:K2D3GOzihV7xSBedGxONSlaw/un1LZgWsc9IfqipN4c= github.com/intel/goresctrl v0.3.0/go.mod h1:fdz3mD85cmP9sHD8JUlrNWAxvwM86CrbmVXltEKd7zk= +github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0= github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= +github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89 h1:12K8AlpT0/6QUXSfV0yi4Q0jkbq8NDtIKFtF61AoqV0= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -939,12 +1127,19 @@ github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559 h1:0VWDXPNE0brOek1Q8b github.com/karalabe/usb v0.0.0-20211005121534-4c5740d64559/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4= github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/golog v0.1.7 h1:0TY5tHn5L5DlRIikepcaRR/6oInIr9AiWsxzt0vvlBE= github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA= +github.com/kataras/iris/v12 v12.2.0-beta5 h1:grB/oCf5baZhmYIeDMfgN3LYrtEcmK8pbxlRvEZ2pgw= github.com/kataras/iris/v12 v12.2.0-beta5/go.mod h1:q26aoWJ0Knx/00iPKg5iizDK7oQQSPjbD8np0XDh6dc= +github.com/kataras/pio v0.0.11 h1:kqreJ5KOEXGMwHAWHDwIl+mjfNCPhAwZPa8gK7MKlyw= github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= +github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY= github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= +github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= @@ -964,7 +1159,9 @@ github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada h1:3L+neHp83cTje github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= @@ -972,9 +1169,11 @@ github.com/kylelemons/go-gypsy v1.0.0 h1:7/wQ7A3UL1bnqRMnZ6T8cwCOArfZCxFmb1iTxaO github.com/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU= github.com/labstack/echo/v4 v4.2.1 h1:LF5Iq7t/jrtUuSutNuiEWtB5eiHfZ5gSe2pcu5exjQw= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= @@ -991,7 +1190,9 @@ github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmt github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3 h1:jUp75lepDg0phMUJBCmvaeFDldD2N3S1lBuPwUTszio= github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailgun/raymond/v2 v2.0.46 h1:aOYHhvTpF5USySJ0o7cpPno/Uh2I5qg2115K25A+Ft4= github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd h1:HvFwW+cm9bCbZ/+vuGNq7CRWXql8c0y8nGeYpqmpvmk= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -1018,10 +1219,12 @@ github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104 h1:d8RFOZ2IiFtFWBcKEH github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= @@ -1031,6 +1234,7 @@ github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPnkFiU= github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k= +github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1054,8 +1258,11 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0= github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk= github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= @@ -1074,6 +1281,7 @@ github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o= github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= @@ -1088,17 +1296,21 @@ github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= +github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5 h1:tFwafIEMf0B7NlcxV/zJ6leBIa81D3hgGSgsE5hCkOQ= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -1112,6 +1324,7 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= +github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7 h1:cZC+usqsYgHtlBaGulVnZ1hfKAi8iWtujBnRLQE698c= github.com/protolambda/bls12-381-util v0.0.0-20220416220906-d8552aa452c7/go.mod h1:IToEjHuttnUzwZI5KBSM/LOOW3qLbbrHOEfp3SbECGY= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -1123,8 +1336,11 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.19.0 h1:WMyLTjHBo64UvNcWqpzY3pbZTYgnemZU8FBZigKc42E= github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78= +github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/scroll-tech/da-codec v0.0.0-20240605080813-32bfc9fccde7/go.mod h1:1wWYii0OPwd5kw+xrz0PFgS420xNadrNF1x/ELJT+TM= github.com/scroll-tech/da-codec v0.0.0-20241006192342-95d2bc79b7e8/go.mod h1:6jxEQvNc7GQKMSUi25PthAUY3WnZL8CN0yWivBgAXi0= @@ -1142,8 +1358,7 @@ github.com/scroll-tech/da-codec v0.1.1-0.20241014152913-2703f226fb0b/go.mod h1:4 github.com/scroll-tech/go-ethereum v1.10.14-0.20240607130425-e2becce6a1a4/go.mod h1:byf/mZ8jLYUCnUePTicjJWn+RvKdxDn7buS6glTnMwQ= github.com/scroll-tech/go-ethereum v1.10.14-0.20240821074444-b3fa00861e5e/go.mod h1:swB5NSp8pKNDuYsTxfR08bHS6L56i119PBx8fxvV8Cs= github.com/scroll-tech/go-ethereum v1.10.14-0.20241010064814-3d88e870ae22/go.mod h1:r9FwtxCtybMkTbWYCyBuevT9TW3zHmOTHqD082Uh+Oo= -github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d h1:vuv7fGKEDtoeetI6RkKt8RAByJsYZBWk9Vo6gShv65c= -github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0 h1:HtCSf6B4gN/87yc5qTl7WsxPKQIIGXLPPM1bMCPOsoY= @@ -1181,7 +1396,9 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtse github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tdewolff/minify/v2 v2.12.4 h1:kejsHQMM17n6/gwdw53qsi6lg0TGddZADVyQOz1KMdE= github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= +github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ= github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= @@ -1191,15 +1408,18 @@ github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 h1:8eY github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7/go.mod h1:qqvyZqkfwkoJuPU/bw61bItaoO0SJ8YSW0vSVRRvsRg= github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= github.com/tonistiigi/go-archvariant v1.0.0/go.mod h1:TxFmO5VS6vMq2kvs3ht04iPXtu2rUT/erOnGFYfk5Ho= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= @@ -1212,7 +1432,9 @@ github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0m github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3 h1:ekJIKh6+YbUIVt9DfNbkR5d6aFcFTLDRyJNAACURBg8= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -1228,6 +1450,7 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg= github.com/yashtewari/glob-intersection v0.1.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1241,20 +1464,25 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd/api/v3 v3.5.5 h1:BX4JIbQ7hl7+jL+g+2j5UAr0o1bctCm6/Ct+ArBGkf0= go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= +go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.5 h1:9S0JUVvmrVl7wCF39iTQthdaaNIiAaQbmK75ogO6GU8= go.etcd.io/etcd/client/pkg/v3 v3.5.5/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= go.etcd.io/etcd/client/v2 v2.305.5 h1:DktRP60//JJpnPC0VBymAN/7V71GHMdjDCBt4ZPXDjI= go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4= +go.etcd.io/etcd/client/v2 v2.305.12 h1:0m4ovXYo1CHaA/Mp3X/Fak5sRNIWf01wk/X1/G3sGKI= go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E= go.etcd.io/etcd/client/v3 v3.5.5 h1:q++2WTJbUgpQu4B6hCuT7VkdwaTP7Qz6Daak3WzbrlI= go.etcd.io/etcd/client/v3 v3.5.5/go.mod h1:aApjR4WGlSumpnJ2kloS75h6aHUmAyaPLjHMxpc7E7c= +go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= go.etcd.io/etcd/pkg/v3 v3.5.5 h1:Ablg7T7OkR+AeeeU32kdVhw/AGDsitkKPl7aW73ssjU= go.etcd.io/etcd/pkg/v3 v3.5.5/go.mod h1:6ksYFxttiUGzC2uxyqiyOEvhAiD0tuIqSZkX3TyPdaE= @@ -1287,12 +1515,14 @@ go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxt go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1333,6 +1563,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= @@ -1384,6 +1615,7 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5 h1:ObuXPmIgI4ZMyQLIz48cJYgSyWdjUXc2SZAdyJMwEAU= golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1439,7 +1671,6 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -1507,6 +1738,7 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= @@ -1539,11 +1771,13 @@ google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYl google.golang.org/api v0.166.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1588,6 +1822,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c/go. google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20240314234333-6e1732d8331c h1:4z0DVWmDWWZ4OeQHLrb6lLBE3uCgSLs9DDA5Zb36DFg= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240314234333-6e1732d8331c/go.mod h1:IN9OQUXZ0xT+26MDwZL8fJcYw+y99b0eYPA2U15Jt8o= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= @@ -1614,6 +1849,7 @@ google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFL google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -1637,6 +1873,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069z honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/component-base v0.26.7 h1:uqsOyZh0Zqoaup8tmHa491D/CvgFdGUs+X2H/inNUKM= k8s.io/component-base v0.26.7/go.mod h1:CZe1HTmX/DQdeBrb9XYOXzs96jXth8ZbFvhLMsoJLUg= @@ -1654,7 +1891,9 @@ nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.37 h1:fAPTNEpzQMOLMGwOHNbUkR2xXTQwMJOZYNx+/mLlOh0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.37/go.mod h1:vfnxT4FXNT8eGvO+xi/DsyC/qHmdujqwrUa1WSspCsk= diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index 983248a72a..4a9a4f5fba 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -82,6 +82,7 @@ func action(ctx *cli.Context) error { fmt.Println(cfg.DBConfig) fmt.Println(cfg.RecoveryConfig) + // TODO: also allow to skip this step and persist DB in case this crashes when waiting for proof? // Restore minimal previous state required to be able to create new chunks, batches and bundles. latestFinalizedChunk, latestFinalizedBatch, err := restoreMinimalPreviousState(cfg, chunkProposer, batchProposer) if err != nil { @@ -300,12 +301,15 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun log.Info("Last L2 block in batch", "batch", batchCommitEvent.BatchIndex(), "L2 block", lastBlockInBatch) // 4. Get the L1 messages count after the latest finalized batch. - l1MessagesCount, err := reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) - if err != nil { - return nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) + var l1MessagesCount uint64 + if cfg.RecoveryConfig.ForceL1MessageCount == 0 { + l1MessagesCount, err = reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) + if err != nil { + return nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) + } + } else { + l1MessagesCount = cfg.RecoveryConfig.ForceL1MessageCount } - // TODO: remove this. only for testing - l1MessagesCount = 220853 log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) @@ -326,10 +330,3 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun return chunk, batch, nil } - -//docker run --rm -it \ -// -e POSTGRES_HOST_AUTH_METHOD=trust \ -// -e POSTGRES_DB=scroll \ -// -v ${PWD}/db_data:/var/lib/postgresql/data \ -// -p 5432:5432 \ -// postgres diff --git a/rollup/go.mod b/rollup/go.mod index b48023d85c..7c1d315f07 100644 --- a/rollup/go.mod +++ b/rollup/go.mod @@ -12,7 +12,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus/client_golang v1.16.0 github.com/scroll-tech/da-codec v0.1.2 - github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d + github.com/scroll-tech/go-ethereum v1.10.24-0.20241029080018-e873ac03ea65 github.com/smartystreets/goconvey v1.8.0 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 diff --git a/rollup/go.sum b/rollup/go.sum index 937aa61c61..7619c2205b 100644 --- a/rollup/go.sum +++ b/rollup/go.sum @@ -271,6 +271,8 @@ github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d h1:vuv github.com/scroll-tech/go-ethereum v1.10.14-0.20241023093931-91c2f9c27f4d/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d h1:ZxRzFWs1VvAGqkeUyjgkEkUHyWlGUHXibqCpLr81KZI= github.com/scroll-tech/go-ethereum v1.10.24-0.20241024005353-591534c3790d/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241029080018-e873ac03ea65 h1:pgRiaYyiyDRd/2yKN8LIZAjxu0bUXyTeoWiXSWPVFVM= +github.com/scroll-tech/go-ethereum v1.10.24-0.20241029080018-e873ac03ea65/go.mod h1:PWEOTg6LeWlJAlFJauO0msSLXWnpHmE+mVh5txtfeRM= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= diff --git a/rollup/internal/config/recovery.go b/rollup/internal/config/recovery.go index 4ed9c0a850..40afb4bf35 100644 --- a/rollup/internal/config/recovery.go +++ b/rollup/internal/config/recovery.go @@ -1,11 +1,11 @@ package config -// L1Config loads l1eth configuration items. type RecoveryConfig struct { Enable bool `json:"enable"` LatestFinalizedBatch uint64 `json:"latest_finalized_batch"` L1BlockHeight uint64 `json:"l1_block_height"` - L2BlockHeightLimit uint64 `json:"l2_block_height_limit"` + L2BlockHeightLimit uint64 `json:"l2_block_height_limit"` + ForceL1MessageCount uint64 `json:"force_l1_message_count"` } From 0f5ebf3cd1d420723bef79f82ba554900db04505 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:50:59 +0800 Subject: [PATCH 09/25] add Dockerfile for relayer in permissionless batches mode --- ...recovery_permissionless_batches.Dockerfile | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 permissionless-batches/recovery_permissionless_batches.Dockerfile diff --git a/permissionless-batches/recovery_permissionless_batches.Dockerfile b/permissionless-batches/recovery_permissionless_batches.Dockerfile new file mode 100644 index 0000000000..317ec1450c --- /dev/null +++ b/permissionless-batches/recovery_permissionless_batches.Dockerfile @@ -0,0 +1,30 @@ +# Download Go dependencies +FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base + +WORKDIR /src +COPY go.work* ./ +COPY ./rollup/go.* ./rollup/ +COPY ./common/go.* ./common/ +COPY ./coordinator/go.* ./coordinator/ +COPY ./database/go.* ./database/ +COPY ./tests/integration-test/go.* ./tests/integration-test/ +COPY ./bridge-history-api/go.* ./bridge-history-api/ +RUN go mod download -x + +# Build rollup_relayer +FROM base as builder + +RUN --mount=target=. \ + --mount=type=cache,target=/root/.cache/go-build \ + cd /src/rollup/cmd/permissionless_batches/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/rollup_relayer + +# Pull rollup_relayer into a second stage deploy ubuntu container +FROM ubuntu:20.04 + +RUN apt update && apt install vim netcat-openbsd net-tools curl ca-certificates -y + +ENV CGO_LDFLAGS="-ldl" + +COPY --from=builder /bin/rollup_relayer /bin/ +WORKDIR /app +ENTRYPOINT ["rollup_relayer"] \ No newline at end of file From f96af8e917e69c5955c64ec96857fab92487506c Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:51:24 +0800 Subject: [PATCH 10/25] add docker compose file to spin up all necessary services together --- permissionless-batches/docker-compose.yml | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 permissionless-batches/docker-compose.yml diff --git a/permissionless-batches/docker-compose.yml b/permissionless-batches/docker-compose.yml new file mode 100644 index 0000000000..fa6e5f2b4b --- /dev/null +++ b/permissionless-batches/docker-compose.yml @@ -0,0 +1,79 @@ +name: permissionless-batches + +services: + relayer: + build: + context: ../ + dockerfile: permissionless-batches/recovery_permissionless_batches.Dockerfile + container_name: permissionless-batches-relayer + volumes: + - ./conf/relayer:/app/conf + command: "--config /app/conf/config.json" + depends_on: + db: + condition: service_healthy + + db: + image: postgres:17.0 + environment: + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_USER: postgres + POSTGRES_DB: scroll + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U postgres" ] + interval: 1s + timeout: 1s + retries: 10 + volumes: + - db_data:/var/lib/postgresql/data + ports: + - "5432:5432" + + coordinator: + build: + context: ../ + dockerfile: build/dockerfiles/coordinator-api.Dockerfile + volumes: + - ./conf/coordinator/:/app/conf + command: "--config /app/conf/config.json --http.port 8390 --verbosity 5" + depends_on: + db: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8390/coordinator/v1/challenge"] + interval: 1s + timeout: 1s + retries: 10 + start_period: 5m + + proving-service-chunk: + image: scrolltech/sdk-cloud-prover:sindri-v0.0.4 + platform: linux/amd64 + command: "--config /app/config.json" + environment: + PROVER_NAME_PREFIX: "sindri_chunk" + CIRCUIT_TYPE: 1 # 1 for chunk proving + RUST_BACKTRACE: 1 + volumes: + - ./conf/proving-service/chunk/:/app/keys + - ./conf/proving-service/config.json:/app/config.json + depends_on: + coordinator: + condition: service_healthy + + proving-service-batch: + image: scrolltech/sdk-cloud-prover:sindri-v0.0.4 + platform: linux/amd64 + command: "--config /app/config.json" + environment: + PROVER_NAME_PREFIX: "sindri_batch" + CIRCUIT_TYPE: 2 # 2 for chunk proving + volumes: + - ./conf/proving-service/batch/:/app/keys + - ./conf/proving-service/config.json:/app/config.json + depends_on: + coordinator: + condition: service_healthy + +volumes: + db_data: \ No newline at end of file From 16a471d4e8909aaf696db40a626c0f2f89a9f900 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:55:38 +0800 Subject: [PATCH 11/25] move docker file to build/dockerfiles --- .../dockerfiles}/recovery_permissionless_batches.Dockerfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {permissionless-batches => build/dockerfiles}/recovery_permissionless_batches.Dockerfile (100%) diff --git a/permissionless-batches/recovery_permissionless_batches.Dockerfile b/build/dockerfiles/recovery_permissionless_batches.Dockerfile similarity index 100% rename from permissionless-batches/recovery_permissionless_batches.Dockerfile rename to build/dockerfiles/recovery_permissionless_batches.Dockerfile From d25094b7efe5ddb7c4608bdff25eca87df872251 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:57:24 +0800 Subject: [PATCH 12/25] add coordinator-cron and proving-service-bundle --- permissionless-batches/docker-compose.yml | 42 +++++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/permissionless-batches/docker-compose.yml b/permissionless-batches/docker-compose.yml index fa6e5f2b4b..f3f3d7dcff 100644 --- a/permissionless-batches/docker-compose.yml +++ b/permissionless-batches/docker-compose.yml @@ -4,7 +4,7 @@ services: relayer: build: context: ../ - dockerfile: permissionless-batches/recovery_permissionless_batches.Dockerfile + dockerfile: build/dockerfiles/recovery_permissionless_batches.Dockerfile container_name: permissionless-batches-relayer volumes: - ./conf/relayer:/app/conf @@ -46,30 +46,58 @@ services: retries: 10 start_period: 5m + coordinator-cron: + build: + context: ../ + dockerfile: build/dockerfiles/coordinator-cron.Dockerfile + volumes: + - ./conf/coordinator/:/app/conf + command: "--config /app/conf/config.json --verbosity 3" + depends_on: + db: + condition: service_healthy + + proving-service-chunk: - image: scrolltech/sdk-cloud-prover:sindri-v0.0.4 + image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 platform: linux/amd64 command: "--config /app/config.json" environment: PROVER_NAME_PREFIX: "sindri_chunk" CIRCUIT_TYPE: 1 # 1 for chunk proving - RUST_BACKTRACE: 1 + N_WORKERS: 1 volumes: - - ./conf/proving-service/chunk/:/app/keys + - ./conf/proving-service/chunk/:/app/ - ./conf/proving-service/config.json:/app/config.json depends_on: coordinator: condition: service_healthy proving-service-batch: - image: scrolltech/sdk-cloud-prover:sindri-v0.0.4 + image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 platform: linux/amd64 command: "--config /app/config.json" environment: PROVER_NAME_PREFIX: "sindri_batch" - CIRCUIT_TYPE: 2 # 2 for chunk proving + CIRCUIT_TYPE: 2 # 2 for batch proving + N_WORKERS: 1 + volumes: + - ./conf/proving-service/batch/:/app + - ./conf/proving-service/config.json:/app/config.json + depends_on: + coordinator: + condition: service_healthy + + proving-service-bundle: + image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 + platform: linux/amd64 + command: "--config /app/config.json" + environment: + PROVER_NAME_PREFIX: "sindri_bundle" + CIRCUIT_TYPE: 3 # 3 for bundle proving + N_WORKERS: 1 volumes: - - ./conf/proving-service/batch/:/app/keys + - ./conf/proving-service/bundle/:/app - ./conf/proving-service/config.json:/app/config.json depends_on: coordinator: From 603feed19ca693f1cd9f41329e6e0466c9e10982 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:09:35 +0800 Subject: [PATCH 13/25] add bundle creation --- rollup/cmd/permissionless_batches/app/app.go | 90 ++++++++++++++++---- rollup/internal/orm/batch.go | 2 +- rollup/internal/orm/bundle.go | 16 ++-- 3 files changed, 83 insertions(+), 25 deletions(-) diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index 4a9a4f5fba..e8b0dda14e 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -18,6 +18,7 @@ import ( "scroll-tech/common/database" "scroll-tech/common/observability" + "scroll-tech/common/types" "scroll-tech/common/utils" "scroll-tech/common/version" "scroll-tech/database/migrate" @@ -54,6 +55,8 @@ func action(ctx *cli.Context) error { subCtx, cancel := context.WithCancel(ctx.Context) defer cancel() + // TODO: avoid resetting the DB if it already exists and has data latestFinalizedBatch+1 as a batch + db, err := initDB(cfg) if err != nil { return fmt.Errorf("failed to init db: %w", err) @@ -75,16 +78,15 @@ func action(ctx *cli.Context) error { chunkProposer := watcher.NewChunkProposer(subCtx, cfg.L2Config.ChunkProposerConfig, genesis.Config, db, registry) batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) - //bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) + bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) fmt.Println(cfg.L1Config) fmt.Println(cfg.L2Config) fmt.Println(cfg.DBConfig) fmt.Println(cfg.RecoveryConfig) - // TODO: also allow to skip this step and persist DB in case this crashes when waiting for proof? // Restore minimal previous state required to be able to create new chunks, batches and bundles. - latestFinalizedChunk, latestFinalizedBatch, err := restoreMinimalPreviousState(cfg, chunkProposer, batchProposer) + latestFinalizedChunk, latestFinalizedBatch, latestFinalizedBundle, err := restoreMinimalPreviousState(cfg, db, chunkProposer, batchProposer, bundleProposer) if err != nil { return fmt.Errorf("failed to restore minimal previous state: %w", err) } @@ -133,11 +135,42 @@ func action(ctx *cli.Context) error { return fmt.Errorf("failed to get latest latestFinalizedBatch: %w", err) } + firstChunkInBatch, err := chunkProposer.ChunkORM().GetChunkByIndex(subCtx, latestBatch.EndChunkIndex) + if err != nil { + return fmt.Errorf("failed to get first chunk in batch: %w", err) + } + lastChunkInBatch, err := chunkProposer.ChunkORM().GetChunkByIndex(subCtx, latestBatch.EndChunkIndex) + if err != nil { + return fmt.Errorf("failed to get last chunk in batch: %w", err) + } + + // Make sure that the batch contains all previously created chunks and thus all blocks. If not the user will need to + // produce another batch (running the application again) starting from the end block of the last chunk in the batch + 1. if latestBatch.EndChunkIndex != latestChunk.Index { - return fmt.Errorf("latest chunk in produced batch %d != %d, too many L2 blocks - specify less L2 blocks and retry again", latestBatch.EndChunkIndex, latestChunk.Index) + log.Warn("Produced batch does not contain all chunks and blocks. You'll need to produce another batch starting from end block+1.", "starting block", firstChunkInBatch.StartBlockNumber, "end block", lastChunkInBatch.EndBlockNumber, "latest block", latestChunk.EndBlockNumber) + } + + log.Info("Batch created", "index", latestBatch.Index, "hash", latestBatch.Hash, "StartChunkIndex", latestBatch.StartChunkIndex, "EndChunkIndex", latestBatch.EndChunkIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) + + bundleProposer.TryProposeBundle() + latestBundle, err := bundleProposer.BundleORM().GetLatestBundle(subCtx) + if err != nil { + return fmt.Errorf("failed to get latest bundle: %w", err) + } + + // Sanity check that the bundle was created correctly: + // 1. should be a new bundle + // 2. should only contain 1 batch, the one we created + if latestFinalizedBundle.Index == latestBundle.Index { + return fmt.Errorf("bundle was not created correctly") } + if latestBundle.StartBatchIndex != latestBatch.Index || latestBundle.EndBatchIndex != latestBatch.Index { + return fmt.Errorf("bundle does not contain the correct batch: %d != %d", latestBundle.StartBatchIndex, latestBatch.Index) + } + + log.Info("Bundle created", "index", latestBundle.Index, "hash", latestBundle.Hash, "StartBatchIndex", latestBundle.StartBatchIndex, "EndBatchIndex", latestBundle.EndBatchIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) - log.Info("Batch created", "index", latestBatch.Index, "hash", latestBatch.Hash, "StartChunkIndex", latestBatch.StartChunkIndex, "EndChunkIndex", latestBatch.EndChunkIndex) + log.Info("Waiting for proofs...") // Catch CTRL-C to ensure a graceful shutdown. interrupt := make(chan os.Signal, 1) @@ -228,7 +261,7 @@ func fetchL2Blocks(ctx context.Context, cfg *config.Config, genesis *core.Genesi } // restoreMinimalPreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. -func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer) (*orm.Chunk, *orm.Batch, error) { +func restoreMinimalPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer) (*orm.Chunk, *orm.Batch, *orm.Bundle, error) { log.Info("Restoring previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) // TODO: make these parameters -> part of genesis config? @@ -237,23 +270,23 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) if err != nil { - return nil, nil, fmt.Errorf("failed to connect to L1 client: %w", err) + return nil, nil, nil, fmt.Errorf("failed to connect to L1 client: %w", err) } reader, err := l1.NewReader(context.Background(), l1.Config{ ScrollChainAddress: scrollChainAddress, L1MessageQueueAddress: l1MessageQueueAddress, }, l1Client) if err != nil { - return nil, nil, fmt.Errorf("failed to create L1 reader: %w", err) + return nil, nil, nil, fmt.Errorf("failed to create L1 reader: %w", err) } // 1. Sanity check user input: Make sure that the user's L1 block height is not higher than the latest finalized block number. latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() if err != nil { - return nil, nil, fmt.Errorf("failed to get latest finalized L1 block number: %w", err) + return nil, nil, nil, fmt.Errorf("failed to get latest finalized L1 block number: %w", err) } if cfg.RecoveryConfig.L1BlockHeight > latestFinalizedL1Block { - return nil, nil, fmt.Errorf("specified L1 block height is higher than the latest finalized block number: %d > %d", cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block) + return nil, nil, nil, fmt.Errorf("specified L1 block height is higher than the latest finalized block number: %d > %d", cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block) } log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) @@ -275,7 +308,7 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun return true }) if batchCommitEvent == nil { - return nil, nil, fmt.Errorf("commit event not found for batch %d", cfg.RecoveryConfig.LatestFinalizedBatch) + return nil, nil, nil, fmt.Errorf("commit event not found for batch %d", cfg.RecoveryConfig.LatestFinalizedBatch) } log.Info("Found commit event for batch", "batch", batchCommitEvent.BatchIndex(), "hash", batchCommitEvent.BatchHash(), "L1 block height", batchCommitEvent.BlockNumber(), "L1 tx hash", batchCommitEvent.TxHash()) @@ -283,17 +316,17 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun // 3. Fetch commit tx data for latest finalized batch. args, err := reader.FetchCommitTxData(batchCommitEvent) if err != nil { - return nil, nil, fmt.Errorf("failed to fetch commit tx data: %w", err) + return nil, nil, nil, fmt.Errorf("failed to fetch commit tx data: %w", err) } codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) if err != nil { - return nil, nil, fmt.Errorf("failed to get codec: %w", err) + return nil, nil, nil, fmt.Errorf("failed to get codec: %w", err) } daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) if err != nil { - return nil, nil, fmt.Errorf("failed to decode DA chunks: %w", err) + return nil, nil, nil, fmt.Errorf("failed to decode DA chunks: %w", err) } lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() @@ -305,7 +338,7 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun if cfg.RecoveryConfig.ForceL1MessageCount == 0 { l1MessagesCount, err = reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) if err != nil { - return nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) + return nil, nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) } } else { l1MessagesCount = cfg.RecoveryConfig.ForceL1MessageCount @@ -316,17 +349,38 @@ func restoreMinimalPreviousState(cfg *config.Config, chunkProposer *watcher.Chun // 5. Insert minimal state to DB. chunk, err := chunkProposer.ChunkORM().InsertChunkRaw(context.Background(), codec.Version(), lastChunk, l1MessagesCount) if err != nil { - return nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) + return nil, nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) } log.Info("Inserted last finalized chunk to DB", "chunk", chunk.Index, "hash", chunk.Hash, "StartBlockNumber", chunk.StartBlockNumber, "EndBlockNumber", chunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", chunk.TotalL1MessagesPoppedBefore) batch, err := batchProposer.BatchORM().InsertBatchRaw(context.Background(), batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) if err != nil { - return nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) + return nil, nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) } log.Info("Inserted last finalized batch to DB", "batch", batch.Index, "hash", batch.Hash) - return chunk, batch, nil + var bundle *orm.Bundle + err = db.Transaction(func(dbTX *gorm.DB) error { + bundle, err = bundleProposer.BundleORM().InsertBundle(context.Background(), []*orm.Batch{batch}, encoding.CodecVersion(batch.CodecVersion), dbTX) + if err != nil { + return fmt.Errorf("failed to insert bundle: %w", err) + } + if err = bundleProposer.BundleORM().UpdateProvingStatus(context.Background(), bundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status: %w", err) + } + if err = bundleProposer.BundleORM().UpdateRollupStatus(context.Background(), bundle.Hash, types.RollupFinalized); err != nil { + return fmt.Errorf("failed to update rollup status: %w", err) + } + + log.Info("Inserted last finalized bundle to DB", "bundle", bundle.Index, "hash", bundle.Hash, "StartBatchIndex", bundle.StartBatchIndex, "EndBatchIndex", bundle.EndBatchIndex) + + return nil + }) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to insert bundle: %w", err) + } + + return chunk, batch, bundle, nil } diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index c7f5b3cf57..f89fb9f0fc 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -349,7 +349,7 @@ func (o *Batch) InsertBatchRaw(ctx context.Context, batchIndex *big.Int, batchHa ProverAssignedAt: nil, ProvedAt: &now, ProofTimeSec: 0, - RollupStatus: 0, + RollupStatus: int16(types.RollupFinalized), CommitTxHash: "", CommittedAt: nil, FinalizeTxHash: "", diff --git a/rollup/internal/orm/bundle.go b/rollup/internal/orm/bundle.go index 3d35be29db..8d17eae9d8 100644 --- a/rollup/internal/orm/bundle.go +++ b/rollup/internal/orm/bundle.go @@ -59,8 +59,8 @@ func (*Bundle) TableName() string { return "bundle" } -// getLatestBundle retrieves the latest bundle from the database. -func (o *Bundle) getLatestBundle(ctx context.Context) (*Bundle, error) { +// GetLatestBundle retrieves the latest bundle from the database. +func (o *Bundle) GetLatestBundle(ctx context.Context) (*Bundle, error) { db := o.db.WithContext(ctx) db = db.Model(&Bundle{}) db = db.Order("index desc") @@ -70,7 +70,7 @@ func (o *Bundle) getLatestBundle(ctx context.Context) (*Bundle, error) { if err == gorm.ErrRecordNotFound { return nil, nil } - return nil, fmt.Errorf("getLatestBundle error: %w", err) + return nil, fmt.Errorf("GetLatestBundle error: %w", err) } return &latestBundle, nil } @@ -106,7 +106,7 @@ func (o *Bundle) GetBundles(ctx context.Context, fields map[string]interface{}, // GetFirstUnbundledBatchIndex retrieves the first unbundled batch index. func (o *Bundle) GetFirstUnbundledBatchIndex(ctx context.Context) (uint64, error) { // Get the latest bundle - latestBundle, err := o.getLatestBundle(ctx) + latestBundle, err := o.GetLatestBundle(ctx) if err != nil { return 0, fmt.Errorf("Bundle.GetFirstUnbundledBatchIndex error: %w", err) } @@ -237,14 +237,18 @@ func (o *Bundle) UpdateProvingStatus(ctx context.Context, hash string, status ty // UpdateRollupStatus updates the rollup status for a bundle. // only used in unit tests. -func (o *Bundle) UpdateRollupStatus(ctx context.Context, hash string, status types.RollupStatus) error { +func (o *Bundle) UpdateRollupStatus(ctx context.Context, hash string, status types.RollupStatus, dbTX ...*gorm.DB) error { updateFields := make(map[string]interface{}) updateFields["rollup_status"] = int(status) if status == types.RollupFinalized { updateFields["finalized_at"] = time.Now() } - db := o.db.WithContext(ctx) + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) db = db.Model(&Bundle{}) db = db.Where("hash", hash) From 5ddd6d6a84348ceb9b6babf75b6ed454b7339707 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:30:29 +0800 Subject: [PATCH 14/25] add permissionless-batches/conf/ to dockerignore files --- build/dockerfiles/coordinator-api.Dockerfile.dockerignore | 2 ++ .../dockerfiles/coordinator-cron.Dockerfile.dockerignore | 2 ++ build/dockerfiles/db_cli.Dockerfile.dockerignore | 2 ++ build/dockerfiles/gas_oracle.Dockerfile.dockerignore | 5 ++++- ...ecovery_permissionless_batches.Dockerfile.dockerignore | 8 ++++++++ build/dockerfiles/rollup_relayer.Dockerfile.dockerignore | 5 ++++- 6 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore diff --git a/build/dockerfiles/coordinator-api.Dockerfile.dockerignore b/build/dockerfiles/coordinator-api.Dockerfile.dockerignore index e67a9b0efe..3fcfcdc46d 100644 --- a/build/dockerfiles/coordinator-api.Dockerfile.dockerignore +++ b/build/dockerfiles/coordinator-api.Dockerfile.dockerignore @@ -4,3 +4,5 @@ docs/ l2geth/ rpc-gateway/ *target/* + +permissionless-batches/conf/ \ No newline at end of file diff --git a/build/dockerfiles/coordinator-cron.Dockerfile.dockerignore b/build/dockerfiles/coordinator-cron.Dockerfile.dockerignore index e67a9b0efe..3fcfcdc46d 100644 --- a/build/dockerfiles/coordinator-cron.Dockerfile.dockerignore +++ b/build/dockerfiles/coordinator-cron.Dockerfile.dockerignore @@ -4,3 +4,5 @@ docs/ l2geth/ rpc-gateway/ *target/* + +permissionless-batches/conf/ \ No newline at end of file diff --git a/build/dockerfiles/db_cli.Dockerfile.dockerignore b/build/dockerfiles/db_cli.Dockerfile.dockerignore index e67a9b0efe..3fcfcdc46d 100644 --- a/build/dockerfiles/db_cli.Dockerfile.dockerignore +++ b/build/dockerfiles/db_cli.Dockerfile.dockerignore @@ -4,3 +4,5 @@ docs/ l2geth/ rpc-gateway/ *target/* + +permissionless-batches/conf/ \ No newline at end of file diff --git a/build/dockerfiles/gas_oracle.Dockerfile.dockerignore b/build/dockerfiles/gas_oracle.Dockerfile.dockerignore index 8734d3f9b6..3fcfcdc46d 100644 --- a/build/dockerfiles/gas_oracle.Dockerfile.dockerignore +++ b/build/dockerfiles/gas_oracle.Dockerfile.dockerignore @@ -1,5 +1,8 @@ assets/ +contracts/ docs/ l2geth/ rpc-gateway/ -*target/* \ No newline at end of file +*target/* + +permissionless-batches/conf/ \ No newline at end of file diff --git a/build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore b/build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore new file mode 100644 index 0000000000..3fcfcdc46d --- /dev/null +++ b/build/dockerfiles/recovery_permissionless_batches.Dockerfile.dockerignore @@ -0,0 +1,8 @@ +assets/ +contracts/ +docs/ +l2geth/ +rpc-gateway/ +*target/* + +permissionless-batches/conf/ \ No newline at end of file diff --git a/build/dockerfiles/rollup_relayer.Dockerfile.dockerignore b/build/dockerfiles/rollup_relayer.Dockerfile.dockerignore index 8734d3f9b6..3fcfcdc46d 100644 --- a/build/dockerfiles/rollup_relayer.Dockerfile.dockerignore +++ b/build/dockerfiles/rollup_relayer.Dockerfile.dockerignore @@ -1,5 +1,8 @@ assets/ +contracts/ docs/ l2geth/ rpc-gateway/ -*target/* \ No newline at end of file +*target/* + +permissionless-batches/conf/ \ No newline at end of file From 5ff6fd079976cb1baa9790df5277a947c37f77f7 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:11:32 +0800 Subject: [PATCH 15/25] refactor cmd/permissionless_batches/app --- rollup/cmd/permissionless_batches/app/app.go | 320 ++--------------- rollup/internal/config/recovery.go | 5 +- .../permissionless_batches/recovery.go | 334 ++++++++++++++++++ .../controller/watcher/batch_proposer.go | 4 - .../controller/watcher/bundle_proposer.go | 4 - .../controller/watcher/chunk_proposer.go | 4 - 6 files changed, 359 insertions(+), 312 deletions(-) create mode 100644 rollup/internal/controller/permissionless_batches/recovery.go diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index e8b0dda14e..7be08523db 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -4,27 +4,19 @@ import ( "context" "fmt" "os" - "os/signal" "github.com/prometheus/client_golang/prometheus" - "github.com/scroll-tech/da-codec/encoding" - "github.com/scroll-tech/go-ethereum/common" - "github.com/scroll-tech/go-ethereum/core" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" - "github.com/scroll-tech/go-ethereum/rollup/l1" "github.com/urfave/cli/v2" - "gorm.io/gorm" "scroll-tech/common/database" "scroll-tech/common/observability" - "scroll-tech/common/types" "scroll-tech/common/utils" "scroll-tech/common/version" - "scroll-tech/database/migrate" "scroll-tech/rollup/internal/config" + "scroll-tech/rollup/internal/controller/permissionless_batches" "scroll-tech/rollup/internal/controller/watcher" - "scroll-tech/rollup/internal/orm" ) var app *cli.App @@ -55,11 +47,18 @@ func action(ctx *cli.Context) error { subCtx, cancel := context.WithCancel(ctx.Context) defer cancel() - // TODO: avoid resetting the DB if it already exists and has data latestFinalizedBatch+1 as a batch + // Make sure the required fields are set. + if cfg.RecoveryConfig.L1BlockHeight == 0 { + return fmt.Errorf("L1 block height must be specified") + } + if cfg.RecoveryConfig.LatestFinalizedBatch == 0 { + return fmt.Errorf("latest finalized batch must be specified") + } - db, err := initDB(cfg) + // init db connection + db, err := database.InitDB(cfg.DBConfig) if err != nil { - return fmt.Errorf("failed to init db: %w", err) + log.Crit("failed to init db connection", "err", err) } defer func() { if err = database.CloseDB(db); err != nil { @@ -80,105 +79,25 @@ func action(ctx *cli.Context) error { batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, genesis.Config, db, registry) bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, genesis.Config, db, registry) - fmt.Println(cfg.L1Config) - fmt.Println(cfg.L2Config) - fmt.Println(cfg.DBConfig) - fmt.Println(cfg.RecoveryConfig) - - // Restore minimal previous state required to be able to create new chunks, batches and bundles. - latestFinalizedChunk, latestFinalizedBatch, latestFinalizedBundle, err := restoreMinimalPreviousState(cfg, db, chunkProposer, batchProposer, bundleProposer) - if err != nil { - return fmt.Errorf("failed to restore minimal previous state: %w", err) - } - - // Fetch and insert the missing blocks from the last block in the latestFinalizedBatch to the latest L2 block. - fromBlock := latestFinalizedChunk.EndBlockNumber + 1 - toBlock, err := fetchL2Blocks(subCtx, cfg, genesis, db, registry, fromBlock, cfg.RecoveryConfig.L2BlockHeightLimit) + // Init l2geth connection + l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) if err != nil { - return fmt.Errorf("failed to fetch L2 blocks: %w", err) + return fmt.Errorf("failed to connect to L2geth at RPC=%s: %w", cfg.L2Config.Endpoint, err) } - fmt.Println(latestFinalizedChunk.Index, latestFinalizedBatch.Index, fromBlock, toBlock) - - // Create chunks for L2 blocks. - log.Info("Creating chunks for L2 blocks", "from", fromBlock, "to", toBlock) - - var latestChunk *orm.Chunk - var count int - for { - if err = chunkProposer.ProposeChunk(); err != nil { - return fmt.Errorf("failed to propose chunk: %w", err) - } - count++ - - latestChunk, err = chunkProposer.ChunkORM().GetLatestChunk(subCtx) - if err != nil { - return fmt.Errorf("failed to get latest latestFinalizedChunk: %w", err) - } + l2Watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) - log.Info("Chunk created", "index", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) + recovery := permissionless_batches.NewRecovery(subCtx, cfg, genesis, db, chunkProposer, batchProposer, bundleProposer, l2Watcher) - // We have created chunks for all available L2 blocks. - if latestChunk.EndBlockNumber >= toBlock { - break + if recovery.RecoveryNeeded() { + if err = recovery.Run(); err != nil { + return fmt.Errorf("failed to run recovery: %w", err) } + log.Info("Success! You're ready to generate proofs!") + } else { + log.Info("TODO: Batch submission") } - log.Info("Chunks created", "count", count, "latest latestFinalizedChunk", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) - - // Create batch for the created chunks. We only allow 1 batch it needs to be submitted (and finalized) with a proof in a single step. - log.Info("Creating batch for chunks", "from", latestFinalizedChunk.Index+1, "to", latestChunk.Index) - - batchProposer.TryProposeBatch() - latestBatch, err := batchProposer.BatchORM().GetLatestBatch(subCtx) - if err != nil { - return fmt.Errorf("failed to get latest latestFinalizedBatch: %w", err) - } - - firstChunkInBatch, err := chunkProposer.ChunkORM().GetChunkByIndex(subCtx, latestBatch.EndChunkIndex) - if err != nil { - return fmt.Errorf("failed to get first chunk in batch: %w", err) - } - lastChunkInBatch, err := chunkProposer.ChunkORM().GetChunkByIndex(subCtx, latestBatch.EndChunkIndex) - if err != nil { - return fmt.Errorf("failed to get last chunk in batch: %w", err) - } - - // Make sure that the batch contains all previously created chunks and thus all blocks. If not the user will need to - // produce another batch (running the application again) starting from the end block of the last chunk in the batch + 1. - if latestBatch.EndChunkIndex != latestChunk.Index { - log.Warn("Produced batch does not contain all chunks and blocks. You'll need to produce another batch starting from end block+1.", "starting block", firstChunkInBatch.StartBlockNumber, "end block", lastChunkInBatch.EndBlockNumber, "latest block", latestChunk.EndBlockNumber) - } - - log.Info("Batch created", "index", latestBatch.Index, "hash", latestBatch.Hash, "StartChunkIndex", latestBatch.StartChunkIndex, "EndChunkIndex", latestBatch.EndChunkIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) - - bundleProposer.TryProposeBundle() - latestBundle, err := bundleProposer.BundleORM().GetLatestBundle(subCtx) - if err != nil { - return fmt.Errorf("failed to get latest bundle: %w", err) - } - - // Sanity check that the bundle was created correctly: - // 1. should be a new bundle - // 2. should only contain 1 batch, the one we created - if latestFinalizedBundle.Index == latestBundle.Index { - return fmt.Errorf("bundle was not created correctly") - } - if latestBundle.StartBatchIndex != latestBatch.Index || latestBundle.EndBatchIndex != latestBatch.Index { - return fmt.Errorf("bundle does not contain the correct batch: %d != %d", latestBundle.StartBatchIndex, latestBatch.Index) - } - - log.Info("Bundle created", "index", latestBundle.Index, "hash", latestBundle.Hash, "StartBatchIndex", latestBundle.StartBatchIndex, "EndBatchIndex", latestBundle.EndBatchIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) - - log.Info("Waiting for proofs...") - - // Catch CTRL-C to ensure a graceful shutdown. - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt) - - // Wait until the interrupt signal is received from an OS signal. - <-interrupt - return nil } @@ -189,198 +108,3 @@ func Run() { os.Exit(1) } } - -func initDB(cfg *config.Config) (*gorm.DB, error) { - // init db connection - db, err := database.InitDB(cfg.DBConfig) - if err != nil { - log.Crit("failed to init db connection", "err", err) - } - - // make sure we are starting from a fresh DB - sqlDB, err := db.DB() - if err != nil { - return nil, fmt.Errorf("failed ") - } - - // reset and init DB - var v int64 - err = migrate.Rollback(sqlDB, &v) - if err != nil { - return nil, fmt.Errorf("failed to rollback db: %w", err) - } - - err = migrate.Migrate(sqlDB) - if err != nil { - return nil, fmt.Errorf("failed to migrate db: %w", err) - } - - return db, nil -} - -func fetchL2Blocks(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, registry prometheus.Registerer, fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) { - if l2BlockHeightLimit > 0 && fromBlock > l2BlockHeightLimit { - return 0, fmt.Errorf("fromBlock (latest finalized L2 block) is higher than specified L2BlockHeightLimit: %d > %d", fromBlock, l2BlockHeightLimit) - } - - log.Info("Fetching L2 blocks with", "fromBlock", fromBlock, "l2BlockHeightLimit", l2BlockHeightLimit) - - // Init l2geth connection - l2client, err := ethclient.Dial(cfg.L2Config.Endpoint) - if err != nil { - return 0, fmt.Errorf("failed to connect to L2geth at RPC=%s: %w", cfg.L2Config.Endpoint, err) - } - - l2Watcher := watcher.NewL2WatcherClient(ctx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) - - // Fetch and insert the missing blocks from the last block in the batch to the latest L2 block. - latestL2Block, err := l2Watcher.Client.BlockNumber(context.Background()) - if err != nil { - return 0, fmt.Errorf("failed to get latest L2 block number: %w", err) - } - - log.Info("Latest L2 block number", "latest L2 block", latestL2Block) - - if l2BlockHeightLimit > latestL2Block { - return 0, fmt.Errorf("l2BlockHeightLimit is higher than the latest L2 block number, not all blocks are available in L2geth: %d > %d", l2BlockHeightLimit, latestL2Block) - } - - toBlock := latestL2Block - if l2BlockHeightLimit > 0 { - toBlock = l2BlockHeightLimit - } - - err = l2Watcher.GetAndStoreBlocks(context.Background(), fromBlock, toBlock) - if err != nil { - return 0, fmt.Errorf("failed to get and store blocks: %w", err) - } - - log.Info("Fetched L2 blocks from", "fromBlock", fromBlock, "toBlock", toBlock) - - return toBlock, nil -} - -// restoreMinimalPreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. -func restoreMinimalPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer) (*orm.Chunk, *orm.Batch, *orm.Bundle, error) { - log.Info("Restoring previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) - - // TODO: make these parameters -> part of genesis config? - scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0") - l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763") - - l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to connect to L1 client: %w", err) - } - reader, err := l1.NewReader(context.Background(), l1.Config{ - ScrollChainAddress: scrollChainAddress, - L1MessageQueueAddress: l1MessageQueueAddress, - }, l1Client) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to create L1 reader: %w", err) - } - - // 1. Sanity check user input: Make sure that the user's L1 block height is not higher than the latest finalized block number. - latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to get latest finalized L1 block number: %w", err) - } - if cfg.RecoveryConfig.L1BlockHeight > latestFinalizedL1Block { - return nil, nil, nil, fmt.Errorf("specified L1 block height is higher than the latest finalized block number: %d > %d", cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block) - } - - log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) - - // 2. Make sure that the specified batch is indeed finalized on the L1 rollup contract and is the latest finalized batch. - // TODO: enable check - //latestFinalizedBatch, err := reader.LatestFinalizedBatch(latestFinalizedL1Block) - //if cfg.RecoveryConfig.LatestFinalizedBatch != latestFinalizedBatch { - // return nil, nil, fmt.Errorf("batch %d is not the latest finalized batch: %d", cfg.RecoveryConfig.LatestFinalizedBatch, latestFinalizedBatch) - //} - - var batchCommitEvent *l1.CommitBatchEvent - err = reader.FetchRollupEventsInRangeWithCallback(cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block, func(event l1.RollupEvent) bool { - if event.Type() == l1.CommitEventType && event.BatchIndex().Uint64() == cfg.RecoveryConfig.LatestFinalizedBatch { - batchCommitEvent = event.(*l1.CommitBatchEvent) - return false - } - - return true - }) - if batchCommitEvent == nil { - return nil, nil, nil, fmt.Errorf("commit event not found for batch %d", cfg.RecoveryConfig.LatestFinalizedBatch) - } - - log.Info("Found commit event for batch", "batch", batchCommitEvent.BatchIndex(), "hash", batchCommitEvent.BatchHash(), "L1 block height", batchCommitEvent.BlockNumber(), "L1 tx hash", batchCommitEvent.TxHash()) - - // 3. Fetch commit tx data for latest finalized batch. - args, err := reader.FetchCommitTxData(batchCommitEvent) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to fetch commit tx data: %w", err) - } - - codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to get codec: %w", err) - } - - daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to decode DA chunks: %w", err) - } - lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] - lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() - - log.Info("Last L2 block in batch", "batch", batchCommitEvent.BatchIndex(), "L2 block", lastBlockInBatch) - - // 4. Get the L1 messages count after the latest finalized batch. - var l1MessagesCount uint64 - if cfg.RecoveryConfig.ForceL1MessageCount == 0 { - l1MessagesCount, err = reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) - } - } else { - l1MessagesCount = cfg.RecoveryConfig.ForceL1MessageCount - } - - log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) - - // 5. Insert minimal state to DB. - chunk, err := chunkProposer.ChunkORM().InsertChunkRaw(context.Background(), codec.Version(), lastChunk, l1MessagesCount) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) - } - - log.Info("Inserted last finalized chunk to DB", "chunk", chunk.Index, "hash", chunk.Hash, "StartBlockNumber", chunk.StartBlockNumber, "EndBlockNumber", chunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", chunk.TotalL1MessagesPoppedBefore) - - batch, err := batchProposer.BatchORM().InsertBatchRaw(context.Background(), batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) - } - - log.Info("Inserted last finalized batch to DB", "batch", batch.Index, "hash", batch.Hash) - - var bundle *orm.Bundle - err = db.Transaction(func(dbTX *gorm.DB) error { - bundle, err = bundleProposer.BundleORM().InsertBundle(context.Background(), []*orm.Batch{batch}, encoding.CodecVersion(batch.CodecVersion), dbTX) - if err != nil { - return fmt.Errorf("failed to insert bundle: %w", err) - } - if err = bundleProposer.BundleORM().UpdateProvingStatus(context.Background(), bundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { - return fmt.Errorf("failed to update proving status: %w", err) - } - if err = bundleProposer.BundleORM().UpdateRollupStatus(context.Background(), bundle.Hash, types.RollupFinalized); err != nil { - return fmt.Errorf("failed to update rollup status: %w", err) - } - - log.Info("Inserted last finalized bundle to DB", "bundle", bundle.Index, "hash", bundle.Hash, "StartBatchIndex", bundle.StartBatchIndex, "EndBatchIndex", bundle.EndBatchIndex) - - return nil - }) - if err != nil { - return nil, nil, nil, fmt.Errorf("failed to insert bundle: %w", err) - } - - return chunk, batch, bundle, nil -} diff --git a/rollup/internal/config/recovery.go b/rollup/internal/config/recovery.go index 40afb4bf35..1d5c25669c 100644 --- a/rollup/internal/config/recovery.go +++ b/rollup/internal/config/recovery.go @@ -3,8 +3,9 @@ package config type RecoveryConfig struct { Enable bool `json:"enable"` - LatestFinalizedBatch uint64 `json:"latest_finalized_batch"` - L1BlockHeight uint64 `json:"l1_block_height"` + L1BlockHeight uint64 `json:"l1_block_height"` + LatestFinalizedBatch uint64 `json:"latest_finalized_batch"` // the latest finalized batch number + ForceLatestFinalizedBatch bool `json:"force_latest_finalized_batch"` // whether to force usage of the latest finalized batch - mainly used for testing L2BlockHeightLimit uint64 `json:"l2_block_height_limit"` ForceL1MessageCount uint64 `json:"force_l1_message_count"` diff --git a/rollup/internal/controller/permissionless_batches/recovery.go b/rollup/internal/controller/permissionless_batches/recovery.go new file mode 100644 index 0000000000..4cc8e1ae91 --- /dev/null +++ b/rollup/internal/controller/permissionless_batches/recovery.go @@ -0,0 +1,334 @@ +package permissionless_batches + +import ( + "context" + "fmt" + + "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/core" + "github.com/scroll-tech/go-ethereum/ethclient" + "github.com/scroll-tech/go-ethereum/log" + "github.com/scroll-tech/go-ethereum/rollup/l1" + "gorm.io/gorm" + + "scroll-tech/common/types" + "scroll-tech/database/migrate" + "scroll-tech/rollup/internal/config" + "scroll-tech/rollup/internal/controller/watcher" + "scroll-tech/rollup/internal/orm" +) + +type Recovery struct { + ctx context.Context + cfg *config.Config + genesis *core.Genesis + db *gorm.DB + chunkORM *orm.Chunk + batchORM *orm.Batch + bundleORM *orm.Bundle + + chunkProposer *watcher.ChunkProposer + batchProposer *watcher.BatchProposer + bundleProposer *watcher.BundleProposer + l2Watcher *watcher.L2WatcherClient +} + +func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) *Recovery { + return &Recovery{ + ctx: ctx, + cfg: cfg, + genesis: genesis, + db: db, + chunkORM: orm.NewChunk(db), + batchORM: orm.NewBatch(db), + bundleORM: orm.NewBundle(db), + chunkProposer: chunkProposer, + batchProposer: batchProposer, + bundleProposer: bundleProposer, + l2Watcher: l2Watcher, + } +} + +// TODO: check if recovery is needed by looking at DB and expected chunks/batches/bundles. +func (r *Recovery) RecoveryNeeded() bool { + return true +} + +func (r *Recovery) Run() error { + // Make sure we start from a clean state. + if err := r.resetDB(); err != nil { + return fmt.Errorf("failed to reset DB: %w", err) + } + + // Restore minimal previous state required to be able to create new chunks, batches and bundles. + latestFinalizedChunk, latestFinalizedBatch, latestFinalizedBundle, err := r.restoreMinimalPreviousState() + if err != nil { + return fmt.Errorf("failed to restore minimal previous state: %w", err) + } + + // Fetch and insert the missing blocks from the last block in the latestFinalizedBatch to the latest L2 block. + fromBlock := latestFinalizedChunk.EndBlockNumber + 1 + toBlock, err := r.fetchL2Blocks(fromBlock, r.cfg.RecoveryConfig.L2BlockHeightLimit) + if err != nil { + return fmt.Errorf("failed to fetch L2 blocks: %w", err) + } + + // Create chunks for L2 blocks. + log.Info("Creating chunks for L2 blocks", "from", fromBlock, "to", toBlock) + + var latestChunk *orm.Chunk + var count int + for { + if err = r.chunkProposer.ProposeChunk(); err != nil { + return fmt.Errorf("failed to propose chunk: %w", err) + } + count++ + + latestChunk, err = r.chunkORM.GetLatestChunk(r.ctx) + if err != nil { + return fmt.Errorf("failed to get latest latestFinalizedChunk: %w", err) + } + + log.Info("Chunk created", "index", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) + + // We have created chunks for all available L2 blocks. + if latestChunk.EndBlockNumber >= toBlock { + break + } + } + + log.Info("Chunks created", "count", count, "latest latestFinalizedChunk", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) + + // Create batch for the created chunks. We only allow 1 batch it needs to be submitted (and finalized) with a proof in a single step. + log.Info("Creating batch for chunks", "from", latestFinalizedChunk.Index+1, "to", latestChunk.Index) + + r.batchProposer.TryProposeBatch() + latestBatch, err := r.batchORM.GetLatestBatch(r.ctx) + if err != nil { + return fmt.Errorf("failed to get latest latestFinalizedBatch: %w", err) + } + + // Sanity check that the batch was created correctly: + // 1. should be a new batch + // 2. should contain all chunks created + if latestFinalizedBatch.Index != latestBatch.Index { + return fmt.Errorf("batch was not created correctly, expected %d but got %d", latestFinalizedBatch.Index+1, latestBatch.Index) + } + + firstChunkInBatch, err := r.chunkORM.GetChunkByIndex(r.ctx, latestBatch.EndChunkIndex) + if err != nil { + return fmt.Errorf("failed to get first chunk in batch: %w", err) + } + lastChunkInBatch, err := r.chunkORM.GetChunkByIndex(r.ctx, latestBatch.EndChunkIndex) + if err != nil { + return fmt.Errorf("failed to get last chunk in batch: %w", err) + } + + // Make sure that the batch contains all previously created chunks and thus all blocks. If not the user will need to + // produce another batch (running the application again) starting from the end block of the last chunk in the batch + 1. + if latestBatch.EndChunkIndex != latestChunk.Index { + log.Warn("Produced batch does not contain all chunks and blocks. You'll need to produce another batch starting from end block+1.", "starting block", firstChunkInBatch.StartBlockNumber, "end block", lastChunkInBatch.EndBlockNumber, "latest block", latestChunk.EndBlockNumber) + } + + log.Info("Batch created", "index", latestBatch.Index, "hash", latestBatch.Hash, "StartChunkIndex", latestBatch.StartChunkIndex, "EndChunkIndex", latestBatch.EndChunkIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) + + r.bundleProposer.TryProposeBundle() + latestBundle, err := r.bundleORM.GetLatestBundle(r.ctx) + if err != nil { + return fmt.Errorf("failed to get latest bundle: %w", err) + } + + // Sanity check that the bundle was created correctly: + // 1. should be a new bundle + // 2. should only contain 1 batch, the one we created + if latestFinalizedBundle.Index == latestBundle.Index { + return fmt.Errorf("bundle was not created correctly") + } + if latestBundle.StartBatchIndex != latestBatch.Index || latestBundle.EndBatchIndex != latestBatch.Index { + return fmt.Errorf("bundle does not contain the correct batch: %d != %d", latestBundle.StartBatchIndex, latestBatch.Index) + } + + log.Info("Bundle created", "index", latestBundle.Index, "hash", latestBundle.Hash, "StartBatchIndex", latestBundle.StartBatchIndex, "EndBatchIndex", latestBundle.EndBatchIndex, "starting block", firstChunkInBatch.StartBlockNumber, "ending block", lastChunkInBatch.EndBlockNumber) + + return nil +} + +// restoreMinimalPreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. +func (r *Recovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, *orm.Bundle, error) { + log.Info("Restoring previous state with", "L1 block height", r.cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", r.cfg.RecoveryConfig.LatestFinalizedBatch) + + l1Client, err := ethclient.Dial(r.cfg.L1Config.Endpoint) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to connect to L1 client: %w", err) + } + reader, err := l1.NewReader(r.ctx, l1.Config{ + ScrollChainAddress: r.genesis.Config.Scroll.L1Config.ScrollChainAddress, + L1MessageQueueAddress: r.genesis.Config.Scroll.L1Config.L1MessageQueueAddress, + }, l1Client) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to create L1 reader: %w", err) + } + + // 1. Sanity check user input: Make sure that the user's L1 block height is not higher than the latest finalized block number. + latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to get latest finalized L1 block number: %w", err) + } + if r.cfg.RecoveryConfig.L1BlockHeight > latestFinalizedL1Block { + return nil, nil, nil, fmt.Errorf("specified L1 block height is higher than the latest finalized block number: %d > %d", r.cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block) + } + + log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) + + // 2. Make sure that the specified batch is indeed finalized on the L1 rollup contract and is the latest finalized batch. + var latestFinalizedBatch uint64 + if r.cfg.RecoveryConfig.ForceLatestFinalizedBatch { + latestFinalizedBatch = r.cfg.RecoveryConfig.LatestFinalizedBatch + } else { + latestFinalizedBatch, err = reader.LatestFinalizedBatch(latestFinalizedL1Block) + if r.cfg.RecoveryConfig.LatestFinalizedBatch != latestFinalizedBatch { + return nil, nil, nil, fmt.Errorf("batch %d is not the latest finalized batch: %d", r.cfg.RecoveryConfig.LatestFinalizedBatch, latestFinalizedBatch) + } + } + + var batchCommitEvent *l1.CommitBatchEvent + err = reader.FetchRollupEventsInRangeWithCallback(r.cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block, func(event l1.RollupEvent) bool { + if event.Type() == l1.CommitEventType && event.BatchIndex().Uint64() == r.cfg.RecoveryConfig.LatestFinalizedBatch { + batchCommitEvent = event.(*l1.CommitBatchEvent) + return false + } + + return true + }) + if batchCommitEvent == nil { + return nil, nil, nil, fmt.Errorf("commit event not found for batch %d", r.cfg.RecoveryConfig.LatestFinalizedBatch) + } + + log.Info("Found commit event for batch", "batch", batchCommitEvent.BatchIndex(), "hash", batchCommitEvent.BatchHash(), "L1 block height", batchCommitEvent.BlockNumber(), "L1 tx hash", batchCommitEvent.TxHash()) + + // 3. Fetch commit tx data for latest finalized batch. + args, err := reader.FetchCommitTxData(batchCommitEvent) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to fetch commit tx data: %w", err) + } + + codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to get codec: %w", err) + } + + daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to decode DA chunks: %w", err) + } + lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] + lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + + log.Info("Last L2 block in batch", "batch", batchCommitEvent.BatchIndex(), "L2 block", lastBlockInBatch) + + // 4. Get the L1 messages count after the latest finalized batch. + var l1MessagesCount uint64 + if r.cfg.RecoveryConfig.ForceL1MessageCount == 0 { + l1MessagesCount, err = reader.FinalizedL1MessageQueueIndex(latestFinalizedL1Block) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to get L1 messages count: %w", err) + } + } else { + l1MessagesCount = r.cfg.RecoveryConfig.ForceL1MessageCount + } + + log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) + + // 5. Insert minimal state to DB. + chunk, err := r.chunkORM.InsertChunkRaw(r.ctx, codec.Version(), lastChunk, l1MessagesCount) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) + } + + log.Info("Inserted last finalized chunk to DB", "chunk", chunk.Index, "hash", chunk.Hash, "StartBlockNumber", chunk.StartBlockNumber, "EndBlockNumber", chunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", chunk.TotalL1MessagesPoppedBefore) + + batch, err := r.batchORM.InsertBatchRaw(r.ctx, batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) + } + + log.Info("Inserted last finalized batch to DB", "batch", batch.Index, "hash", batch.Hash) + + var bundle *orm.Bundle + err = r.db.Transaction(func(dbTX *gorm.DB) error { + bundle, err = r.bundleORM.InsertBundle(r.ctx, []*orm.Batch{batch}, encoding.CodecVersion(batch.CodecVersion), dbTX) + if err != nil { + return fmt.Errorf("failed to insert bundle: %w", err) + } + if err = r.bundleORM.UpdateProvingStatus(r.ctx, bundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status: %w", err) + } + if err = r.bundleORM.UpdateRollupStatus(r.ctx, bundle.Hash, types.RollupFinalized); err != nil { + return fmt.Errorf("failed to update rollup status: %w", err) + } + + log.Info("Inserted last finalized bundle to DB", "bundle", bundle.Index, "hash", bundle.Hash, "StartBatchIndex", bundle.StartBatchIndex, "EndBatchIndex", bundle.EndBatchIndex) + + return nil + }) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to insert bundle: %w", err) + } + + return chunk, batch, bundle, nil +} + +func (r *Recovery) fetchL2Blocks(fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) { + if l2BlockHeightLimit > 0 && fromBlock > l2BlockHeightLimit { + return 0, fmt.Errorf("fromBlock (latest finalized L2 block) is higher than specified L2BlockHeightLimit: %d > %d", fromBlock, l2BlockHeightLimit) + } + + log.Info("Fetching L2 blocks with", "fromBlock", fromBlock, "l2BlockHeightLimit", l2BlockHeightLimit) + + // Fetch and insert the missing blocks from the last block in the batch to the latest L2 block. + latestL2Block, err := r.l2Watcher.Client.BlockNumber(r.ctx) + if err != nil { + return 0, fmt.Errorf("failed to get latest L2 block number: %w", err) + } + + log.Info("Latest L2 block number", "latest L2 block", latestL2Block) + + if l2BlockHeightLimit > latestL2Block { + return 0, fmt.Errorf("l2BlockHeightLimit is higher than the latest L2 block number, not all blocks are available in L2geth: %d > %d", l2BlockHeightLimit, latestL2Block) + } + + toBlock := latestL2Block + if l2BlockHeightLimit > 0 { + toBlock = l2BlockHeightLimit + } + + err = r.l2Watcher.GetAndStoreBlocks(r.ctx, fromBlock, toBlock) + if err != nil { + return 0, fmt.Errorf("failed to get and store blocks: %w", err) + } + + log.Info("Fetched L2 blocks from", "fromBlock", fromBlock, "toBlock", toBlock) + + return toBlock, nil +} + +func (r *Recovery) resetDB() error { + sqlDB, err := r.db.DB() + if err != nil { + return fmt.Errorf("failed to get db connection: %w", err) + } + + // reset and init DB + var v int64 + err = migrate.Rollback(sqlDB, &v) + if err != nil { + return fmt.Errorf("failed to rollback db: %w", err) + } + + err = migrate.Migrate(sqlDB) + if err != nil { + return fmt.Errorf("failed to migrate db: %w", err) + } + + return nil +} diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index e565d88f31..ec25c8f247 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -149,10 +149,6 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, chai return p } -func (p *BatchProposer) BatchORM() *orm.Batch { - return p.batchOrm -} - // TryProposeBatch tries to propose a new batches. func (p *BatchProposer) TryProposeBatch() { p.batchProposerCircleTotal.Inc() diff --git a/rollup/internal/controller/watcher/bundle_proposer.go b/rollup/internal/controller/watcher/bundle_proposer.go index ca53da3909..686ad580c0 100644 --- a/rollup/internal/controller/watcher/bundle_proposer.go +++ b/rollup/internal/controller/watcher/bundle_proposer.go @@ -86,10 +86,6 @@ func NewBundleProposer(ctx context.Context, cfg *config.BundleProposerConfig, ch return p } -func (p *BundleProposer) BundleORM() *orm.Bundle { - return p.bundleOrm -} - // TryProposeBundle tries to propose a new bundle. func (p *BundleProposer) TryProposeBundle() { p.bundleProposerCircleTotal.Inc() diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 03cd3c25fc..0b0d5a6ba4 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -174,10 +174,6 @@ func (p *ChunkProposer) TryProposeChunk() { } } -func (p *ChunkProposer) ChunkORM() *orm.Chunk { - return p.chunkOrm -} - func (p *ChunkProposer) updateDBChunkInfo(chunk *encoding.Chunk, codecVersion encoding.CodecVersion, metrics *utils.ChunkMetrics) error { if chunk == nil { return nil From 0108873709ae90700c9860c23544317d874e60d6 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:24:53 +0800 Subject: [PATCH 16/25] implement RecoveryNeeded functionality to allow re-running without overriding and instead switching to batch submission mode --- rollup/cmd/permissionless_batches/app/app.go | 1 + .../permissionless_batches/recovery.go | 46 +++++++++++++++---- .../internal/controller/watcher/l2_watcher.go | 4 -- rollup/internal/orm/chunk.go | 4 +- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/rollup/cmd/permissionless_batches/app/app.go b/rollup/cmd/permissionless_batches/app/app.go index 7be08523db..e359927477 100644 --- a/rollup/cmd/permissionless_batches/app/app.go +++ b/rollup/cmd/permissionless_batches/app/app.go @@ -95,6 +95,7 @@ func action(ctx *cli.Context) error { } log.Info("Success! You're ready to generate proofs!") } else { + // TODO: implement batch submission if proofs are available log.Info("TODO: Batch submission") } diff --git a/rollup/internal/controller/permissionless_batches/recovery.go b/rollup/internal/controller/permissionless_batches/recovery.go index 4cc8e1ae91..98554aa7c6 100644 --- a/rollup/internal/controller/permissionless_batches/recovery.go +++ b/rollup/internal/controller/permissionless_batches/recovery.go @@ -18,6 +18,11 @@ import ( "scroll-tech/rollup/internal/orm" ) +const ( + defaultRestoredChunkIndex uint64 = 1337 + defaultRestoredBundleIndex uint64 = 1 +) + type Recovery struct { ctx context.Context cfg *config.Config @@ -49,9 +54,32 @@ func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, } } -// TODO: check if recovery is needed by looking at DB and expected chunks/batches/bundles. func (r *Recovery) RecoveryNeeded() bool { - return true + chunk, err := r.chunkORM.GetLatestChunk(r.ctx) + if err != nil { + return true + } + if chunk.Index <= defaultRestoredChunkIndex { + return true + } + + batch, err := r.batchORM.GetLatestBatch(r.ctx) + if err != nil { + return true + } + if batch.Index <= r.cfg.RecoveryConfig.LatestFinalizedBatch { + return true + } + + bundle, err := r.bundleORM.GetLatestBundle(r.ctx) + if err != nil { + return true + } + if bundle.Index <= defaultRestoredBundleIndex { + return true + } + + return false } func (r *Recovery) Run() error { @@ -61,13 +89,13 @@ func (r *Recovery) Run() error { } // Restore minimal previous state required to be able to create new chunks, batches and bundles. - latestFinalizedChunk, latestFinalizedBatch, latestFinalizedBundle, err := r.restoreMinimalPreviousState() + restoredFinalizedChunk, restoredFinalizedBatch, restoredFinalizedBundle, err := r.restoreMinimalPreviousState() if err != nil { return fmt.Errorf("failed to restore minimal previous state: %w", err) } // Fetch and insert the missing blocks from the last block in the latestFinalizedBatch to the latest L2 block. - fromBlock := latestFinalizedChunk.EndBlockNumber + 1 + fromBlock := restoredFinalizedChunk.EndBlockNumber + 1 toBlock, err := r.fetchL2Blocks(fromBlock, r.cfg.RecoveryConfig.L2BlockHeightLimit) if err != nil { return fmt.Errorf("failed to fetch L2 blocks: %w", err) @@ -100,7 +128,7 @@ func (r *Recovery) Run() error { log.Info("Chunks created", "count", count, "latest latestFinalizedChunk", latestChunk.Index, "hash", latestChunk.Hash, "StartBlockNumber", latestChunk.StartBlockNumber, "EndBlockNumber", latestChunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", latestChunk.TotalL1MessagesPoppedBefore) // Create batch for the created chunks. We only allow 1 batch it needs to be submitted (and finalized) with a proof in a single step. - log.Info("Creating batch for chunks", "from", latestFinalizedChunk.Index+1, "to", latestChunk.Index) + log.Info("Creating batch for chunks", "from", restoredFinalizedChunk.Index+1, "to", latestChunk.Index) r.batchProposer.TryProposeBatch() latestBatch, err := r.batchORM.GetLatestBatch(r.ctx) @@ -111,8 +139,8 @@ func (r *Recovery) Run() error { // Sanity check that the batch was created correctly: // 1. should be a new batch // 2. should contain all chunks created - if latestFinalizedBatch.Index != latestBatch.Index { - return fmt.Errorf("batch was not created correctly, expected %d but got %d", latestFinalizedBatch.Index+1, latestBatch.Index) + if restoredFinalizedBatch.Index+1 != latestBatch.Index { + return fmt.Errorf("batch was not created correctly, expected %d but got %d", restoredFinalizedBatch.Index+1, latestBatch.Index) } firstChunkInBatch, err := r.chunkORM.GetChunkByIndex(r.ctx, latestBatch.EndChunkIndex) @@ -141,7 +169,7 @@ func (r *Recovery) Run() error { // Sanity check that the bundle was created correctly: // 1. should be a new bundle // 2. should only contain 1 batch, the one we created - if latestFinalizedBundle.Index == latestBundle.Index { + if restoredFinalizedBundle.Index == latestBundle.Index { return fmt.Errorf("bundle was not created correctly") } if latestBundle.StartBatchIndex != latestBatch.Index || latestBundle.EndBatchIndex != latestBatch.Index { @@ -240,7 +268,7 @@ func (r *Recovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, *orm.B log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) // 5. Insert minimal state to DB. - chunk, err := r.chunkORM.InsertChunkRaw(r.ctx, codec.Version(), lastChunk, l1MessagesCount) + chunk, err := r.chunkORM.InsertChunkRaw(r.ctx, defaultRestoredChunkIndex, codec.Version(), lastChunk, l1MessagesCount) if err != nil { return nil, nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) } diff --git a/rollup/internal/controller/watcher/l2_watcher.go b/rollup/internal/controller/watcher/l2_watcher.go index 2ceba4d049..9f8848e5c8 100644 --- a/rollup/internal/controller/watcher/l2_watcher.go +++ b/rollup/internal/controller/watcher/l2_watcher.go @@ -60,10 +60,6 @@ func NewL2WatcherClient(ctx context.Context, client *ethclient.Client, confirmat const blocksFetchLimit = uint64(10) -func (w *L2WatcherClient) BlockORM() *orm.L2Block { - return w.l2BlockOrm -} - // TryFetchRunningMissingBlocks attempts to fetch and store block traces for any missing blocks. func (w *L2WatcherClient) TryFetchRunningMissingBlocks(blockHeight uint64) error { w.metrics.fetchRunningMissingBlocksTotal.Inc() diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index e24e7a35b0..b8eb4bab4f 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -257,7 +257,7 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer return &newChunk, nil } -func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) (*Chunk, error) { +func (o *Chunk) InsertChunkRaw(ctx context.Context, index uint64, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) (*Chunk, error) { // Create some unique identifier. It is not really used for anything except in DB. var chunkBytes []byte for _, block := range chunk.Blocks { @@ -269,7 +269,7 @@ func (o *Chunk) InsertChunkRaw(ctx context.Context, codecVersion encoding.CodecV numBlocks := len(chunk.Blocks) emptyHash := common.Hash{}.Hex() newChunk := &Chunk{ - Index: 1337, + Index: index, Hash: hash.Hex(), StartBlockNumber: chunk.Blocks[0].Number(), StartBlockHash: emptyHash, From a6f914a896a1b6e0340b27df95ab82e95bac62a8 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Wed, 20 Nov 2024 20:11:56 +0800 Subject: [PATCH 17/25] refactor cmd/rollup_relayer/app and split into FullRecovery struct --- rollup/cmd/rollup_relayer/app/app.go | 336 +--------------- .../{recovery.go => minimal_recovery.go} | 16 +- .../controller/relayer/full_recovery.go | 360 ++++++++++++++++++ 3 files changed, 382 insertions(+), 330 deletions(-) rename rollup/internal/controller/permissionless_batches/{recovery.go => minimal_recovery.go} (96%) create mode 100644 rollup/internal/controller/relayer/full_recovery.go diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index bd4a81a2ff..e169635a12 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -8,23 +8,18 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" - "github.com/scroll-tech/da-codec/encoding" - "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/ethclient" "github.com/scroll-tech/go-ethereum/log" "github.com/scroll-tech/go-ethereum/rollup/l1" "github.com/urfave/cli/v2" - "gorm.io/gorm" "scroll-tech/common/database" "scroll-tech/common/observability" - "scroll-tech/common/types" "scroll-tech/common/utils" "scroll-tech/common/version" "scroll-tech/rollup/internal/config" "scroll-tech/rollup/internal/controller/relayer" "scroll-tech/rollup/internal/controller/watcher" - "scroll-tech/rollup/internal/orm" butils "scroll-tech/rollup/internal/utils" ) @@ -98,7 +93,20 @@ func action(ctx *cli.Context) error { if cfg.RecoveryConfig.Enable { log.Info("Starting rollup-relayer in recovery mode", "version", version.Version) - if err = restoreFullPreviousState(cfg, db, chunkProposer, batchProposer, bundleProposer, l2watcher); err != nil { + l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) + if err != nil { + return fmt.Errorf("failed to connect to L1 client: %w", err) + } + reader, err := l1.NewReader(context.Background(), l1.Config{ + ScrollChainAddress: genesis.Config.Scroll.L1Config.ScrollChainAddress, + L1MessageQueueAddress: genesis.Config.Scroll.L1Config.L1MessageQueueAddress, + }, l1Client) + if err != nil { + return fmt.Errorf("failed to create L1 reader: %w", err) + } + + fullRecovery := relayer.NewFullRecovery(subCtx, cfg, genesis, db, chunkProposer, batchProposer, bundleProposer, l2watcher, l1Client, reader) + if err = fullRecovery.RestoreFullPreviousState(); err != nil { log.Crit("failed to restore full previous state", "error", err) } @@ -148,319 +156,3 @@ func Run() { os.Exit(1) } } - -func restoreFullPreviousState(cfg *config.Config, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) error { - log.Info("Restoring full previous state with", "L1 block height", cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", cfg.RecoveryConfig.LatestFinalizedBatch) - - // DB state should be clean: the latest batch in the DB should be finalized on L1. This function will - // restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1. - - // 1. Get latest finalized batch stored in DB - latestDBBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) - if err != nil { - return fmt.Errorf("failed to get latest batch from DB: %w", err) - } - fmt.Println("latestDBBatch", latestDBBatch) - - // TODO: - // 1. what if it is a fresh start? -> latest batch is nil - //latestDBBatch.CommitTxHash - - log.Info("Latest finalized batch in DB", "batch", latestDBBatch.Index, "hash", latestDBBatch.Hash) - - // TODO: make these parameters -> part of genesis config? - scrollChainAddress := common.HexToAddress("0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0") - l1MessageQueueAddress := common.HexToAddress("0xF0B2293F5D834eAe920c6974D50957A1732de763") - - l1Client, err := ethclient.Dial(cfg.L1Config.Endpoint) - if err != nil { - return fmt.Errorf("failed to connect to L1 client: %w", err) - } - reader, err := l1.NewReader(context.Background(), l1.Config{ - ScrollChainAddress: scrollChainAddress, - L1MessageQueueAddress: l1MessageQueueAddress, - }, l1Client) - if err != nil { - return fmt.Errorf("failed to create L1 reader: %w", err) - } - - // 2. Get latest finalized L1 block - latestFinalizedL1Block, err := reader.GetLatestFinalizedBlockNumber() - if err != nil { - return fmt.Errorf("failed to get latest finalized L1 block number: %w", err) - } - - log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) - - // 3. Get latest finalized batch from contract (at latest finalized L1 block) - latestFinalizedBatch, err := reader.LatestFinalizedBatch(latestFinalizedL1Block) - if err != nil { - return fmt.Errorf("failed to get latest finalized batch: %w", err) - } - - log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatch, "at latest finalized L1 block", latestFinalizedL1Block) - - // 4. Get batches one by one from stored in DB to latest finalized batch. - receipt, err := l1Client.TransactionReceipt(context.Background(), common.HexToHash(latestDBBatch.CommitTxHash)) - if err != nil { - return fmt.Errorf("failed to get transaction receipt of latest DB batch finalization transaction: %w", err) - } - fromBlock := receipt.BlockNumber.Uint64() - - log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatch) - - commitsHeapMap := common.NewHeapMap[uint64, *l1.CommitBatchEvent](func(event *l1.CommitBatchEvent) uint64 { - return event.BatchIndex().Uint64() - }) - batchEventsHeap := common.NewHeap[*batchEvents]() - var bundles [][]*batchEvents - - err = reader.FetchRollupEventsInRangeWithCallback(fromBlock, latestFinalizedL1Block, func(event l1.RollupEvent) bool { - // We're only interested in batches that are newer than the latest finalized batch in the DB. - if event.BatchIndex().Uint64() <= latestDBBatch.Index { - return true - } - - switch event.Type() { - case l1.CommitEventType: - commitEvent := event.(*l1.CommitBatchEvent) - commitsHeapMap.Push(commitEvent) - - case l1.FinalizeEventType: - finalizeEvent := event.(*l1.FinalizeBatchEvent) - - var bundle []*batchEvents - - // with bundles all commited batches until this finalized batch are finalized in the same bundle - for commitsHeapMap.Len() > 0 { - commitEvent := commitsHeapMap.Peek() - if commitEvent.BatchIndex().Uint64() > finalizeEvent.BatchIndex().Uint64() { - break - } - - bEvents := newBatchEvents(commitEvent, finalizeEvent) - commitsHeapMap.Pop() - batchEventsHeap.Push(bEvents) - bundle = append(bundle, bEvents) - } - - bundles = append(bundles, bundle) - - // Stop fetching rollup events if we reached the latest finalized batch. - if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatch { - return false - } - - case l1.RevertEventType: - // We ignore reverted batches. - commitsHeapMap.RemoveByKey(event.BatchIndex().Uint64()) - } - - return true - }) - if err != nil { - return fmt.Errorf("failed to fetch rollup events: %w", err) - } - - // 5. Process all finalized batches: fetch L2 blocks and reproduce chunks and batches. - for batchEventsHeap.Len() > 0 { - nextBatch := batchEventsHeap.Pop().Value() - fmt.Println("nextBatch", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), nextBatch.finalize.BatchIndex(), nextBatch.finalize.BatchHash()) - if err = processFinalizedBatch(db, reader, nextBatch, chunkProposer, batchProposer, l2Watcher); err != nil { - return fmt.Errorf("failed to process finalized batch %d %s: %w", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), err) - } - - log.Info("Processed finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) - } - - // 6. Create bundles if needed. - for _, bundle := range bundles { - var dbBatches []*orm.Batch - var lastBatchInBundle *orm.Batch - - for _, batch := range bundle { - dbBatch, err := batchProposer.BatchORM().GetBatchByIndex(context.Background(), batch.commit.BatchIndex().Uint64()) - if err != nil { - return fmt.Errorf("failed to get batch by index for bundle generation: %w", err) - } - // Bundles are only supported for codec version 3 and above. - if encoding.CodecVersion(dbBatch.CodecVersion) < encoding.CodecV3 { - break - } - - dbBatches = append(dbBatches, dbBatch) - lastBatchInBundle = dbBatch - } - - if len(dbBatches) == 0 { - continue - } - - err = db.Transaction(func(dbTX *gorm.DB) error { - newBundle, err := bundleProposer.BundleORM().InsertBundle(context.Background(), dbBatches, encoding.CodecVersion(lastBatchInBundle.CodecVersion), dbTX) - if err != nil { - return fmt.Errorf("failed to insert bundle to DB: %w", err) - } - if err = batchProposer.BatchORM().UpdateBundleHashInRange(context.Background(), newBundle.StartBatchIndex, newBundle.EndBatchIndex, newBundle.Hash, dbTX); err != nil { - return fmt.Errorf("failed to update bundle_hash %s for batches (%d to %d): %w", newBundle.Hash, newBundle.StartBatchIndex, newBundle.EndBatchIndex, err) - } - - if err = bundleProposer.BundleORM().UpdateFinalizeTxHashAndRollupStatus(context.Background(), newBundle.Hash, lastBatchInBundle.FinalizeTxHash, types.RollupFinalized, dbTX); err != nil { - return fmt.Errorf("failed to update finalize tx hash and rollup status for bundle %s: %w", newBundle.Hash, err) - } - - if err = bundleProposer.BundleORM().UpdateProvingStatus(context.Background(), newBundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { - return fmt.Errorf("failed to update proving status for bundle %s: %w", newBundle.Hash, err) - } - - return nil - }) - if err != nil { - return fmt.Errorf("failed to insert bundle in DB transaction: %w", err) - } - - fmt.Println("bundle", len(bundle), bundle[0].commit.BatchIndex()) - } - - return nil -} - -func processFinalizedBatch(db *gorm.DB, reader *l1.Reader, nextBatch *batchEvents, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, l2Watcher *watcher.L2WatcherClient) error { - log.Info("Processing finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) - - // 5.1. Fetch commit tx data for batch (via commit event). - args, err := reader.FetchCommitTxData(nextBatch.commit) - if err != nil { - return fmt.Errorf("failed to fetch commit tx data: %w", err) - } - - codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) - if err != nil { - return fmt.Errorf("failed to get codec: %w", err) - } - - daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) - if err != nil { - return fmt.Errorf("failed to decode DA chunks: %w", err) - } - lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] - lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() - - log.Info("Fetching L2 blocks from l2geth", "batch", nextBatch.commit.BatchIndex(), "last L2 block in batch", lastBlockInBatch) - - // 5.2. Fetch L2 blocks for the entire batch. - if err = l2Watcher.TryFetchRunningMissingBlocks(lastBlockInBatch); err != nil { - return fmt.Errorf("failed to fetch L2 blocks: %w", err) - } - - // 5.3. Reproduce chunks. - daChunks := make([]*encoding.Chunk, 0, len(daChunksRawTxs)) - dbChunks := make([]*orm.Chunk, 0, len(daChunksRawTxs)) - for _, daChunkRawTxs := range daChunksRawTxs { - start := daChunkRawTxs.Blocks[0].Number() - end := daChunkRawTxs.Blocks[len(daChunkRawTxs.Blocks)-1].Number() - - blocks, err := l2Watcher.BlockORM().GetL2BlocksInRange(context.Background(), start, end) - if err != nil { - return fmt.Errorf("failed to get L2 blocks in range: %w", err) - } - - log.Info("Reproducing chunk", "start block", start, "end block", end) - - var chunk encoding.Chunk - for _, block := range blocks { - chunk.Blocks = append(chunk.Blocks, block) - } - - metrics, err := butils.CalculateChunkMetrics(&chunk, codec.Version()) - if err != nil { - return fmt.Errorf("failed to calculate chunk metrics: %w", err) - } - - err = db.Transaction(func(dbTX *gorm.DB) error { - dbChunk, err := chunkProposer.ChunkORM().InsertChunk(context.Background(), &chunk, codec.Version(), *metrics, dbTX) - if err != nil { - return fmt.Errorf("failed to insert chunk to DB: %w", err) - } - if err := l2Watcher.BlockORM().UpdateChunkHashInRange(context.Background(), dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, dbChunk.Hash, dbTX); err != nil { - return fmt.Errorf("failed to update chunk_hash for l2_blocks (chunk hash: %s, start block: %d, end block: %d): %w", dbChunk.Hash, dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, err) - } - - if err = chunkProposer.ChunkORM().UpdateProvingStatus(context.Background(), dbChunk.Hash, types.ProvingTaskVerified, dbTX); err != nil { - return fmt.Errorf("failed to update proving status for chunk %s: %w", dbChunk.Hash, err) - } - - daChunks = append(daChunks, &chunk) - dbChunks = append(dbChunks, dbChunk) - - return nil - }) - if err != nil { - return fmt.Errorf("failed to insert chunk in DB transaction: %w", err) - } - } - - // 5.4 Reproduce batch. - dbParentBatch, err := batchProposer.BatchORM().GetLatestBatch(context.Background()) - if err != nil { - return fmt.Errorf("failed to get latest batch from DB: %w", err) - } - - var batch encoding.Batch - batch.Index = dbParentBatch.Index + 1 - batch.ParentBatchHash = common.HexToHash(dbParentBatch.Hash) - batch.TotalL1MessagePoppedBefore = dbChunks[0].TotalL1MessagesPoppedBefore - - for _, chunk := range daChunks { - batch.Chunks = append(batch.Chunks, chunk) - } - - metrics, err := butils.CalculateBatchMetrics(&batch, codec.Version()) - if err != nil { - return fmt.Errorf("failed to calculate batch metrics: %w", err) - } - - err = db.Transaction(func(dbTX *gorm.DB) error { - dbBatch, err := batchProposer.BatchORM().InsertBatch(context.Background(), &batch, codec.Version(), *metrics, dbTX) - if err != nil { - return fmt.Errorf("failed to insert batch to DB: %w", err) - } - if err = chunkProposer.ChunkORM().UpdateBatchHashInRange(context.Background(), dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, dbBatch.Hash, dbTX); err != nil { - return fmt.Errorf("failed to update batch_hash for chunks (batch hash: %s, start chunk: %d, end chunk: %d): %w", dbBatch.Hash, dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, err) - } - - if err = batchProposer.BatchORM().UpdateProvingStatus(context.Background(), dbBatch.Hash, types.ProvingTaskVerified, dbTX); err != nil { - return fmt.Errorf("failed to update proving status for batch %s: %w", dbBatch.Hash, err) - } - if err = batchProposer.BatchORM().UpdateRollupStatusCommitAndFinalizeTxHash(context.Background(), dbBatch.Hash, types.RollupFinalized, nextBatch.commit.TxHash().Hex(), nextBatch.finalize.TxHash().Hex(), dbTX); err != nil { - return fmt.Errorf("failed to update rollup status for batch %s: %w", dbBatch.Hash, err) - } - - return nil - }) - if err != nil { - return fmt.Errorf("failed to insert batch in DB transaction: %w", err) - } - - return nil -} - -type batchEvents struct { - commit *l1.CommitBatchEvent - finalize *l1.FinalizeBatchEvent -} - -func newBatchEvents(commit *l1.CommitBatchEvent, finalize *l1.FinalizeBatchEvent) *batchEvents { - if commit.BatchIndex().Uint64() != finalize.BatchIndex().Uint64() { - panic("commit and finalize batch indexes do not match") - } - - return &batchEvents{ - commit: commit, - finalize: finalize, - } -} - -func (e *batchEvents) CompareTo(other *batchEvents) int { - return e.commit.BatchIndex().Cmp(other.commit.BatchIndex()) -} diff --git a/rollup/internal/controller/permissionless_batches/recovery.go b/rollup/internal/controller/permissionless_batches/minimal_recovery.go similarity index 96% rename from rollup/internal/controller/permissionless_batches/recovery.go rename to rollup/internal/controller/permissionless_batches/minimal_recovery.go index 98554aa7c6..1f1437734c 100644 --- a/rollup/internal/controller/permissionless_batches/recovery.go +++ b/rollup/internal/controller/permissionless_batches/minimal_recovery.go @@ -23,7 +23,7 @@ const ( defaultRestoredBundleIndex uint64 = 1 ) -type Recovery struct { +type MinimalRecovery struct { ctx context.Context cfg *config.Config genesis *core.Genesis @@ -38,8 +38,8 @@ type Recovery struct { l2Watcher *watcher.L2WatcherClient } -func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) *Recovery { - return &Recovery{ +func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient) *MinimalRecovery { + return &MinimalRecovery{ ctx: ctx, cfg: cfg, genesis: genesis, @@ -54,7 +54,7 @@ func NewRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, } } -func (r *Recovery) RecoveryNeeded() bool { +func (r *MinimalRecovery) RecoveryNeeded() bool { chunk, err := r.chunkORM.GetLatestChunk(r.ctx) if err != nil { return true @@ -82,7 +82,7 @@ func (r *Recovery) RecoveryNeeded() bool { return false } -func (r *Recovery) Run() error { +func (r *MinimalRecovery) Run() error { // Make sure we start from a clean state. if err := r.resetDB(); err != nil { return fmt.Errorf("failed to reset DB: %w", err) @@ -182,7 +182,7 @@ func (r *Recovery) Run() error { } // restoreMinimalPreviousState restores the minimal previous state required to be able to create new chunks, batches and bundles. -func (r *Recovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, *orm.Bundle, error) { +func (r *MinimalRecovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, *orm.Bundle, error) { log.Info("Restoring previous state with", "L1 block height", r.cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", r.cfg.RecoveryConfig.LatestFinalizedBatch) l1Client, err := ethclient.Dial(r.cfg.L1Config.Endpoint) @@ -306,7 +306,7 @@ func (r *Recovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, *orm.B return chunk, batch, bundle, nil } -func (r *Recovery) fetchL2Blocks(fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) { +func (r *MinimalRecovery) fetchL2Blocks(fromBlock uint64, l2BlockHeightLimit uint64) (uint64, error) { if l2BlockHeightLimit > 0 && fromBlock > l2BlockHeightLimit { return 0, fmt.Errorf("fromBlock (latest finalized L2 block) is higher than specified L2BlockHeightLimit: %d > %d", fromBlock, l2BlockHeightLimit) } @@ -340,7 +340,7 @@ func (r *Recovery) fetchL2Blocks(fromBlock uint64, l2BlockHeightLimit uint64) (u return toBlock, nil } -func (r *Recovery) resetDB() error { +func (r *MinimalRecovery) resetDB() error { sqlDB, err := r.db.DB() if err != nil { return fmt.Errorf("failed to get db connection: %w", err) diff --git a/rollup/internal/controller/relayer/full_recovery.go b/rollup/internal/controller/relayer/full_recovery.go new file mode 100644 index 0000000000..3bde1b02fd --- /dev/null +++ b/rollup/internal/controller/relayer/full_recovery.go @@ -0,0 +1,360 @@ +package relayer + +import ( + "context" + "fmt" + + "github.com/scroll-tech/da-codec/encoding" + "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/core" + "github.com/scroll-tech/go-ethereum/ethclient" + "github.com/scroll-tech/go-ethereum/log" + "github.com/scroll-tech/go-ethereum/rollup/l1" + "gorm.io/gorm" + + "scroll-tech/common/types" + "scroll-tech/rollup/internal/config" + "scroll-tech/rollup/internal/controller/watcher" + "scroll-tech/rollup/internal/orm" + butils "scroll-tech/rollup/internal/utils" +) + +type FullRecovery struct { + ctx context.Context + cfg *config.Config + genesis *core.Genesis + db *gorm.DB + blockORM *orm.L2Block + chunkORM *orm.Chunk + batchORM *orm.Batch + bundleORM *orm.Bundle + + chunkProposer *watcher.ChunkProposer + batchProposer *watcher.BatchProposer + bundleProposer *watcher.BundleProposer + l2Watcher *watcher.L2WatcherClient + l1Client *ethclient.Client + l1Reader *l1.Reader +} + +func NewFullRecovery(ctx context.Context, cfg *config.Config, genesis *core.Genesis, db *gorm.DB, chunkProposer *watcher.ChunkProposer, batchProposer *watcher.BatchProposer, bundleProposer *watcher.BundleProposer, l2Watcher *watcher.L2WatcherClient, l1Client *ethclient.Client, l1Reader *l1.Reader) *FullRecovery { + return &FullRecovery{ + ctx: ctx, + cfg: cfg, + genesis: genesis, + db: db, + blockORM: orm.NewL2Block(db), + chunkORM: orm.NewChunk(db), + batchORM: orm.NewBatch(db), + bundleORM: orm.NewBundle(db), + + chunkProposer: chunkProposer, + batchProposer: batchProposer, + bundleProposer: bundleProposer, + l2Watcher: l2Watcher, + l1Client: l1Client, + l1Reader: l1Reader, + } +} + +// RestoreFullPreviousState restores the full state from L1. +// The DB state should be clean: the latest batch in the DB should be finalized on L1. This function will +// restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1. +func (f *FullRecovery) RestoreFullPreviousState() error { + log.Info("Restoring full previous state with", "L1 block height", f.cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", f.cfg.RecoveryConfig.LatestFinalizedBatch) + + // 1. Get latest finalized batch stored in DB + latestDBBatch, err := f.batchORM.GetLatestBatch(context.Background()) + if err != nil { + return fmt.Errorf("failed to get latest batch from DB: %w", err) + } + + // TODO: + // 1. what if it is a fresh start? -> latest batch is nil + //latestDBBatch.CommitTxHash + + log.Info("Latest finalized batch in DB", "batch", latestDBBatch.Index, "hash", latestDBBatch.Hash) + + // 2. Get latest finalized L1 block + latestFinalizedL1Block, err := f.l1Reader.GetLatestFinalizedBlockNumber() + if err != nil { + return fmt.Errorf("failed to get latest finalized L1 block number: %w", err) + } + + log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) + + // 3. Get latest finalized batch from contract (at latest finalized L1 block) + latestFinalizedBatch, err := f.l1Reader.LatestFinalizedBatch(latestFinalizedL1Block) + if err != nil { + return fmt.Errorf("failed to get latest finalized batch: %w", err) + } + + // TODO: remove this, just for debugging + latestFinalizedBatch = 82310 + log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatch, "at latest finalized L1 block", latestFinalizedL1Block) + + // 4. Get batches one by one from stored in DB to latest finalized batch. + receipt, err := f.l1Client.TransactionReceipt(context.Background(), common.HexToHash(latestDBBatch.CommitTxHash)) + if err != nil { + return fmt.Errorf("failed to get transaction receipt of latest DB batch finalization transaction: %w", err) + } + fromBlock := receipt.BlockNumber.Uint64() + + log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatch) + + commitsHeapMap := common.NewHeapMap[uint64, *l1.CommitBatchEvent](func(event *l1.CommitBatchEvent) uint64 { + return event.BatchIndex().Uint64() + }) + batchEventsHeap := common.NewHeap[*batchEvents]() + var bundles [][]*batchEvents + + err = f.l1Reader.FetchRollupEventsInRangeWithCallback(fromBlock, latestFinalizedL1Block, func(event l1.RollupEvent) bool { + // We're only interested in batches that are newer than the latest finalized batch in the DB. + if event.BatchIndex().Uint64() <= latestDBBatch.Index { + return true + } + + fmt.Println("event", event.Type(), event.BatchIndex().Uint64()) + + switch event.Type() { + case l1.CommitEventType: + commitEvent := event.(*l1.CommitBatchEvent) + commitsHeapMap.Push(commitEvent) + + case l1.FinalizeEventType: + finalizeEvent := event.(*l1.FinalizeBatchEvent) + + var bundle []*batchEvents + + // with bundles all commited batches until this finalized batch are finalized in the same bundle + for commitsHeapMap.Len() > 0 { + commitEvent := commitsHeapMap.Peek() + if commitEvent.BatchIndex().Uint64() > finalizeEvent.BatchIndex().Uint64() { + break + } + + bEvents := newBatchEvents(commitEvent, finalizeEvent) + commitsHeapMap.Pop() + batchEventsHeap.Push(bEvents) + bundle = append(bundle, bEvents) + } + + bundles = append(bundles, bundle) + + // Stop fetching rollup events if we reached the latest finalized batch. + if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatch { + return false + } + + case l1.RevertEventType: + // We ignore reverted batches. + commitsHeapMap.RemoveByKey(event.BatchIndex().Uint64()) + } + + return true + }) + if err != nil { + return fmt.Errorf("failed to fetch rollup events: %w", err) + } + + // 5. Process all finalized batches: fetch L2 blocks and reproduce chunks and batches. + for batchEventsHeap.Len() > 0 { + nextBatch := batchEventsHeap.Pop().Value() + if err = f.processFinalizedBatch(nextBatch); err != nil { + return fmt.Errorf("failed to process finalized batch %d %s: %w", nextBatch.commit.BatchIndex(), nextBatch.commit.BatchHash(), err) + } + + log.Info("Processed finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) + } + + // 6. Create bundles if needed. + for _, bundle := range bundles { + var dbBatches []*orm.Batch + var lastBatchInBundle *orm.Batch + + for _, batch := range bundle { + dbBatch, err := f.batchORM.GetBatchByIndex(context.Background(), batch.commit.BatchIndex().Uint64()) + if err != nil { + return fmt.Errorf("failed to get batch by index for bundle generation: %w", err) + } + // Bundles are only supported for codec version 3 and above. + if encoding.CodecVersion(dbBatch.CodecVersion) < encoding.CodecV3 { + break + } + + dbBatches = append(dbBatches, dbBatch) + lastBatchInBundle = dbBatch + } + + if len(dbBatches) == 0 { + continue + } + + err = f.db.Transaction(func(dbTX *gorm.DB) error { + newBundle, err := f.bundleORM.InsertBundle(context.Background(), dbBatches, encoding.CodecVersion(lastBatchInBundle.CodecVersion), dbTX) + if err != nil { + return fmt.Errorf("failed to insert bundle to DB: %w", err) + } + if err = f.batchORM.UpdateBundleHashInRange(context.Background(), newBundle.StartBatchIndex, newBundle.EndBatchIndex, newBundle.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update bundle_hash %s for batches (%d to %d): %w", newBundle.Hash, newBundle.StartBatchIndex, newBundle.EndBatchIndex, err) + } + + if err = f.bundleORM.UpdateFinalizeTxHashAndRollupStatus(context.Background(), newBundle.Hash, lastBatchInBundle.FinalizeTxHash, types.RollupFinalized, dbTX); err != nil { + return fmt.Errorf("failed to update finalize tx hash and rollup status for bundle %s: %w", newBundle.Hash, err) + } + + if err = f.bundleORM.UpdateProvingStatus(context.Background(), newBundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for bundle %s: %w", newBundle.Hash, err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to insert bundle in DB transaction: %w", err) + } + + fmt.Println("bundle", len(bundle), bundle[0].commit.BatchIndex()) + } + + return nil +} + +func (f *FullRecovery) processFinalizedBatch(nextBatch *batchEvents) error { + log.Info("Processing finalized batch", "batch", nextBatch.commit.BatchIndex(), "hash", nextBatch.commit.BatchHash()) + + // 5.1. Fetch commit tx data for batch (via commit event). + args, err := f.l1Reader.FetchCommitTxData(nextBatch.commit) + if err != nil { + return fmt.Errorf("failed to fetch commit tx data: %w", err) + } + + codec, err := encoding.CodecFromVersion(encoding.CodecVersion(args.Version)) + if err != nil { + return fmt.Errorf("failed to get codec: %w", err) + } + + daChunksRawTxs, err := codec.DecodeDAChunksRawTx(args.Chunks) + if err != nil { + return fmt.Errorf("failed to decode DA chunks: %w", err) + } + lastChunk := daChunksRawTxs[len(daChunksRawTxs)-1] + lastBlockInBatch := lastChunk.Blocks[len(lastChunk.Blocks)-1].Number() + + log.Info("Fetching L2 blocks from l2geth", "batch", nextBatch.commit.BatchIndex(), "last L2 block in batch", lastBlockInBatch) + + // 5.2. Fetch L2 blocks for the entire batch. + if err = f.l2Watcher.TryFetchRunningMissingBlocks(lastBlockInBatch); err != nil { + return fmt.Errorf("failed to fetch L2 blocks: %w", err) + } + + // 5.3. Reproduce chunks. + daChunks := make([]*encoding.Chunk, 0, len(daChunksRawTxs)) + dbChunks := make([]*orm.Chunk, 0, len(daChunksRawTxs)) + for _, daChunkRawTxs := range daChunksRawTxs { + start := daChunkRawTxs.Blocks[0].Number() + end := daChunkRawTxs.Blocks[len(daChunkRawTxs.Blocks)-1].Number() + + blocks, err := f.blockORM.GetL2BlocksInRange(context.Background(), start, end) + if err != nil { + return fmt.Errorf("failed to get L2 blocks in range: %w", err) + } + + log.Info("Reproducing chunk", "start block", start, "end block", end) + + var chunk encoding.Chunk + for _, block := range blocks { + chunk.Blocks = append(chunk.Blocks, block) + } + + metrics, err := butils.CalculateChunkMetrics(&chunk, codec.Version()) + if err != nil { + return fmt.Errorf("failed to calculate chunk metrics: %w", err) + } + + err = f.db.Transaction(func(dbTX *gorm.DB) error { + dbChunk, err := f.chunkORM.InsertChunk(context.Background(), &chunk, codec.Version(), *metrics, dbTX) + if err != nil { + return fmt.Errorf("failed to insert chunk to DB: %w", err) + } + if err := f.blockORM.UpdateChunkHashInRange(context.Background(), dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, dbChunk.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update chunk_hash for l2_blocks (chunk hash: %s, start block: %d, end block: %d): %w", dbChunk.Hash, dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, err) + } + + if err = f.chunkORM.UpdateProvingStatus(context.Background(), dbChunk.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for chunk %s: %w", dbChunk.Hash, err) + } + + daChunks = append(daChunks, &chunk) + dbChunks = append(dbChunks, dbChunk) + + return nil + }) + if err != nil { + return fmt.Errorf("failed to insert chunk in DB transaction: %w", err) + } + } + + // 5.4 Reproduce batch. + dbParentBatch, err := f.batchORM.GetLatestBatch(context.Background()) + if err != nil { + return fmt.Errorf("failed to get latest batch from DB: %w", err) + } + + var batch encoding.Batch + batch.Index = dbParentBatch.Index + 1 + batch.ParentBatchHash = common.HexToHash(dbParentBatch.Hash) + batch.TotalL1MessagePoppedBefore = dbChunks[0].TotalL1MessagesPoppedBefore + + for _, chunk := range daChunks { + batch.Chunks = append(batch.Chunks, chunk) + } + + metrics, err := butils.CalculateBatchMetrics(&batch, codec.Version()) + if err != nil { + return fmt.Errorf("failed to calculate batch metrics: %w", err) + } + + err = f.db.Transaction(func(dbTX *gorm.DB) error { + dbBatch, err := f.batchORM.InsertBatch(context.Background(), &batch, codec.Version(), *metrics, dbTX) + if err != nil { + return fmt.Errorf("failed to insert batch to DB: %w", err) + } + if err = f.chunkORM.UpdateBatchHashInRange(context.Background(), dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, dbBatch.Hash, dbTX); err != nil { + return fmt.Errorf("failed to update batch_hash for chunks (batch hash: %s, start chunk: %d, end chunk: %d): %w", dbBatch.Hash, dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, err) + } + + if err = f.batchORM.UpdateProvingStatus(context.Background(), dbBatch.Hash, types.ProvingTaskVerified, dbTX); err != nil { + return fmt.Errorf("failed to update proving status for batch %s: %w", dbBatch.Hash, err) + } + if err = f.batchORM.UpdateRollupStatusCommitAndFinalizeTxHash(context.Background(), dbBatch.Hash, types.RollupFinalized, nextBatch.commit.TxHash().Hex(), nextBatch.finalize.TxHash().Hex(), dbTX); err != nil { + return fmt.Errorf("failed to update rollup status for batch %s: %w", dbBatch.Hash, err) + } + + return nil + }) + if err != nil { + return fmt.Errorf("failed to insert batch in DB transaction: %w", err) + } + + return nil +} + +type batchEvents struct { + commit *l1.CommitBatchEvent + finalize *l1.FinalizeBatchEvent +} + +func newBatchEvents(commit *l1.CommitBatchEvent, finalize *l1.FinalizeBatchEvent) *batchEvents { + if commit.BatchIndex().Uint64() > finalize.BatchIndex().Uint64() { + panic(fmt.Sprintf("commit and finalize batch index mismatch: %d != %d", commit.BatchIndex().Uint64(), finalize.BatchIndex().Uint64())) + } + + return &batchEvents{ + commit: commit, + finalize: finalize, + } +} + +func (e *batchEvents) CompareTo(other *batchEvents) int { + return e.commit.BatchIndex().Cmp(other.commit.BatchIndex()) +} From 012350241369d25a23d3b2653d2a25b65d4e98d3 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:15:09 +0800 Subject: [PATCH 18/25] clean up --- .../controller/relayer/full_recovery.go | 52 +++++++++---------- rollup/internal/orm/batch.go | 2 +- rollup/internal/orm/chunk.go | 1 - 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/rollup/internal/controller/relayer/full_recovery.go b/rollup/internal/controller/relayer/full_recovery.go index 3bde1b02fd..84c004ec33 100644 --- a/rollup/internal/controller/relayer/full_recovery.go +++ b/rollup/internal/controller/relayer/full_recovery.go @@ -64,15 +64,11 @@ func (f *FullRecovery) RestoreFullPreviousState() error { log.Info("Restoring full previous state with", "L1 block height", f.cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", f.cfg.RecoveryConfig.LatestFinalizedBatch) // 1. Get latest finalized batch stored in DB - latestDBBatch, err := f.batchORM.GetLatestBatch(context.Background()) + latestDBBatch, err := f.batchORM.GetLatestBatch(f.ctx) if err != nil { return fmt.Errorf("failed to get latest batch from DB: %w", err) } - // TODO: - // 1. what if it is a fresh start? -> latest batch is nil - //latestDBBatch.CommitTxHash - log.Info("Latest finalized batch in DB", "batch", latestDBBatch.Index, "hash", latestDBBatch.Hash) // 2. Get latest finalized L1 block @@ -84,23 +80,21 @@ func (f *FullRecovery) RestoreFullPreviousState() error { log.Info("Latest finalized L1 block number", "latest finalized L1 block", latestFinalizedL1Block) // 3. Get latest finalized batch from contract (at latest finalized L1 block) - latestFinalizedBatch, err := f.l1Reader.LatestFinalizedBatch(latestFinalizedL1Block) + latestFinalizedBatchContract, err := f.l1Reader.LatestFinalizedBatch(latestFinalizedL1Block) if err != nil { return fmt.Errorf("failed to get latest finalized batch: %w", err) } - // TODO: remove this, just for debugging - latestFinalizedBatch = 82310 - log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatch, "at latest finalized L1 block", latestFinalizedL1Block) + log.Info("Latest finalized batch from L1 contract", "latest finalized batch", latestFinalizedBatchContract, "at latest finalized L1 block", latestFinalizedL1Block) // 4. Get batches one by one from stored in DB to latest finalized batch. - receipt, err := f.l1Client.TransactionReceipt(context.Background(), common.HexToHash(latestDBBatch.CommitTxHash)) + receipt, err := f.l1Client.TransactionReceipt(f.ctx, common.HexToHash(latestDBBatch.CommitTxHash)) if err != nil { return fmt.Errorf("failed to get transaction receipt of latest DB batch finalization transaction: %w", err) } fromBlock := receipt.BlockNumber.Uint64() - log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatch) + log.Info("Fetching rollup events from L1", "from block", fromBlock, "to block", latestFinalizedL1Block, "from batch", latestDBBatch.Index, "to batch", latestFinalizedBatchContract) commitsHeapMap := common.NewHeapMap[uint64, *l1.CommitBatchEvent](func(event *l1.CommitBatchEvent) uint64 { return event.BatchIndex().Uint64() @@ -114,8 +108,6 @@ func (f *FullRecovery) RestoreFullPreviousState() error { return true } - fmt.Println("event", event.Type(), event.BatchIndex().Uint64()) - switch event.Type() { case l1.CommitEventType: commitEvent := event.(*l1.CommitBatchEvent) @@ -142,7 +134,7 @@ func (f *FullRecovery) RestoreFullPreviousState() error { bundles = append(bundles, bundle) // Stop fetching rollup events if we reached the latest finalized batch. - if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatch { + if finalizeEvent.BatchIndex().Uint64() >= latestFinalizedBatchContract { return false } @@ -173,7 +165,7 @@ func (f *FullRecovery) RestoreFullPreviousState() error { var lastBatchInBundle *orm.Batch for _, batch := range bundle { - dbBatch, err := f.batchORM.GetBatchByIndex(context.Background(), batch.commit.BatchIndex().Uint64()) + dbBatch, err := f.batchORM.GetBatchByIndex(f.ctx, batch.commit.BatchIndex().Uint64()) if err != nil { return fmt.Errorf("failed to get batch by index for bundle generation: %w", err) } @@ -191,19 +183,19 @@ func (f *FullRecovery) RestoreFullPreviousState() error { } err = f.db.Transaction(func(dbTX *gorm.DB) error { - newBundle, err := f.bundleORM.InsertBundle(context.Background(), dbBatches, encoding.CodecVersion(lastBatchInBundle.CodecVersion), dbTX) + newBundle, err := f.bundleORM.InsertBundle(f.ctx, dbBatches, encoding.CodecVersion(lastBatchInBundle.CodecVersion), dbTX) if err != nil { return fmt.Errorf("failed to insert bundle to DB: %w", err) } - if err = f.batchORM.UpdateBundleHashInRange(context.Background(), newBundle.StartBatchIndex, newBundle.EndBatchIndex, newBundle.Hash, dbTX); err != nil { + if err = f.batchORM.UpdateBundleHashInRange(f.ctx, newBundle.StartBatchIndex, newBundle.EndBatchIndex, newBundle.Hash, dbTX); err != nil { return fmt.Errorf("failed to update bundle_hash %s for batches (%d to %d): %w", newBundle.Hash, newBundle.StartBatchIndex, newBundle.EndBatchIndex, err) } - if err = f.bundleORM.UpdateFinalizeTxHashAndRollupStatus(context.Background(), newBundle.Hash, lastBatchInBundle.FinalizeTxHash, types.RollupFinalized, dbTX); err != nil { + if err = f.bundleORM.UpdateFinalizeTxHashAndRollupStatus(f.ctx, newBundle.Hash, lastBatchInBundle.FinalizeTxHash, types.RollupFinalized, dbTX); err != nil { return fmt.Errorf("failed to update finalize tx hash and rollup status for bundle %s: %w", newBundle.Hash, err) } - if err = f.bundleORM.UpdateProvingStatus(context.Background(), newBundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { + if err = f.bundleORM.UpdateProvingStatus(f.ctx, newBundle.Hash, types.ProvingTaskVerified, dbTX); err != nil { return fmt.Errorf("failed to update proving status for bundle %s: %w", newBundle.Hash, err) } @@ -254,7 +246,7 @@ func (f *FullRecovery) processFinalizedBatch(nextBatch *batchEvents) error { start := daChunkRawTxs.Blocks[0].Number() end := daChunkRawTxs.Blocks[len(daChunkRawTxs.Blocks)-1].Number() - blocks, err := f.blockORM.GetL2BlocksInRange(context.Background(), start, end) + blocks, err := f.blockORM.GetL2BlocksInRange(f.ctx, start, end) if err != nil { return fmt.Errorf("failed to get L2 blocks in range: %w", err) } @@ -272,21 +264,23 @@ func (f *FullRecovery) processFinalizedBatch(nextBatch *batchEvents) error { } err = f.db.Transaction(func(dbTX *gorm.DB) error { - dbChunk, err := f.chunkORM.InsertChunk(context.Background(), &chunk, codec.Version(), *metrics, dbTX) + dbChunk, err := f.chunkORM.InsertChunk(f.ctx, &chunk, codec.Version(), *metrics, dbTX) if err != nil { return fmt.Errorf("failed to insert chunk to DB: %w", err) } - if err := f.blockORM.UpdateChunkHashInRange(context.Background(), dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, dbChunk.Hash, dbTX); err != nil { + if err := f.blockORM.UpdateChunkHashInRange(f.ctx, dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, dbChunk.Hash, dbTX); err != nil { return fmt.Errorf("failed to update chunk_hash for l2_blocks (chunk hash: %s, start block: %d, end block: %d): %w", dbChunk.Hash, dbChunk.StartBlockNumber, dbChunk.EndBlockNumber, err) } - if err = f.chunkORM.UpdateProvingStatus(context.Background(), dbChunk.Hash, types.ProvingTaskVerified, dbTX); err != nil { + if err = f.chunkORM.UpdateProvingStatus(f.ctx, dbChunk.Hash, types.ProvingTaskVerified, dbTX); err != nil { return fmt.Errorf("failed to update proving status for chunk %s: %w", dbChunk.Hash, err) } daChunks = append(daChunks, &chunk) dbChunks = append(dbChunks, dbChunk) + log.Info("Inserted chunk", "index", dbChunk.Index, "hash", dbChunk.Hash, "start block", dbChunk.StartBlockNumber, "end block", dbChunk.EndBlockNumber) + return nil }) if err != nil { @@ -295,7 +289,7 @@ func (f *FullRecovery) processFinalizedBatch(nextBatch *batchEvents) error { } // 5.4 Reproduce batch. - dbParentBatch, err := f.batchORM.GetLatestBatch(context.Background()) + dbParentBatch, err := f.batchORM.GetLatestBatch(f.ctx) if err != nil { return fmt.Errorf("failed to get latest batch from DB: %w", err) } @@ -315,21 +309,23 @@ func (f *FullRecovery) processFinalizedBatch(nextBatch *batchEvents) error { } err = f.db.Transaction(func(dbTX *gorm.DB) error { - dbBatch, err := f.batchORM.InsertBatch(context.Background(), &batch, codec.Version(), *metrics, dbTX) + dbBatch, err := f.batchORM.InsertBatch(f.ctx, &batch, codec.Version(), *metrics, dbTX) if err != nil { return fmt.Errorf("failed to insert batch to DB: %w", err) } - if err = f.chunkORM.UpdateBatchHashInRange(context.Background(), dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, dbBatch.Hash, dbTX); err != nil { + if err = f.chunkORM.UpdateBatchHashInRange(f.ctx, dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, dbBatch.Hash, dbTX); err != nil { return fmt.Errorf("failed to update batch_hash for chunks (batch hash: %s, start chunk: %d, end chunk: %d): %w", dbBatch.Hash, dbBatch.StartChunkIndex, dbBatch.EndChunkIndex, err) } - if err = f.batchORM.UpdateProvingStatus(context.Background(), dbBatch.Hash, types.ProvingTaskVerified, dbTX); err != nil { + if err = f.batchORM.UpdateProvingStatus(f.ctx, dbBatch.Hash, types.ProvingTaskVerified, dbTX); err != nil { return fmt.Errorf("failed to update proving status for batch %s: %w", dbBatch.Hash, err) } - if err = f.batchORM.UpdateRollupStatusCommitAndFinalizeTxHash(context.Background(), dbBatch.Hash, types.RollupFinalized, nextBatch.commit.TxHash().Hex(), nextBatch.finalize.TxHash().Hex(), dbTX); err != nil { + if err = f.batchORM.UpdateRollupStatusCommitAndFinalizeTxHash(f.ctx, dbBatch.Hash, types.RollupFinalized, nextBatch.commit.TxHash().Hex(), nextBatch.finalize.TxHash().Hex(), dbTX); err != nil { return fmt.Errorf("failed to update rollup status for batch %s: %w", dbBatch.Hash, err) } + log.Info("Inserted batch", "index", dbBatch.Index, "hash", dbBatch.Hash, "start chunk", dbBatch.StartChunkIndex, "end chunk", dbBatch.EndChunkIndex) + return nil }) if err != nil { diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index f89fb9f0fc..81b594e4e1 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -422,7 +422,7 @@ func (o *Batch) UpdateRollupStatusCommitAndFinalizeTxHash(ctx context.Context, h updateFields["commit_tx_hash"] = commitTxHash updateFields["committed_at"] = utils.NowUTC() updateFields["finalize_tx_hash"] = finalizeTxHash - updateFields["finalized_at"] = time.Now() + updateFields["finalized_at"] = utils.NowUTC() updateFields["rollup_status"] = int(status) diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index b8eb4bab4f..020b269980 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -204,7 +204,6 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer parentChunkStateRoot = parentChunk.StateRoot } - fmt.Println("insertChunk", totalL1MessagePoppedBefore, chunkIndex, parentChunkHash) chunkHash, err := utils.GetChunkHash(chunk, totalL1MessagePoppedBefore, codecVersion) if err != nil { log.Error("failed to get chunk hash", "err", err) From 596d9fe355c5796265d7f3c43d4121594cb5cda9 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:54:13 +0800 Subject: [PATCH 19/25] introduce profiles to docker-compose.yml --- permissionless-batches/docker-compose.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/permissionless-batches/docker-compose.yml b/permissionless-batches/docker-compose.yml index f3f3d7dcff..f38bd30292 100644 --- a/permissionless-batches/docker-compose.yml +++ b/permissionless-batches/docker-compose.yml @@ -1,7 +1,7 @@ name: permissionless-batches services: - relayer: + relayer-batch-production: build: context: ../ dockerfile: build/dockerfiles/recovery_permissionless_batches.Dockerfile @@ -9,6 +9,8 @@ services: volumes: - ./conf/relayer:/app/conf command: "--config /app/conf/config.json" + profiles: + - batch-production-submission depends_on: db: condition: service_healthy @@ -36,6 +38,8 @@ services: volumes: - ./conf/coordinator/:/app/conf command: "--config /app/conf/config.json --http.port 8390 --verbosity 5" + profiles: + - proving depends_on: db: condition: service_healthy @@ -53,6 +57,8 @@ services: volumes: - ./conf/coordinator/:/app/conf command: "--config /app/conf/config.json --verbosity 3" + profiles: + - proving depends_on: db: condition: service_healthy @@ -62,6 +68,8 @@ services: image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 platform: linux/amd64 command: "--config /app/config.json" + profiles: + - proving environment: PROVER_NAME_PREFIX: "sindri_chunk" CIRCUIT_TYPE: 1 # 1 for chunk proving @@ -77,6 +85,8 @@ services: image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 platform: linux/amd64 command: "--config /app/config.json" + profiles: + - proving environment: PROVER_NAME_PREFIX: "sindri_batch" CIRCUIT_TYPE: 2 # 2 for batch proving @@ -92,6 +102,8 @@ services: image: scrolltech/sdk-cloud-prover:sindri-v0.0.5 platform: linux/amd64 command: "--config /app/config.json" + profiles: + - proving environment: PROVER_NAME_PREFIX: "sindri_bundle" CIRCUIT_TYPE: 3 # 3 for bundle proving From d85bdf5cf3c15cb37cb2c5e84e99635288622215 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:54:32 +0800 Subject: [PATCH 20/25] initial instructions in README.md --- permissionless-batches/README.md | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 permissionless-batches/README.md diff --git a/permissionless-batches/README.md b/permissionless-batches/README.md new file mode 100644 index 0000000000..154377c45c --- /dev/null +++ b/permissionless-batches/README.md @@ -0,0 +1,36 @@ +# Permissionless Batches +Permissionless batches aka enforced batches is a feature that provides guarantee to users that they can exit Scroll even if the operator is down or censoring. +It allows anyone to take over and submit a batch (permissionless batch submission) together with a proof after a certain time period has passed without a batch being finalized on L1. + +Once permissionless batch mode is activated, the operator can no longer submit batches in a permissioned way. Only the security council can deactivate permissionless batch mode and reinstate the operator as the only batch submitter. +There are two types of situations to consider: +- `Permissionless batch mode is activated:` This means that finalization halted for some time. Now anyone can submit batches utilizing the [batch production toolkit](#batch-production-toolkit). +- `Permissionless batch mode is deactivated:` This means that the security council has decided to reinstate the operator as the only batch submitter. The operator needs to [recover](#operator-recovery) the sequencer and relayer to resume batch submission and the valid L2 chain. + + +## Pre-requisites +- install instructions +- download stuff for coordinator + + +## Batch production toolkit +1. l2geth recovery +2. l2geth block production +3. relayer in permissionless mode with proving etc + +### Proving service +``` +"l2geth": { + "endpoint": "" + } +``` + + +## Operator recovery +- l2geth recovery and relayer recovery + +### Relayer +``` +l2_config.endpoint +``` + From a9eac08aeeb7c689e62a059eba166892c0c67d2e Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:34:56 +0800 Subject: [PATCH 21/25] address review comments --- .../permissionless_batches/minimal_recovery.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rollup/internal/controller/permissionless_batches/minimal_recovery.go b/rollup/internal/controller/permissionless_batches/minimal_recovery.go index 1f1437734c..5509278138 100644 --- a/rollup/internal/controller/permissionless_batches/minimal_recovery.go +++ b/rollup/internal/controller/permissionless_batches/minimal_recovery.go @@ -19,7 +19,9 @@ import ( ) const ( - defaultRestoredChunkIndex uint64 = 1337 + // defaultRestoredChunkIndex is the default index of the last restored fake chunk. It is used to be able to generate new chunks pretending that we have already processed some chunks. + defaultRestoredChunkIndex uint64 = 1337 + // defaultRestoredBundleIndex is the default index of the last restored fake bundle. It is used to be able to generate new bundles pretending that we have already processed some bundles. defaultRestoredBundleIndex uint64 = 1 ) @@ -219,17 +221,20 @@ func (r *MinimalRecovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, } } + // Find the commit event for the latest finalized batch. var batchCommitEvent *l1.CommitBatchEvent err = reader.FetchRollupEventsInRangeWithCallback(r.cfg.RecoveryConfig.L1BlockHeight, latestFinalizedL1Block, func(event l1.RollupEvent) bool { - if event.Type() == l1.CommitEventType && event.BatchIndex().Uint64() == r.cfg.RecoveryConfig.LatestFinalizedBatch { + if event.Type() == l1.CommitEventType && event.BatchIndex().Uint64() == latestFinalizedBatch { batchCommitEvent = event.(*l1.CommitBatchEvent) + // We found the commit event for the batch, stop searching. return false } + // Continue until we find the commit event for the batch. return true }) if batchCommitEvent == nil { - return nil, nil, nil, fmt.Errorf("commit event not found for batch %d", r.cfg.RecoveryConfig.LatestFinalizedBatch) + return nil, nil, nil, fmt.Errorf("commit event not found for batch %d", latestFinalizedBatch) } log.Info("Found commit event for batch", "batch", batchCommitEvent.BatchIndex(), "hash", batchCommitEvent.BatchHash(), "L1 block height", batchCommitEvent.BlockNumber(), "L1 tx hash", batchCommitEvent.TxHash()) From 606162ee48b2c8f3330d33fcb5247748bfd088a0 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:20:42 +0800 Subject: [PATCH 22/25] add dummy configuration and documentation for permissionless batch production toolkit --- permissionless-batches/README.md | 111 ++++++++++++++++-- .../conf/coordinator/assets/.gitkeep | 0 .../conf/coordinator/config.json | 38 ++++++ .../conf/coordinator/params/.gitkeep | 0 permissionless-batches/conf/genesis.json | 1 + .../conf/proving-service/batch/.gitkeep | 0 .../conf/proving-service/bundle/.gitkeep | 0 .../conf/proving-service/chunk/.gitkeep | 0 .../conf/proving-service/config.json | 26 ++++ .../conf/relayer/config.json | 55 +++++++++ permissionless-batches/docker-compose.yml | 6 +- 11 files changed, 222 insertions(+), 15 deletions(-) create mode 100644 permissionless-batches/conf/coordinator/assets/.gitkeep create mode 100644 permissionless-batches/conf/coordinator/config.json create mode 100644 permissionless-batches/conf/coordinator/params/.gitkeep create mode 100644 permissionless-batches/conf/genesis.json create mode 100644 permissionless-batches/conf/proving-service/batch/.gitkeep create mode 100644 permissionless-batches/conf/proving-service/bundle/.gitkeep create mode 100644 permissionless-batches/conf/proving-service/chunk/.gitkeep create mode 100644 permissionless-batches/conf/proving-service/config.json create mode 100644 permissionless-batches/conf/relayer/config.json diff --git a/permissionless-batches/README.md b/permissionless-batches/README.md index 154377c45c..2a27f5382d 100644 --- a/permissionless-batches/README.md +++ b/permissionless-batches/README.md @@ -8,29 +8,114 @@ There are two types of situations to consider: - `Permissionless batch mode is deactivated:` This means that the security council has decided to reinstate the operator as the only batch submitter. The operator needs to [recover](#operator-recovery) the sequencer and relayer to resume batch submission and the valid L2 chain. -## Pre-requisites -- install instructions -- download stuff for coordinator +## Batch production toolkit +The batch production toolkit is a set of tools that allow anyone to submit a batch in permissionless mode. It consists of three main components: +1. l2geth state recovery from L1 +2. l2geth block production +3. production, proving and submission of batch with `docker-compose.yml` +### Pre-requisites +- Unix-like OS, 32GB RAM +- Docker +- [l2geth](https://github.com/scroll-tech/go-ethereum/) or [Docker image](https://hub.docker.com/r/scrolltech/l2geth) of corresponding version [TODO link list with versions](#batch-production-toolkit). +- access to an Ethereum L1 RPC node (beacon node and execution client) +- ability to run a prover or access to a proving service (e.g. Sindri) +- L1 account with funds to pay for the batch submission -## Batch production toolkit -1. l2geth recovery -2. l2geth block production -3. relayer in permissionless mode with proving etc +### 1. l2geth state recovery from L1 +Once permissionless mode is activated there's no blocks being produced and propagated on L2. The first step is to recover the latest state of the L2 chain from L1. This is done by running l2geth in recovery mode. +More information about l2geth recovery (aka L1 follower mode) can be found [here TODO: put correct link once released](https://github.com/scroll-tech/scroll-documentation/pull/374). + +Running l2geth in recovery mode requires following configuration: +- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode +- `--da.blob.beaconnode` - L1 RPC beacon node +- `--l1.endpoint` - L1 RPC execution client +- `--da.sync=true` - enables syncing with L1 +- `--da.recovery` - enables recovery mode +- `--da.recovery.initiall1block` - initial L1 block (commit tx of initial batch) +- `--da.recovery.initialbatch` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https://scrollscan.com/batches). +- `--da.recovery.l2endblock` - until which L2 block recovery should run (optional) -### Proving service +```bash +./build/bin/geth --scroll<-sepolia> \ +--datadir "tmp/datadir" \ +--gcmode archive \ +--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \ +--da.blob.beaconnode "" \ +--l1.endpoint "" \ +--da.sync=true --da.recovery --da.recovery.initiall1block "" --da.recovery.initialbatch "" --da.recovery.l2endblock "" \ +--verbosity 3 ``` -"l2geth": { - "endpoint": "" - } + +### 2. l2geth block production +After the state is recovered, the next step is to produce blocks on L2. This is done by running l2geth in block production mode. +As a pre-requisite, the state recovery must be completed and the latest state of the L2 chain must be available. + +You also need to generate a keystore e.g. with [Clef](https://geth.ethereum.org/docs/fundamentals/account-management) to be able to sign blocks. +This key is not used for any funds, but required for block production to work. Once you generated blocks you can safely discard it. + +Running l2geth in block production mode requires following configuration: +- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode +- `--da.blob.beaconnode` - L1 RPC beacon node +- `--l1.endpoint` - L1 RPC execution client +- `--da.sync=true` - enables syncing with L1 +- `--da.recovery` - enables recovery mode +- `--da.recovery.produceblocks` - enables block production +- `--miner.etherbase '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' --mine` - enables mining. the address is not used, but required for mining to work +- `---miner.gaslimit 1 --miner.gasprice 1 --miner.maxaccountsnum 100 --rpc.gascap 0 --gpo.ignoreprice 1` - gas limits for block production + +```bash +./build/bin/geth --scroll<-sepolia> \ +--datadir "tmp/datadir" \ +--gcmode archive \ +--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \ +--da.blob.beaconnode "" \ +--l1.endpoint "" \ +--da.sync=true --da.recovery --da.recovery.produceblocks \ +--miner.gaslimit 1 --miner.gasprice 1 --miner.maxaccountsnum 100 --rpc.gascap 0 --gpo.ignoreprice 1 \ +--miner.etherbase '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' --mine \ +--ccc \ +--verbosity 3 ``` +### 3. production, proving and submission of batch with `docker-compose.yml` +After the blocks are produced, the next step is to produce a batch, prove it and submit it to L1. This is done by running the `docker-compose.yml` in the `permissionless-batches` folder. + + +#### Producing a batch +To produce a batch you need to run the `batch-production-submission` profile in `docker-compose.yml`. + +1. Fill `conf/genesis.json` with the latest genesis state from the L2 chain. The genesis for the current fork can be found here: [TODO link list with versions](#batch-production-toolkit) +2. Make sure that `l2geth` with your locally produced blocks is running and reachable from the Docker network (e.g. `http://host.docker.internal:8545`) +3. Fill in required fields in `conf/relayer/config.json` + + +Run with `docker compose --profile batch-production-submission up`. + +#### Proving a batch +To prove a batch you need to run the `proving` profile in `docker-compose.yml`. + +1. Make sure `verifier` `low_version_circuit` and `high_version_circuit` in `conf/coordinator/config.json` are correct for the latest fork: [TODO link list with versions](#batch-production-toolkit) +2. Download the latest `assets` and `params` for the circuit from [TODO link list with versions](#batch-production-toolkit) into `conf/coordinator/assets` and `conf/coordinator/params` respectively. +3. Fill in the required fields in `conf/proving-service/config.json`. It is recommended to use Sindri. You'll need to obtain credits and an API key from their [website](https://sindri.app/). +4. Alternatively, you can run your own prover: https://github.com/scroll-tech/scroll-prover. However, this requires more configuration. + +Run with `docker compose --profile proving up`. + + +#### Batch submission +TODO + ## Operator recovery -- l2geth recovery and relayer recovery +- l2geth recovery with sign blocks and relayer recovery + +### Pre-requisites + +### l2geth recovery ### Relayer + ``` l2_config.endpoint ``` - diff --git a/permissionless-batches/conf/coordinator/assets/.gitkeep b/permissionless-batches/conf/coordinator/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/permissionless-batches/conf/coordinator/config.json b/permissionless-batches/conf/coordinator/config.json new file mode 100644 index 0000000000..fd38cc25f4 --- /dev/null +++ b/permissionless-batches/conf/coordinator/config.json @@ -0,0 +1,38 @@ +{ + "prover_manager": { + "provers_per_session": 1, + "session_attempts": 5, + "bundle_collection_time_sec": 3600, + "batch_collection_time_sec": 3600, + "chunk_collection_time_sec": 3600, + "verifier": { + "mock_mode": false, + "low_version_circuit": { + "params_path": "./conf/params", + "assets_path": "./conf/assets", + "fork_name": "darwinV2", + "min_prover_version": "v4.4.55" + }, + "high_version_circuit": { + "params_path": "./conf/params", + "assets_path": "./conf/assets", + "fork_name": "darwinV2", + "min_prover_version": "v4.4.56" + } + } + }, + "db": { + "driver_name": "postgres", + "dsn": "postgres://db/scroll?sslmode=disable&user=postgres", + "maxOpenNum": 200, + "maxIdleNum": 20 + }, + "l2": { + "chain_id": 111 + }, + "auth": { + "secret": "prover secret key", + "challenge_expire_duration_sec": 3600, + "login_expire_duration_sec": 3600 + } +} diff --git a/permissionless-batches/conf/coordinator/params/.gitkeep b/permissionless-batches/conf/coordinator/params/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/permissionless-batches/conf/genesis.json b/permissionless-batches/conf/genesis.json new file mode 100644 index 0000000000..bebd2dde38 --- /dev/null +++ b/permissionless-batches/conf/genesis.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/permissionless-batches/conf/proving-service/batch/.gitkeep b/permissionless-batches/conf/proving-service/batch/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/permissionless-batches/conf/proving-service/bundle/.gitkeep b/permissionless-batches/conf/proving-service/bundle/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/permissionless-batches/conf/proving-service/chunk/.gitkeep b/permissionless-batches/conf/proving-service/chunk/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/permissionless-batches/conf/proving-service/config.json b/permissionless-batches/conf/proving-service/config.json new file mode 100644 index 0000000000..de7fc9334c --- /dev/null +++ b/permissionless-batches/conf/proving-service/config.json @@ -0,0 +1,26 @@ +{ + "prover_name_prefix": "prover_", + "keys_dir": "/app/", + "db_path": "/app/", + "coordinator": { + "base_url": "http://coordinator:8390", + "retry_count": 3, + "retry_wait_time_sec": 5, + "connection_timeout_sec": 60 + }, + "l2geth": { + "endpoint": "" + }, + "prover": { + "circuit_type": 2, + "circuit_version": "v0.13.1", + "n_workers": 1, + "cloud": { + "base_url": "https://sindri.app/api/v1/", + "api_key": "", + "retry_count": 3, + "retry_wait_time_sec": 5, + "connection_timeout_sec": 60 + } + } +} \ No newline at end of file diff --git a/permissionless-batches/conf/relayer/config.json b/permissionless-batches/conf/relayer/config.json new file mode 100644 index 0000000000..3b06b6dcc3 --- /dev/null +++ b/permissionless-batches/conf/relayer/config.json @@ -0,0 +1,55 @@ +{ + "l1_config": { + "endpoint": "" + }, + "l2_config": { + "confirmations": "0x0", + "endpoint": "", + "relayer_config": { + "commit_sender_signer_config": { + "signer_type": "PrivateKey", + "private_key_signer_config": { + "private_key": "1414141414141414141414141414141414141414141414141414141414141414" + } + }, + "l1_commit_gas_limit_multiplier": 1.2 + }, + "chunk_proposer_config": { + "propose_interval_milliseconds": 100, + "max_block_num_per_chunk": 100, + "max_tx_num_per_chunk": 100, + "max_l1_commit_gas_per_chunk": 11234567, + "max_l1_commit_calldata_size_per_chunk": 112345, + "chunk_timeout_sec": 300, + "max_row_consumption_per_chunk": 1048319, + "gas_cost_increase_multiplier": 1.2, + "max_uncompressed_batch_bytes_size": 634880 + }, + "batch_proposer_config": { + "propose_interval_milliseconds": 1000, + "max_l1_commit_gas_per_batch": 11234567, + "max_l1_commit_calldata_size_per_batch": 112345, + "batch_timeout_sec": 300, + "gas_cost_increase_multiplier": 1.2, + "max_uncompressed_batch_bytes_size": 634880 + }, + "bundle_proposer_config": { + "max_batch_num_per_bundle": 20, + "bundle_timeout_sec": 36000 + } + }, + "db_config": { + "driver_name": "postgres", + "dsn": "postgres://db/scroll?sslmode=disable&user=postgres", + "maxOpenNum": 200, + "maxIdleNum": 20 + }, + "recovery_config": { + "enable": true, + "l1_block_height": , + "latest_finalized_batch": , + "l2_block_height_limit": , + "force_latest_finalized_batch": false, + "force_l1_message_count": 0 + } +} diff --git a/permissionless-batches/docker-compose.yml b/permissionless-batches/docker-compose.yml index f38bd30292..dca785c1fd 100644 --- a/permissionless-batches/docker-compose.yml +++ b/permissionless-batches/docker-compose.yml @@ -7,7 +7,8 @@ services: dockerfile: build/dockerfiles/recovery_permissionless_batches.Dockerfile container_name: permissionless-batches-relayer volumes: - - ./conf/relayer:/app/conf + - ./conf/relayer/config.json:/app/conf/config.json + - ./conf/genesis.json:/app/conf/genesis.json command: "--config /app/conf/config.json" profiles: - batch-production-submission @@ -36,7 +37,8 @@ services: context: ../ dockerfile: build/dockerfiles/coordinator-api.Dockerfile volumes: - - ./conf/coordinator/:/app/conf + - ./conf/coordinator/config.json:/app/conf/config.json + - ./conf/genesis.json:/app/conf/genesis.json command: "--config /app/conf/config.json --http.port 8390 --verbosity 5" profiles: - proving From 30c0201d408156f4d3d7c140b43d891b32151489 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:22:40 +0800 Subject: [PATCH 23/25] ignore /conf folder from git --- permissionless-batches/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 permissionless-batches/.gitignore diff --git a/permissionless-batches/.gitignore b/permissionless-batches/.gitignore new file mode 100644 index 0000000000..ac3d45c877 --- /dev/null +++ b/permissionless-batches/.gitignore @@ -0,0 +1 @@ +conf/ \ No newline at end of file From ec9d862ea3ea85786e6eb5cc4639e9f80e868260 Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:53:21 +0800 Subject: [PATCH 24/25] add documentation for operator recovery --- permissionless-batches/README.md | 52 ++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/permissionless-batches/README.md b/permissionless-batches/README.md index 2a27f5382d..252c31d458 100644 --- a/permissionless-batches/README.md +++ b/permissionless-batches/README.md @@ -14,7 +14,7 @@ The batch production toolkit is a set of tools that allow anyone to submit a bat 2. l2geth block production 3. production, proving and submission of batch with `docker-compose.yml` -### Pre-requisites +### Prerequisites - Unix-like OS, 32GB RAM - Docker - [l2geth](https://github.com/scroll-tech/go-ethereum/) or [Docker image](https://hub.docker.com/r/scrolltech/l2geth) of corresponding version [TODO link list with versions](#batch-production-toolkit). @@ -49,7 +49,7 @@ Running l2geth in recovery mode requires following configuration: ### 2. l2geth block production After the state is recovered, the next step is to produce blocks on L2. This is done by running l2geth in block production mode. -As a pre-requisite, the state recovery must be completed and the latest state of the L2 chain must be available. +As a prerequisite, the state recovery must be completed and the latest state of the L2 chain must be available. You also need to generate a keystore e.g. with [Clef](https://geth.ethereum.org/docs/fundamentals/account-management) to be able to sign blocks. This key is not used for any funds, but required for block production to work. Once you generated blocks you can safely discard it. @@ -108,14 +108,54 @@ TODO ## Operator recovery -- l2geth recovery with sign blocks and relayer recovery +Operator recovery needs to be run by the rollup operator to resume normal rollup operation after permissionless batch mode is deactivated. It consists of two main components: +1. l2geth recovery +2. Relayer recovery -### Pre-requisites +These steps are required to resume permissioned batch submission and the valid L2 chain. They will restore the entire history of the batches submitted during permissionless mode. + +### Prerequisites +- l2geth with the latest state of the L2 chain (before permissionless mode was activated) +- signer key for the sequencer according to Clique consensus +- relayer and coordinator are set up, running and up-to-date with the latest state of the L2 chain (before permissionless mode was activated) ### l2geth recovery +Running l2geth in recovery mode requires following configuration: +- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode +- `--da.blob.beaconnode` - L1 RPC beacon node +- `--l1.endpoint` - L1 RPC execution client +- `--da.sync=true` - enables syncing with L1 +- `--da.recovery` - enables recovery mode +- `--da.recovery.signblocks` - enables signing blocks with the sequencer and configured key +- `--da.recovery.initiall1block` - initial L1 block (commit tx of initial batch) +- `--da.recovery.initialbatch` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https://scrollscan.com/batches). +- `--da.recovery.l2endblock` - until which L2 block recovery should run (optional) + +```bash +./build/bin/geth --scroll<-sepolia> \ +--datadir "tmp/datadir" \ +--gcmode archive \ +--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \ +--da.blob.beaconnode "" \ +--l1.endpoint "" \ +--da.sync=true --da.recovery --da.recovery.signblocks --da.recovery.initiall1block "" --da.recovery.initialbatch "" --da.recovery.l2endblock "" \ +--verbosity 3 +``` -### Relayer +After the recovery is finished, start the sequencer in normal operation and continue issuing L2 blocks as normal. This will resume the L2 chain, allow the relayer (after running recovery) to create new batches and allow other L2 follower nodes to sync up the valid and signed L2 chain. +### Relayer recovery +Start the relayer with the following additional top-level configuration: ``` -l2_config.endpoint + "recovery_config": { + "enable": true + } +``` + +This will make the relayer recover all the chunks, batches and bundles that were submitted during permissionless mode. These batches are marked automatically as proven and finalized. +Once this process is finished, start the relayer normally without the recovery config to resume normal operation. ``` + "recovery_config": { + "enable": false + } +``` \ No newline at end of file From 6ef477578a69c107d611a686eea7d7f486582e6e Mon Sep 17 00:00:00 2001 From: jonastheis <4181434+jonastheis@users.noreply.github.com> Date: Tue, 26 Nov 2024 09:47:49 +0800 Subject: [PATCH 25/25] address review comments --- .../minimal_recovery.go | 16 +++--- .../controller/relayer/full_recovery.go | 4 +- rollup/internal/orm/batch.go | 49 ++++++------------- rollup/internal/orm/chunk.go | 39 ++++++--------- 4 files changed, 40 insertions(+), 68 deletions(-) diff --git a/rollup/internal/controller/permissionless_batches/minimal_recovery.go b/rollup/internal/controller/permissionless_batches/minimal_recovery.go index 5509278138..71f33b681f 100644 --- a/rollup/internal/controller/permissionless_batches/minimal_recovery.go +++ b/rollup/internal/controller/permissionless_batches/minimal_recovery.go @@ -19,10 +19,10 @@ import ( ) const ( - // defaultRestoredChunkIndex is the default index of the last restored fake chunk. It is used to be able to generate new chunks pretending that we have already processed some chunks. - defaultRestoredChunkIndex uint64 = 1337 - // defaultRestoredBundleIndex is the default index of the last restored fake bundle. It is used to be able to generate new bundles pretending that we have already processed some bundles. - defaultRestoredBundleIndex uint64 = 1 + // defaultFakeRestoredChunkIndex is the default index of the last restored fake chunk. It is used to be able to generate new chunks pretending that we have already processed some chunks. + defaultFakeRestoredChunkIndex uint64 = 1337 + // defaultFakeRestoredBundleIndex is the default index of the last restored fake bundle. It is used to be able to generate new bundles pretending that we have already processed some bundles. + defaultFakeRestoredBundleIndex uint64 = 1 ) type MinimalRecovery struct { @@ -61,7 +61,7 @@ func (r *MinimalRecovery) RecoveryNeeded() bool { if err != nil { return true } - if chunk.Index <= defaultRestoredChunkIndex { + if chunk.Index <= defaultFakeRestoredChunkIndex { return true } @@ -77,7 +77,7 @@ func (r *MinimalRecovery) RecoveryNeeded() bool { if err != nil { return true } - if bundle.Index <= defaultRestoredBundleIndex { + if bundle.Index <= defaultFakeRestoredBundleIndex { return true } @@ -273,14 +273,14 @@ func (r *MinimalRecovery) restoreMinimalPreviousState() (*orm.Chunk, *orm.Batch, log.Info("L1 messages count after latest finalized batch", "batch", batchCommitEvent.BatchIndex(), "count", l1MessagesCount) // 5. Insert minimal state to DB. - chunk, err := r.chunkORM.InsertChunkRaw(r.ctx, defaultRestoredChunkIndex, codec.Version(), lastChunk, l1MessagesCount) + chunk, err := r.chunkORM.InsertPermissionlessChunk(r.ctx, defaultFakeRestoredChunkIndex, codec.Version(), lastChunk, l1MessagesCount) if err != nil { return nil, nil, nil, fmt.Errorf("failed to insert chunk raw: %w", err) } log.Info("Inserted last finalized chunk to DB", "chunk", chunk.Index, "hash", chunk.Hash, "StartBlockNumber", chunk.StartBlockNumber, "EndBlockNumber", chunk.EndBlockNumber, "TotalL1MessagesPoppedBefore", chunk.TotalL1MessagesPoppedBefore) - batch, err := r.batchORM.InsertBatchRaw(r.ctx, batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) + batch, err := r.batchORM.InsertPermissionlessBatch(r.ctx, batchCommitEvent.BatchIndex(), batchCommitEvent.BatchHash(), codec.Version(), chunk) if err != nil { return nil, nil, nil, fmt.Errorf("failed to insert batch raw: %w", err) } diff --git a/rollup/internal/controller/relayer/full_recovery.go b/rollup/internal/controller/relayer/full_recovery.go index 84c004ec33..c74c65be32 100644 --- a/rollup/internal/controller/relayer/full_recovery.go +++ b/rollup/internal/controller/relayer/full_recovery.go @@ -61,7 +61,7 @@ func NewFullRecovery(ctx context.Context, cfg *config.Config, genesis *core.Gene // The DB state should be clean: the latest batch in the DB should be finalized on L1. This function will // restore all batches between the latest finalized batch in the DB and the latest finalized batch on L1. func (f *FullRecovery) RestoreFullPreviousState() error { - log.Info("Restoring full previous state with", "L1 block height", f.cfg.RecoveryConfig.L1BlockHeight, "latest finalized batch", f.cfg.RecoveryConfig.LatestFinalizedBatch) + log.Info("Restoring full previous state") // 1. Get latest finalized batch stored in DB latestDBBatch, err := f.batchORM.GetLatestBatch(f.ctx) @@ -204,8 +204,6 @@ func (f *FullRecovery) RestoreFullPreviousState() error { if err != nil { return fmt.Errorf("failed to insert bundle in DB transaction: %w", err) } - - fmt.Println("bundle", len(bundle), bundle[0].commit.BatchIndex()) } return nil diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index 81b594e4e1..0bfc22b2c5 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -326,48 +326,29 @@ func (o *Batch) InsertBatch(ctx context.Context, batch *encoding.Batch, codecVer return &newBatch, nil } -func (o *Batch) InsertBatchRaw(ctx context.Context, batchIndex *big.Int, batchHash common.Hash, codecVersion encoding.CodecVersion, chunk *Chunk) (*Batch, error) { +func (o *Batch) InsertPermissionlessBatch(ctx context.Context, batchIndex *big.Int, batchHash common.Hash, codecVersion encoding.CodecVersion, chunk *Chunk) (*Batch, error) { now := time.Now() newBatch := &Batch{ - Index: batchIndex.Uint64(), - Hash: batchHash.Hex(), - DataHash: "", - StartChunkIndex: chunk.Index, - StartChunkHash: chunk.Hash, - EndChunkIndex: chunk.Index, - EndChunkHash: chunk.Hash, - StateRoot: "", - WithdrawRoot: "", - ParentBatchHash: "", - BatchHeader: []byte{1, 2, 3}, - CodecVersion: int16(codecVersion), - EnableCompress: false, - BlobBytes: nil, - ChunkProofsStatus: 0, - ProvingStatus: int16(types.ProvingTaskVerified), - Proof: nil, - ProverAssignedAt: nil, - ProvedAt: &now, - ProofTimeSec: 0, - RollupStatus: int16(types.RollupFinalized), - CommitTxHash: "", - CommittedAt: nil, - FinalizeTxHash: "", - FinalizedAt: &now, - OracleStatus: 0, - OracleTxHash: "", - BlobDataProof: nil, - BlobSize: 0, - BundleHash: "", - TotalL1CommitGas: 0, - TotalL1CommitCalldataSize: 0, + Index: batchIndex.Uint64(), + Hash: batchHash.Hex(), + StartChunkIndex: chunk.Index, + StartChunkHash: chunk.Hash, + EndChunkIndex: chunk.Index, + EndChunkHash: chunk.Hash, + BatchHeader: []byte{1, 2, 3}, + CodecVersion: int16(codecVersion), + EnableCompress: false, + ProvingStatus: int16(types.ProvingTaskVerified), + ProvedAt: &now, + RollupStatus: int16(types.RollupFinalized), + FinalizedAt: &now, } db := o.db.WithContext(ctx) db = db.Model(&Batch{}) if err := db.Create(newBatch).Error; err != nil { - return nil, fmt.Errorf("Batch.InsertBatchRaw error: %w", err) + return nil, fmt.Errorf("Batch.InsertPermissionlessBatch error: %w", err) } return newBatch, nil diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index 020b269980..32f549b118 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -256,7 +256,7 @@ func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVer return &newChunk, nil } -func (o *Chunk) InsertChunkRaw(ctx context.Context, index uint64, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) (*Chunk, error) { +func (o *Chunk) InsertPermissionlessChunk(ctx context.Context, index uint64, codecVersion encoding.CodecVersion, chunk *encoding.DAChunkRawTx, totalL1MessagePoppedBefore uint64) (*Chunk, error) { // Create some unique identifier. It is not really used for anything except in DB. var chunkBytes []byte for _, block := range chunk.Blocks { @@ -268,28 +268,21 @@ func (o *Chunk) InsertChunkRaw(ctx context.Context, index uint64, codecVersion e numBlocks := len(chunk.Blocks) emptyHash := common.Hash{}.Hex() newChunk := &Chunk{ - Index: index, - Hash: hash.Hex(), - StartBlockNumber: chunk.Blocks[0].Number(), - StartBlockHash: emptyHash, - EndBlockNumber: chunk.Blocks[numBlocks-1].Number(), - EndBlockHash: emptyHash, - TotalL2TxGas: 0, - TotalL2TxNum: 0, - TotalL1CommitCalldataSize: 0, - TotalL1CommitGas: 0, - StartBlockTime: chunk.Blocks[0].Timestamp(), - TotalL1MessagesPoppedBefore: totalL1MessagePoppedBefore, - TotalL1MessagesPoppedInChunk: 0, - ParentChunkHash: emptyHash, - StateRoot: emptyHash, - ParentChunkStateRoot: emptyHash, - WithdrawRoot: emptyHash, - CodecVersion: int16(codecVersion), - EnableCompress: false, - ProvingStatus: int16(types.ProvingTaskVerified), - CrcMax: 0, - BlobSize: 0, + Index: index, + Hash: hash.Hex(), + StartBlockNumber: chunk.Blocks[0].Number(), + StartBlockHash: emptyHash, + EndBlockNumber: chunk.Blocks[numBlocks-1].Number(), + EndBlockHash: emptyHash, + StartBlockTime: chunk.Blocks[0].Timestamp(), + TotalL1MessagesPoppedBefore: totalL1MessagePoppedBefore, + ParentChunkHash: emptyHash, + StateRoot: emptyHash, + ParentChunkStateRoot: emptyHash, + WithdrawRoot: emptyHash, + CodecVersion: int16(codecVersion), + EnableCompress: false, + ProvingStatus: int16(types.ProvingTaskVerified), } db := o.db.WithContext(ctx)