-
Notifications
You must be signed in to change notification settings - Fork 9
Block data migration #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Block data migration #147
Changes from all commits
6e41571
2677854
cbbc17f
da81742
e88665a
f3feeeb
d3aff38
c1b2e7a
c1cca6e
8787ce8
3ac4661
f004979
349aaf1
9f841a4
4ae2e22
2df677a
f158be8
84d516a
a48f897
0fecde3
f1d88a2
5c4a1e5
393e96e
c6f68f6
62b47f3
3601fe6
44f15c1
c861c70
eb4188f
caec5c9
f72af10
7d222f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,92 +1,50 @@ | ||
| name: Docker Build Scan | ||
| on: | ||
| pull_request: | ||
| branches: | ||
| - "master" | ||
| - "celo*" | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| Build-Scan-Container-op-ufm: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-ufm/Dockerfile | ||
|
|
||
| Build-Scan-Container-ops-bedrock-l1: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: ops-bedrock/Dockerfile.l1 | ||
| context: ops-bedrock | ||
|
|
||
| Build-Scan-Container-ops-bedrock-l2: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: ops-bedrock/Dockerfile.l2 | ||
| context: ops-bedrock | ||
|
|
||
| Build-Scan-Container-indexer: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: indexer/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-heartbeat: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-heartbeat/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-exporter: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-exporter/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-program: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-program/Dockerfile | ||
|
|
||
| Build-Scan-Container-ops-bedrock: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: ops-bedrock/Dockerfile.stateviz | ||
|
|
||
| Build-Scan-Container-ci-builder: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: ops/docker/ci-builder/Dockerfile | ||
|
|
||
| Build-Scan-Container-proxyd: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: proxyd/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-node: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-node/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-batcher: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-batcher/Dockerfile | ||
|
|
||
| Build-Scan-Container-indexer-ui: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: indexer/ui/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-proposer: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-proposer/Dockerfile | ||
|
|
||
| Build-Scan-Container-op-challenger: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-challenger/Dockerfile | ||
|
|
||
| Build-Scan-Container-endpoint-monitor: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: endpoint-monitor/Dockerfile | ||
|
|
||
| Build-Scan-Container-opwheel: | ||
| uses: celo-org/reusable-workflows/.github/workflows/container-cicd-local.yaml@v1.11.2 | ||
| with: | ||
| dockerfile: op-wheel/Dockerfile | ||
|
|
||
| detect-files-changed: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| files-changed: ${{ steps.detect-files-changed.outputs.all_changed_files }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Detect files changed | ||
| id: detect-files-changed | ||
| uses: tj-actions/changed-files@v44 | ||
| with: | ||
| separator: ',' | ||
|
|
||
| build-cel2-migration-tool: | ||
| runs-on: ubuntu-latest | ||
| needs: detect-files-changed | ||
| if: | | ||
| contains(needs.detect-files-changed.outputs.files-changed, 'op-chain-ops/cmd/celo-dbmigrate') || | ||
| contains(needs.detect-files-changed.outputs.files-changed, 'op-chain-ops/cmd/celo-migrate') || | ||
| contains(needs.detect-files-changed.outputs.files-changed, 'op-chain-ops/Dockerfile') | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| security-events: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Login at GCP Artifact Registry | ||
| uses: celo-org/reusable-workflows/.github/actions/auth-gcp-artifact-registry@v2.0 | ||
| with: | ||
| workload-id-provider: 'projects/1094498259535/locations/global/workloadIdentityPools/gh-optimism/providers/github-by-repos' | ||
| service-account: 'celo-optimism-gh@devopsre.iam.gserviceaccount.com' | ||
| docker-gcp-registries: us-west1-docker.pkg.dev | ||
| - name: Build and push container | ||
| uses: celo-org/reusable-workflows/.github/actions/build-container@v2.0 | ||
| with: | ||
| platforms: linux/amd64 | ||
| registry: us-west1-docker.pkg.dev/devopsre/dev-images/cel2-migration-tool | ||
| tags: ${{ github.sha }} | ||
| context: ./ | ||
| dockerfile: ./op-chain-ops/Dockerfile | ||
| push: true | ||
| trivy: false | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -226,7 +226,8 @@ require ( | |||||||||||
| rsc.io/tmplfunc v0.0.3 // indirect | ||||||||||||
| ) | ||||||||||||
|
|
||||||||||||
| replace github.com/ethereum/go-ethereum => github.com/celo-org/op-geth v0.0.0-20240612131021-96a2a76ceaaa | ||||||||||||
| // replace github.com/ethereum/go-ethereum => github.com/celo-org/op-geth v0.0.0-20240612131021-96a2a76ceaaa | ||||||||||||
| replace github.com/ethereum/go-ethereum => github.com/celo-org/op-geth v0.0.0-20240612164035-ef9b9a19f53e | ||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that we'll need to wait for my branch to be merged before you can merge this PR and after my branch has been merged you'll need to update this reference. |
||||||||||||
|
|
||||||||||||
| //replace github.com/ethereum/go-ethereum v1.13.9 => ../op-geth | ||||||||||||
|
Comment on lines
+229
to
232
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| FROM golang:1.21.1-alpine3.18 as builder | ||
|
|
||
| RUN apk --no-cache add make | ||
|
|
||
| COPY ./go.mod /app/go.mod | ||
| COPY ./go.sum /app/go.sum | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| RUN go mod download | ||
|
|
||
| COPY ./op-bindings /app/op-bindings | ||
| COPY ./op-service /app/op-service | ||
| COPY ./op-node /app/op-node | ||
| COPY ./op-chain-ops /app/op-chain-ops | ||
| WORKDIR /app/op-chain-ops | ||
| RUN make celo-dbmigrate celo-migrate | ||
|
|
||
| FROM alpine:3.18 | ||
| RUN apk --no-cache add ca-certificates bash rsync | ||
|
|
||
| # RUN addgroup -S app && adduser -S app -G app | ||
| # USER app | ||
| WORKDIR /app | ||
|
|
||
| COPY --from=builder /app/op-chain-ops/bin/celo-dbmigrate /app | ||
| COPY --from=builder /app/op-chain-ops/bin/celo-migrate /app | ||
| ENV PATH="/app:${PATH}" | ||
|
|
||
| ENTRYPOINT ["/app/celo-dbmigrate"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
| "path/filepath" | ||
|
|
||
| "github.com/ethereum/go-ethereum/common" | ||
| "github.com/ethereum/go-ethereum/core/rawdb" | ||
| "github.com/ethereum/go-ethereum/ethdb" | ||
| "github.com/ethereum/go-ethereum/log" | ||
| "golang.org/x/sync/errgroup" | ||
| ) | ||
|
|
||
| // RLPBlockRange is a range of blocks in RLP format | ||
| type RLPBlockRange struct { | ||
| start uint64 | ||
| hashes [][]byte | ||
| headers [][]byte | ||
| bodies [][]byte | ||
| receipts [][]byte | ||
| tds [][]byte | ||
| } | ||
|
|
||
| func migrateAncientsDb(oldDBPath, newDBPath string, batchSize uint64) (uint64, error) { | ||
| oldFreezer, err := rawdb.NewChainFreezer(filepath.Join(oldDBPath, "ancient"), "", false) // TODO can't be readonly because we need the .meta files to be created | ||
| if err != nil { | ||
| return 0, fmt.Errorf("failed to open old freezer: %w", err) | ||
| } | ||
| defer oldFreezer.Close() | ||
|
|
||
| newFreezer, err := rawdb.NewChainFreezer(filepath.Join(newDBPath, "ancient"), "", false) | ||
| if err != nil { | ||
| return 0, fmt.Errorf("failed to open new freezer: %w", err) | ||
| } | ||
| defer newFreezer.Close() | ||
|
|
||
| numAncientsOld, err := oldFreezer.Ancients() | ||
| if err != nil { | ||
| return 0, fmt.Errorf("failed to get number of ancients in old freezer: %w", err) | ||
| } | ||
|
|
||
| numAncientsNew, err := newFreezer.Ancients() | ||
| if err != nil { | ||
| return 0, fmt.Errorf("failed to get number of ancients in new freezer: %w", err) | ||
| } | ||
|
|
||
| log.Info("Migration Started", "process", "ancients migration", "startBlock", numAncientsNew, "endBlock", numAncientsOld, "count", numAncientsOld-numAncientsNew+1) | ||
| g, ctx := errgroup.WithContext(context.Background()) | ||
| readChan := make(chan RLPBlockRange, 10) | ||
| transformChan := make(chan RLPBlockRange, 10) | ||
|
|
||
| log.Info("Migrating data", "start", numAncientsNew, "end", numAncientsOld, "step", batchSize) | ||
|
|
||
| g.Go(func() error { | ||
| return readAncientBlocks(ctx, oldFreezer, numAncientsNew, numAncientsOld, batchSize, readChan) | ||
| }) | ||
| g.Go(func() error { return transformBlocks(ctx, readChan, transformChan) }) | ||
| g.Go(func() error { return writeAncientBlocks(ctx, newFreezer, transformChan) }) | ||
|
|
||
| if err = g.Wait(); err != nil { | ||
| return 0, fmt.Errorf("failed to migrate ancients: %w", err) | ||
| } | ||
|
|
||
| numAncientsNew, err = newFreezer.Ancients() | ||
| if err != nil { | ||
| return 0, fmt.Errorf("failed to get number of ancients in new freezer: %w", err) | ||
| } | ||
|
|
||
| log.Info("Migration End", "process", "ancients migration", "totalBlocks", numAncientsNew) | ||
| return numAncientsNew, nil | ||
| } | ||
|
|
||
| func readAncientBlocks(ctx context.Context, freezer *rawdb.Freezer, startBlock, endBlock, batchSize uint64, out chan<- RLPBlockRange) error { | ||
| defer close(out) | ||
|
|
||
| for i := startBlock; i < endBlock; i += batchSize { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return ctx.Err() | ||
| default: | ||
| count := min(batchSize, endBlock-i+1) | ||
| start := i | ||
|
|
||
| blockRange := RLPBlockRange{ | ||
| start: start, | ||
| hashes: make([][]byte, count), | ||
| headers: make([][]byte, count), | ||
| bodies: make([][]byte, count), | ||
| receipts: make([][]byte, count), | ||
| tds: make([][]byte, count), | ||
| } | ||
| var err error | ||
|
|
||
| blockRange.hashes, err = freezer.AncientRange(rawdb.ChainFreezerHashTable, start, count, 0) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read hashes from old freezer: %w", err) | ||
| } | ||
| blockRange.headers, err = freezer.AncientRange(rawdb.ChainFreezerHeaderTable, start, count, 0) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read headers from old freezer: %w", err) | ||
| } | ||
| blockRange.bodies, err = freezer.AncientRange(rawdb.ChainFreezerBodiesTable, start, count, 0) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read bodies from old freezer: %w", err) | ||
| } | ||
| blockRange.receipts, err = freezer.AncientRange(rawdb.ChainFreezerReceiptTable, start, count, 0) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read receipts from old freezer: %w", err) | ||
| } | ||
| blockRange.tds, err = freezer.AncientRange(rawdb.ChainFreezerDifficultyTable, start, count, 0) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to read tds from old freezer: %w", err) | ||
| } | ||
|
|
||
| out <- blockRange | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func transformBlocks(ctx context.Context, in <-chan RLPBlockRange, out chan<- RLPBlockRange) error { | ||
| // Transform blocks from the in channel and send them to the out channel | ||
| defer close(out) | ||
| for blockRange := range in { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return ctx.Err() | ||
| default: | ||
| for i := range blockRange.hashes { | ||
| blockNumber := blockRange.start + uint64(i) | ||
|
|
||
| newHeader, err := transformHeader(blockRange.headers[i]) | ||
| if err != nil { | ||
| return fmt.Errorf("can't transform header: %w", err) | ||
| } | ||
| newBody, err := transformBlockBody(blockRange.bodies[i]) | ||
| if err != nil { | ||
| return fmt.Errorf("can't transform body: %w", err) | ||
| } | ||
|
|
||
| if yes, newHash := hasSameHash(newHeader, blockRange.hashes[i]); !yes { | ||
| log.Error("Hash mismatch", "block", blockNumber, "oldHash", common.BytesToHash(blockRange.hashes[i]), "newHash", newHash) | ||
| return fmt.Errorf("hash mismatch at block %d", blockNumber) | ||
| } | ||
|
|
||
| blockRange.headers[i] = newHeader | ||
| blockRange.bodies[i] = newBody | ||
| } | ||
| out <- blockRange | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func writeAncientBlocks(ctx context.Context, freezer *rawdb.Freezer, in <-chan RLPBlockRange) error { | ||
| // Write blocks from the in channel to the newDb | ||
| for blockRange := range in { | ||
| select { | ||
| case <-ctx.Done(): | ||
| return ctx.Err() | ||
| default: | ||
| _, err := freezer.ModifyAncients(func(aWriter ethdb.AncientWriteOp) error { | ||
| for i := range blockRange.hashes { | ||
| blockNumber := blockRange.start + uint64(i) | ||
| if err := aWriter.AppendRaw(rawdb.ChainFreezerHashTable, blockNumber, blockRange.hashes[i]); err != nil { | ||
| return fmt.Errorf("can't write hash to Freezer: %w", err) | ||
| } | ||
| if err := aWriter.AppendRaw(rawdb.ChainFreezerHeaderTable, blockNumber, blockRange.headers[i]); err != nil { | ||
| return fmt.Errorf("can't write header to Freezer: %w", err) | ||
| } | ||
| if err := aWriter.AppendRaw(rawdb.ChainFreezerBodiesTable, blockNumber, blockRange.bodies[i]); err != nil { | ||
| return fmt.Errorf("can't write body to Freezer: %w", err) | ||
| } | ||
| if err := aWriter.AppendRaw(rawdb.ChainFreezerReceiptTable, blockNumber, blockRange.receipts[i]); err != nil { | ||
| return fmt.Errorf("can't write receipts to Freezer: %w", err) | ||
| } | ||
| if err := aWriter.AppendRaw(rawdb.ChainFreezerDifficultyTable, blockNumber, blockRange.tds[i]); err != nil { | ||
| return fmt.Errorf("can't write td to Freezer: %w", err) | ||
| } | ||
| } | ||
| return nil | ||
| }) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to write block range: %w", err) | ||
| } | ||
| log.Info("Wrote ancient blocks", "start", blockRange.start, "end", blockRange.start+uint64(len(blockRange.hashes)-1), "count", len(blockRange.hashes)) | ||
| } | ||
| } | ||
| return nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes added here c861c70