diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000000..542de477686a
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,25 @@
+version: 2
+updates:
+ # Check for updates on our docker image and for celestia-node
+ - package-ecosystem: docker
+ directory: "/ops-bedrock"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ labels:
+ - dependencies
+ - package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ labels:
+ - dependencies
+ # Check for updates on celestia packages
+ - package-ecosystem: gomod
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ labels:
+ - dependencies
diff --git a/.github/workflows/fork-sync.yml b/.github/workflows/fork-sync.yml
new file mode 100644
index 000000000000..33b5d4b2fcd5
--- /dev/null
+++ b/.github/workflows/fork-sync.yml
@@ -0,0 +1,18 @@
+name: Sync Fork
+
+on:
+ schedule:
+ - cron: '*/30 * * * *' # every 30 minutes
+ workflow_dispatch: # on button click
+
+jobs:
+ sync:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: tgymnich/fork-sync@v1.8
+ with:
+ owner: llvm
+ base: celesita-develop
+ head: develop
\ No newline at end of file
diff --git a/Makefile b/Makefile
index fb6ba7049db5..c9ddb9805e53 100644
--- a/Makefile
+++ b/Makefile
@@ -65,26 +65,46 @@ devnet-up:
@bash ./ops-bedrock/devnet-up.sh
.PHONY: devnet-up
+testnet-up:
+ @bash ./ops-bedrock/testnet-up.sh
+.PHONY: testnet-up
+
devnet-up-deploy:
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=.
.PHONY: devnet-up-deploy
devnet-down:
- @(cd ./ops-bedrock && GENESIS_TIMESTAMP=$(shell date +%s) docker-compose stop)
+ @(cd ./ops-bedrock && GENESIS_TIMESTAMP=$(shell date +%s) docker-compose -f docker-compose-devnet.yml stop)
.PHONY: devnet-down
+testnet-down:
+ @(cd ./ops-bedrock && GENESIS_TIMESTAMP=$(shell date +%s) docker-compose -f docker-compose-testnet.yml stop)
+.PHONY: testnet-down
+
devnet-clean:
rm -rf ./packages/contracts-bedrock/deployments/devnetL1
rm -rf ./.devnet
- cd ./ops-bedrock && docker-compose down
+ cd ./ops-bedrock && docker-compose -f docker-compose-devnet.yml down
docker image ls 'ops-bedrock*' --format='{{.Repository}}' | xargs -r docker rmi
docker volume ls --filter name=ops-bedrock --format='{{.Name}}' | xargs -r docker volume rm
.PHONY: devnet-clean
+testnet-clean:
+ rm -rf ./packages/contracts-bedrock/deployments/devnetL1
+ rm -rf ./.devnet
+ cd ./ops-bedrock && docker-compose -f docker-compose-testnet.yml down
+ docker image ls 'ops-bedrock*' --format='{{.Repository}}' | xargs -r docker rmi
+ docker volume ls --filter name=ops-bedrock --format='{{.Name}}' | xargs -r docker volume rm
+.PHONY: testnet-clean
+
devnet-logs:
- @(cd ./ops-bedrock && docker-compose logs -f)
+ @(cd ./ops-bedrock && docker-compose -f docker-compose-devnet.yml logs -f)
.PHONY: devnet-logs
+testnet-logs:
+ @(cd ./ops-bedrock && docker-compose -f docker-compose-testnet.yml logs -f)
+ .PHONY: testnet-logs
+
test-unit:
make -C ./op-node test
make -C ./op-proposer test
diff --git a/README.md b/README.md
index 767fce6e619a..c7f17e261a4d 100644
--- a/README.md
+++ b/README.md
@@ -3,50 +3,100 @@
+
Optimism is a low-cost and lightning-fast Ethereum L2 blockchain, built with the OP Stack.
- Optimism is a low-cost and lightning-fast Ethereum L2 blockchain.
+ +
+
+ Celestia is a modular consensus and data network, built to enable anyone to easily deploy their own blockchain with minimal overhead.
-## What is Optimism?
+## Celestia + OP Stack tutorial
+
+If you're looking to run the OP Stack + Celestia setup for this repository, please visit the [Optimism & Celestia guides and tutorials](https://docs.celestia.org/developers/intro-to-op-stack/) to get started.
+
+## What are Optimism and the OP Stack?
Optimism is a low-cost and lightning-fast Ethereum L2 blockchain, **but it's also so much more than that**.
-Optimism is the technical foundation for [the Optimism Collective](https://app.optimism.io/announcement), a band of communities, companies, and citizens united by a mutually beneficial pact to adhere to the axiom of **impact=profit** — the principle that positive impact to the collective should be rewarded with profit to the individual.
-We're trying to solve some of the most critical coordination failures facing the crypto ecosystem today.
-**We're particularly focused on creating a sustainable funding stream for the public goods and infrastructure upon which the ecosystem so heavily relies but has so far been unable to adequately reward.**
-We'd love for you to check out [The Optimistic Vision](https://www.optimism.io/vision) to understand more about why we do what we do.
+The OP Stack powers Optimism, an Ethereum L2 blockchain, and forms the technical foundation for the [the Optimism Collective](https://app.optimism.io/announcement)—a group committed to the **impact=profit** principle. This principle rewards individuals for their positive contributions to the collective.
+
+Optimism addresses critical coordination failures in the crypto ecosystem, such as funding public goods and infrastructure. The OP Stack focuses on creating a shared, open-source system for developing new L2 blockchains within the proposed Superchain ecosystem, promoting collaboration and preventing redundant efforts.
+
+As Optimism evolves, the OP Stack will adapt, encompassing components ranging from blockchain infrastructure to governance systems. This software suite aims to simplify L2 blockchain creation while supporting the growth and development of the Optimism ecosystem.
+
+## What is Celestia?
+
+Celestia is a modular consensus and data network, built to enable anyone to easily deploy their own blockchain with minimal overhead.
+
+Celestia is a minimal blockchain that only orders and publishes transactions and does not execute them. By decoupling the consensus and application execution layers, Celestia modularizes the blockchain technology stack and unlocks new possibilities for decentralized application builders. Lean more at [Celestia.org](https://celestia.org).
+
+## Maintenance
+
+The maintenance guide for this repository can be found in the Wiki tab of the repository or [here](https://github.com/celestiaorg/optimism/wiki).
## Documentation
-If you want to build on top of Optimism, take a look at the extensive documentation on the [Optimism Community Hub](http://community.optimism.io/).
-If you want to build Optimism, check out the [Protocol Specs](./specs/).
+If you want to build on top of Celestia, take a look at the documentation at [docs.celestia.org](https://docs.celestia.org).
+
+If you want to learn more about the OP Stack, check out the documentation at [stack.optimism.io](https://stack.optimism.io/).
## Community
+### Optimism
+
General discussion happens most frequently on the [Optimism discord](https://discord.gg/optimism).
Governance discussion can also be found on the [Optimism Governance Forum](https://gov.optimism.io/).
-## Contributing
+### Celestia
+
+General discussion happens most frequently on the [Celestia discord](https://discord.com/invite/YsnTPcSfWQ).
+Other discussions can be found on the [Celestia forum](https://forum.celestia.org).
+
+
+
+## e2e testing
+
+This repository has updated end-to-end tests in the `op-e2e` package to work with
+Celestia as the data availability (DA) layer.
+
+Currently, the tests assume a working [Celestia devnet](https://github.com/rollkit/local-celestia-devnet) running locally:
-## Security Policy and Vulnerability Reporting
+```bash
+docker run --platform linux/amd64 -p 26650:26657 -p 26659:26659 ghcr.io/rollkit/local-celestia-devnet:v0.9.5
+```
-Please refer to our canonical [Security Policy](https://github.com/ethereum-optimism/.github/blob/master/SECURITY.md) document for detailed information about how to report vulnerabilities in this codebase.
-Bounty hunters are encouraged to check out [our Immunefi bug bounty program](https://immunefi.com/bounty/optimism/).
-We offer up to $2,000,042 for in-scope critical vulnerabilities and [we pay our maximum bug bounty rewards](https://medium.com/ethereum-optimism/disclosure-fixing-a-critical-bug-in-optimisms-geth-fork-a836ebdf7c94).
+The e2e tests can be triggered with:
-## The Bedrock Upgrade
+```bash
+cd $HOME/optimism
+cd op-e2e
+make test
+```
-Optimism is currently preparing for [its next major upgrade called Bedrock](https://dev.optimism.io/introducing-optimism-bedrock/).
-Bedrock significantly revamps how Optimism works under the hood and will help make Optimism the fastest, cheapest, and most reliable rollup yet.
-You can find detailed specifications for the Bedrock upgrade within the [specs folder](./specs) in this repository.
+## Bridging
-Please note that a significant number of packages and folders within this repository are part of the Bedrock upgrade and are NOT currently running in production.
-Refer to the Directory Structure section below to understand which packages are currently running in production and which are intended for use as part of the Bedrock upgrade.
+If you have the OP Stack + Celestia setup running, you can test out bridging from the L1
+to the L2.
+
+To do this, first navigate to the `packages/contracts-bedrock` directory and create a
+`.env` file with the following contents:
+
+```bash
+L1_PROVIDER_URL=http://localhost:8545
+L2_PROVIDER_URL=http://localhost:9545
+PRIVATE_KEY=bf7604d9d3a1c7748642b1b7b05c2bd219c9faa91458b370f85e5a40f3b03af7
+```
+
+Then, run the following from the same directory:
+
+```bash
+npx hardhat deposit --network devnetL1 --l1-provider-url http://localhost:8545 --l2-provider-url http://localhost:9545 --amount-eth --to
+```
## Directory Structure
@@ -86,7 +136,7 @@ Refer to the Directory Structure section below to understand which packages are
├── ops-bedrock: Bedrock devnet work
└── specs: Specs of the rollup starting at the Bedrock upgrade
-
+
diff --git a/bedrock-devnet/devnet/__init__.py b/bedrock-devnet/devnet/__init__.py
index f9a6c494301e..a81aa1bd733f 100644
--- a/bedrock-devnet/devnet/__init__.py
+++ b/bedrock-devnet/devnet/__init__.py
@@ -111,6 +111,10 @@ def main():
})
wait_up(9545)
+ log.info('Bringing up DA')
+ run_command(['docker-compose', 'up', '-d', 'da'], cwd=ops_bedrock_dir, env={
+ 'PWD': ops_bedrock_dir,
+ })
log.info('Bringing up everything else.')
run_command(['docker-compose', 'up', '-d', 'op-node', 'op-proposer', 'op-batcher'], cwd=ops_bedrock_dir, env={
'PWD': ops_bedrock_dir,
diff --git a/docs/op-stack/src/assets/docs/understand/Celestia-logo-color-color.svg b/docs/op-stack/src/assets/docs/understand/Celestia-logo-color-color.svg
new file mode 100644
index 000000000000..6d22cb408925
--- /dev/null
+++ b/docs/op-stack/src/assets/docs/understand/Celestia-logo-color-color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 1c672dd091b0..5a0d9e3ec25e 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.19
require (
github.com/btcsuite/btcd v0.23.3
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
+ github.com/celestiaorg/go-cnc v0.4.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0
github.com/docker/docker v20.10.24+incompatible
github.com/docker/go-connections v0.4.0
@@ -29,7 +30,7 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/prometheus/client_golang v1.14.0
github.com/schollz/progressbar/v3 v3.13.0
- github.com/stretchr/testify v1.8.1
+ github.com/stretchr/testify v1.8.2
github.com/urfave/cli v1.22.9
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
golang.org/x/crypto v0.6.0
@@ -72,6 +73,7 @@ require (
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
@@ -125,7 +127,6 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/pointerstructure v1.2.1 // indirect
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
- github.com/morikuni/aec v1.0.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect
@@ -137,7 +138,7 @@ require (
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/onsi/ginkgo/v2 v2.8.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.0.2 // indirect
+ github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
diff --git a/go.sum b/go.sum
index d80b907b8057..d201f1637650 100644
--- a/go.sum
+++ b/go.sum
@@ -89,6 +89,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
+github.com/celestiaorg/go-cnc v0.4.1 h1:7fz8Y8HKKxE2dCp2m9Qlm+NoROxJWGCiKtcvaYp8iM8=
+github.com/celestiaorg/go-cnc v0.4.1/go.mod h1:zYzvHudSd1iNPuHBMyvZ1YvWou5aT9JXgtch9Tkaf70=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -241,6 +243,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
+github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
+github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@@ -579,7 +583,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
-github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
@@ -641,8 +644,8 @@ github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9
github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
-github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
+github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@@ -787,8 +790,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI=
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
@@ -955,6 +958,7 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
diff --git a/op-batcher/flags/flags.go b/op-batcher/flags/flags.go
index 006017ef8bcd..37e225180fbe 100644
--- a/op-batcher/flags/flags.go
+++ b/op-batcher/flags/flags.go
@@ -33,6 +33,12 @@ var (
Usage: "HTTP provider URL for Rollup node",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "ROLLUP_RPC"),
}
+ DaRpcFlag = cli.StringFlag{
+ Name: "da-rpc",
+ Usage: "HTTP provider URL for DA node",
+ Required: true,
+ EnvVar: opservice.PrefixEnvVar(envVarPrefix, "DA_RPC"),
+ }
SubSafetyMarginFlag = cli.Uint64Flag{
Name: "sub-safety-margin",
Usage: "The batcher tx submission safety margin (in #L1-blocks) to subtract " +
@@ -91,6 +97,7 @@ var requiredFlags = []cli.Flag{
L1EthRpcFlag,
L2EthRpcFlag,
RollupRpcFlag,
+ DaRpcFlag,
SubSafetyMarginFlag,
PollIntervalFlag,
}
diff --git a/op-celestia/go.mod b/op-celestia/go.mod
new file mode 100644
index 000000000000..ea993b8cfb1f
--- /dev/null
+++ b/op-celestia/go.mod
@@ -0,0 +1,11 @@
+module github.com/ethereum-optimism/optimism/op-celestia
+
+go 1.19
+
+require github.com/celestiaorg/go-cnc v0.4.1
+
+require (
+ github.com/go-resty/resty/v2 v2.7.0 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 // indirect
+)
diff --git a/op-celestia/go.sum b/op-celestia/go.sum
new file mode 100644
index 000000000000..37e622ee7363
--- /dev/null
+++ b/op-celestia/go.sum
@@ -0,0 +1,42 @@
+github.com/celestiaorg/go-cnc v0.4.1 h1:7fz8Y8HKKxE2dCp2m9Qlm+NoROxJWGCiKtcvaYp8iM8=
+github.com/celestiaorg/go-cnc v0.4.1/go.mod h1:zYzvHudSd1iNPuHBMyvZ1YvWou5aT9JXgtch9Tkaf70=
+github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
+github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc=
+golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/op-celestia/main.go b/op-celestia/main.go
new file mode 100644
index 000000000000..fc76b30b50b4
--- /dev/null
+++ b/op-celestia/main.go
@@ -0,0 +1,44 @@
+package main
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/celestiaorg/go-cnc"
+)
+
+func main() {
+ data, _ := hex.DecodeString(os.Args[2])
+ buf := bytes.NewBuffer(data)
+ var height int64
+ err := binary.Read(buf, binary.BigEndian, &height)
+ if err != nil {
+ panic(err)
+ }
+ var index uint32
+ err = binary.Read(buf, binary.BigEndian, &index)
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("celestia block height: %v; tx index: %v\n", height, index)
+ fmt.Println("-----------------------------------------")
+ client, err := cnc.NewClient("http://localhost:26659", cnc.WithTimeout(30*time.Second))
+ if err != nil {
+ panic(err)
+ }
+ nsBytes, err := hex.DecodeString(os.Args[1])
+ if err != nil {
+ panic(err)
+ }
+ namespace := cnc.MustNewV0(nsBytes)
+ namespacedData, err := client.NamespacedData(context.Background(), namespace, uint64(height))
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("optimism block data on celestia: %x\n", namespacedData)
+}
diff --git a/op-celestia/op-celestia b/op-celestia/op-celestia
new file mode 100755
index 000000000000..3a77ca74c253
Binary files /dev/null and b/op-celestia/op-celestia differ
diff --git a/op-e2e/actions/l2_verifier.go b/op-e2e/actions/l2_verifier.go
index d1293ecc7c6f..d2cc14801d56 100644
--- a/op-e2e/actions/l2_verifier.go
+++ b/op-e2e/actions/l2_verifier.go
@@ -57,7 +57,9 @@ type L2API interface {
func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, eng L2API, cfg *rollup.Config) *L2Verifier {
metrics := &testutils.TestDerivationMetrics{}
- pipeline := derive.NewDerivationPipeline(log, cfg, l1, eng, metrics)
+ daCfg, err := rollup.NewDAConfig("http://localhost:26659", "0000e8e5f679bf7116cb")
+ require.NoError(t, err)
+ pipeline := derive.NewDerivationPipeline(log, cfg, daCfg, l1, eng, metrics)
pipeline.Reset()
rollupNode := &L2Verifier{
diff --git a/op-e2e/setup.go b/op-e2e/setup.go
index 6e99c0bb54be..0a5e08d13472 100644
--- a/op-e2e/setup.go
+++ b/op-e2e/setup.go
@@ -57,6 +57,7 @@ func newTxMgrConfig(l1Addr string, privKey *ecdsa.PrivateKey) txmgr.CLIConfig {
ReceiptQueryInterval: 50 * time.Millisecond,
NetworkTimeout: 2 * time.Second,
TxNotInMempoolTimeout: 2 * time.Minute,
+ NamespaceId: "000008e5f679bf7116cb",
}
}
@@ -532,6 +533,13 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
c.Rollup.LogDescription(cfg.Loggers[name], chaincfg.L2ChainIDToNetworkName)
+ daCfg, err := rollup.NewDAConfig("http://127.0.0.1:26659", "0000e8e5f679bf7116cb")
+ if err != nil {
+ return nil, err
+ }
+
+ c.DAConfig = *daCfg
+
node, err := rollupNode.New(context.Background(), &c, cfg.Loggers[name], snapLog, "", metrics.NewMetrics(""))
if err != nil {
didErrAfterStart = true
diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go
index ded27af0b72e..ffb07fac6686 100644
--- a/op-node/flags/flags.go
+++ b/op-node/flags/flags.go
@@ -38,6 +38,18 @@ var (
Usage: "Rollup chain parameters",
EnvVar: prefixEnvVar("ROLLUP_CONFIG"),
}
+ DaRPC = cli.StringFlag{
+ Name: "da-rpc",
+ Usage: "Data Availability RPC",
+ Value: "http://da:26659",
+ EnvVar: prefixEnvVar("DA_RPC"),
+ }
+ NamespaceId = cli.StringFlag{
+ Name: "namespace-id",
+ Usage: "Namespace ID for DA node",
+ Value: "000008e5f679bf7116cb",
+ EnvVar: prefixEnvVar("NAMESPACE_ID"),
+ }
Network = cli.StringFlag{
Name: "network",
Usage: fmt.Sprintf("Predefined network selection. Available networks: %s", strings.Join(chaincfg.AvailableNetworks(), ", ")),
@@ -218,6 +230,8 @@ var requiredFlags = []cli.Flag{
var optionalFlags = []cli.Flag{
RollupConfig,
+ DaRPC,
+ NamespaceId,
Network,
L1TrustRPC,
L1RPCProviderKind,
diff --git a/op-node/node/config.go b/op-node/node/config.go
index 37533a868aa0..f85e1f61a474 100644
--- a/op-node/node/config.go
+++ b/op-node/node/config.go
@@ -21,6 +21,8 @@ type Config struct {
Rollup rollup.Config
+ DAConfig rollup.DAConfig
+
// P2PSigner will be used for signing off on published content
// if the node is sequencing and if the p2p stack is enabled
P2PSigner p2p.SignerSetup
diff --git a/op-node/node/node.go b/op-node/node/node.go
index 0dd4b89144e9..3c30178e9fc5 100644
--- a/op-node/node/node.go
+++ b/op-node/node/node.go
@@ -17,6 +17,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/metrics"
"github.com/ethereum-optimism/optimism/op-node/p2p"
+ "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-node/sources"
)
@@ -39,6 +40,7 @@ type OpNode struct {
p2pSigner p2p.Signer // p2p gogssip application messages will be signed with this signer
tracer Tracer // tracer to get events for testing/debugging
runCfg *RuntimeConfig // runtime configurables
+ daCfg *rollup.DAConfig
// some resources cannot be stopped directly, like the p2p gossipsub router (not our design),
// and depend on this ctx to be closed.
@@ -74,7 +76,15 @@ func New(ctx context.Context, cfg *Config, log log.Logger, snapshotLog log.Logge
return n, nil
}
+func (n *OpNode) initDA(ctx context.Context, cfg *Config) error {
+ n.daCfg = &cfg.DAConfig
+ return nil
+}
+
func (n *OpNode) init(ctx context.Context, cfg *Config, snapshotLog log.Logger) error {
+ if err := n.initDA(ctx, cfg); err != nil {
+ return err
+ }
if err := n.initTracer(ctx, cfg); err != nil {
return err
}
@@ -199,7 +209,7 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config, snapshotLog log.Logger
return err
}
- n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.l2Source, n.l1Source, n, n, n.log, snapshotLog, n.metrics)
+ n.l2Driver = driver.NewDriver(&cfg.Driver, &cfg.Rollup, n.daCfg, n.l2Source, n.l1Source, n, n, n.log, snapshotLog, n.metrics)
return nil
}
diff --git a/op-node/rollup/da_config.go b/op-node/rollup/da_config.go
new file mode 100644
index 000000000000..e036e50eae8b
--- /dev/null
+++ b/op-node/rollup/da_config.go
@@ -0,0 +1,34 @@
+package rollup
+
+import (
+ "encoding/hex"
+ "time"
+
+ "github.com/celestiaorg/go-cnc"
+)
+
+type DAConfig struct {
+ Rpc string
+ Namespace cnc.Namespace
+ Client *cnc.Client
+}
+
+func NewDAConfig(rpc string, ns string) (*DAConfig, error) {
+ nsBytes, err := hex.DecodeString(ns)
+ if err != nil {
+ return &DAConfig{}, err
+ }
+
+ namespace := cnc.MustNewV0(nsBytes)
+
+ daClient, err := cnc.NewClient(rpc, cnc.WithTimeout(30*time.Second))
+ if err != nil {
+ return &DAConfig{}, err
+ }
+
+ return &DAConfig{
+ Namespace: namespace,
+ Rpc: rpc,
+ Client: daClient,
+ }, nil
+}
diff --git a/op-node/rollup/derive/calldata_source.go b/op-node/rollup/derive/calldata_source.go
index 52314420a8de..4dbdaedc96ec 100644
--- a/op-node/rollup/derive/calldata_source.go
+++ b/op-node/rollup/derive/calldata_source.go
@@ -1,7 +1,10 @@
package derive
import (
+ "bytes"
"context"
+ "encoding/binary"
+ "encoding/hex"
"errors"
"fmt"
"io"
@@ -29,16 +32,17 @@ type L1TransactionFetcher interface {
type DataSourceFactory struct {
log log.Logger
cfg *rollup.Config
+ daCfg *rollup.DAConfig
fetcher L1TransactionFetcher
}
-func NewDataSourceFactory(log log.Logger, cfg *rollup.Config, fetcher L1TransactionFetcher) *DataSourceFactory {
- return &DataSourceFactory{log: log, cfg: cfg, fetcher: fetcher}
+func NewDataSourceFactory(log log.Logger, cfg *rollup.Config, daCfg *rollup.DAConfig, fetcher L1TransactionFetcher) *DataSourceFactory {
+ return &DataSourceFactory{log: log, cfg: cfg, daCfg: daCfg, fetcher: fetcher}
}
// OpenData returns a DataIter. This struct implements the `Next` function.
-func (ds *DataSourceFactory) OpenData(ctx context.Context, id eth.BlockID, batcherAddr common.Address) DataIter {
- return NewDataSource(ctx, ds.log, ds.cfg, ds.fetcher, id, batcherAddr)
+func (ds *DataSourceFactory) OpenData(ctx context.Context, id eth.BlockID, batcherAddr common.Address) (DataIter, error) {
+ return NewDataSource(ctx, ds.log, ds.cfg, ds.daCfg, ds.fetcher, id, batcherAddr)
}
// DataSource is a fault tolerant approach to fetching data.
@@ -51,6 +55,7 @@ type DataSource struct {
// Required to re-attempt fetching
id eth.BlockID
cfg *rollup.Config // TODO: `DataFromEVMTransactions` should probably not take the full config
+ daCfg *rollup.DAConfig
fetcher L1TransactionFetcher
log log.Logger
@@ -59,7 +64,7 @@ type DataSource struct {
// NewDataSource creates a new calldata source. It suppresses errors in fetching the L1 block if they occur.
// If there is an error, it will attempt to fetch the result on the next call to `Next`.
-func NewDataSource(ctx context.Context, log log.Logger, cfg *rollup.Config, fetcher L1TransactionFetcher, block eth.BlockID, batcherAddr common.Address) DataIter {
+func NewDataSource(ctx context.Context, log log.Logger, cfg *rollup.Config, daCfg *rollup.DAConfig, fetcher L1TransactionFetcher, block eth.BlockID, batcherAddr common.Address) (DataIter, error) {
_, txs, err := fetcher.InfoAndTxsByHash(ctx, block.Hash)
if err != nil {
return &DataSource{
@@ -69,12 +74,23 @@ func NewDataSource(ctx context.Context, log log.Logger, cfg *rollup.Config, fetc
fetcher: fetcher,
log: log,
batcherAddr: batcherAddr,
- }
+ }, nil
} else {
+ data, err := DataFromEVMTransactions(cfg, daCfg, batcherAddr, txs, log.New("origin", block))
+ if err != nil {
+ return &DataSource{
+ open: false,
+ id: block,
+ cfg: cfg,
+ fetcher: fetcher,
+ log: log,
+ batcherAddr: batcherAddr,
+ }, err
+ }
return &DataSource{
open: true,
- data: DataFromEVMTransactions(cfg, batcherAddr, txs, log.New("origin", block)),
- }
+ data: data,
+ }, nil
}
}
@@ -85,7 +101,11 @@ func (ds *DataSource) Next(ctx context.Context) (eth.Data, error) {
if !ds.open {
if _, txs, err := ds.fetcher.InfoAndTxsByHash(ctx, ds.id.Hash); err == nil {
ds.open = true
- ds.data = DataFromEVMTransactions(ds.cfg, ds.batcherAddr, txs, log.New("origin", ds.id))
+ ds.data, err = DataFromEVMTransactions(ds.cfg, ds.daCfg, ds.batcherAddr, txs, log.New("origin", ds.id))
+ if err != nil {
+ // already wrapped
+ return nil, err
+ }
} else if errors.Is(err, ethereum.NotFound) {
return nil, NewResetError(fmt.Errorf("failed to open calldata source: %w", err))
} else {
@@ -104,7 +124,7 @@ func (ds *DataSource) Next(ctx context.Context) (eth.Data, error) {
// DataFromEVMTransactions filters all of the transactions and returns the calldata from transactions
// that are sent to the batch inbox address from the batch sender address.
// This will return an empty array if no valid transactions are found.
-func DataFromEVMTransactions(config *rollup.Config, batcherAddr common.Address, txs types.Transactions, log log.Logger) []eth.Data {
+func DataFromEVMTransactions(config *rollup.Config, daCfg *rollup.DAConfig, batcherAddr common.Address, txs types.Transactions, log log.Logger) ([]eth.Data, error) {
var out []eth.Data
l1Signer := config.L1Signer()
for j, tx := range txs {
@@ -119,8 +139,42 @@ func DataFromEVMTransactions(config *rollup.Config, batcherAddr common.Address,
log.Warn("tx in inbox with unauthorized submitter", "index", j, "err", err)
continue // not an authorized batch submitter, ignore
}
- out = append(out, tx.Data())
+
+ if daCfg != nil {
+ height, index, err := decodeETHData(tx.Data())
+ if err != nil {
+ log.Warn("unable to decode data pointer", "index", j, "err", err)
+ return nil, err
+ }
+ log.Info("requesting data from celestia", "namespace", hex.EncodeToString(daCfg.Namespace.Bytes()), "height", height)
+ data, err := daCfg.Client.NamespacedData(context.Background(), daCfg.Namespace, uint64(height))
+ if err != nil {
+ return nil, NewResetError(fmt.Errorf("failed to retrieve data from celestia: %w", err))
+ }
+ log.Debug("retrieved data", "data", hex.EncodeToString(data[index]))
+ out = append(out, data[index])
+ } else {
+ out = append(out, tx.Data())
+ }
}
}
- return out
+ return out, nil
+}
+
+// decodeETHData will decode the data retrieved from the EVM, this data
+// was previously posted from op-batcher and contains the block height
+// with transaction index of the SubmitPFD transaction to the DA.
+func decodeETHData(celestiaData []byte) (int64, uint32, error) {
+ buf := bytes.NewBuffer(celestiaData)
+ var height int64
+ err := binary.Read(buf, binary.BigEndian, &height)
+ if err != nil {
+ return 0, 0, fmt.Errorf("error deserializing height: %w", err)
+ }
+ var index uint32
+ err = binary.Read(buf, binary.BigEndian, &index)
+ if err != nil {
+ return 0, 0, fmt.Errorf("error deserializing index: %w", err)
+ }
+ return height, index, nil
}
diff --git a/op-node/rollup/derive/calldata_source_test.go b/op-node/rollup/derive/calldata_source_test.go
index b7bfcd5a4ddf..a57fdb4e7d4c 100644
--- a/op-node/rollup/derive/calldata_source_test.go
+++ b/op-node/rollup/derive/calldata_source_test.go
@@ -121,8 +121,9 @@ func TestDataFromEVMTransactions(t *testing.T) {
}
}
- out := DataFromEVMTransactions(cfg, batcherAddr, txs, testlog.Logger(t, log.LvlCrit))
+ out, err := DataFromEVMTransactions(cfg, nil, batcherAddr, txs, testlog.Logger(t, log.LvlCrit))
require.ElementsMatch(t, expectedData, out)
+ require.NoError(t, err)
}
}
diff --git a/op-node/rollup/derive/l1_retrieval.go b/op-node/rollup/derive/l1_retrieval.go
index aecc19e6862b..50f1452f90c3 100644
--- a/op-node/rollup/derive/l1_retrieval.go
+++ b/op-node/rollup/derive/l1_retrieval.go
@@ -11,7 +11,7 @@ import (
)
type DataAvailabilitySource interface {
- OpenData(ctx context.Context, id eth.BlockID, batcherAddr common.Address) DataIter
+ OpenData(ctx context.Context, id eth.BlockID, batcherAddr common.Address) (DataIter, error)
}
type NextBlockProvider interface {
@@ -53,7 +53,10 @@ func (l1r *L1Retrieval) NextData(ctx context.Context) ([]byte, error) {
} else if err != nil {
return nil, err
}
- l1r.datas = l1r.dataSrc.OpenData(ctx, next.ID(), l1r.prev.SystemConfig().BatcherAddr)
+ l1r.datas, err = l1r.dataSrc.OpenData(ctx, next.ID(), l1r.prev.SystemConfig().BatcherAddr)
+ if err != nil {
+ return nil, err
+ }
}
l1r.log.Debug("fetching next piece of data")
@@ -73,7 +76,7 @@ func (l1r *L1Retrieval) NextData(ctx context.Context) ([]byte, error) {
// Note that we open up the `l1r.datas` here because it is requires to maintain the
// internal invariants that later propagate up the derivation pipeline.
func (l1r *L1Retrieval) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth.SystemConfig) error {
- l1r.datas = l1r.dataSrc.OpenData(ctx, base.ID(), sysCfg.BatcherAddr)
+ l1r.datas, _ = l1r.dataSrc.OpenData(ctx, base.ID(), sysCfg.BatcherAddr)
l1r.log.Info("Reset of L1Retrieval done", "origin", base)
return io.EOF
}
diff --git a/op-node/rollup/derive/pipeline.go b/op-node/rollup/derive/pipeline.go
index 4dcd74a8e778..22cbc97163ae 100644
--- a/op-node/rollup/derive/pipeline.go
+++ b/op-node/rollup/derive/pipeline.go
@@ -75,11 +75,11 @@ type DerivationPipeline struct {
}
// NewDerivationPipeline creates a derivation pipeline, which should be reset before use.
-func NewDerivationPipeline(log log.Logger, cfg *rollup.Config, l1Fetcher L1Fetcher, engine Engine, metrics Metrics) *DerivationPipeline {
+func NewDerivationPipeline(log log.Logger, cfg *rollup.Config, daCfg *rollup.DAConfig, l1Fetcher L1Fetcher, engine Engine, metrics Metrics) *DerivationPipeline {
// Pull stages
l1Traversal := NewL1Traversal(log, cfg, l1Fetcher)
- dataSrc := NewDataSourceFactory(log, cfg, l1Fetcher) // auxiliary stage for L1Retrieval
+ dataSrc := NewDataSourceFactory(log, cfg, daCfg, l1Fetcher) // auxiliary stage for L1Retrieval
l1Src := NewL1Retrieval(log, dataSrc, l1Traversal)
frameQueue := NewFrameQueue(log, l1Src)
bank := NewChannelBank(log, cfg, frameQueue, l1Fetcher)
diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go
index 08d1c844eca9..500ea102b076 100644
--- a/op-node/rollup/driver/driver.go
+++ b/op-node/rollup/driver/driver.go
@@ -102,12 +102,12 @@ type AltSync interface {
}
// NewDriver composes an events handler that tracks L1 state, triggers L2 derivation, and optionally sequences new L2 blocks.
-func NewDriver(driverCfg *Config, cfg *rollup.Config, l2 L2Chain, l1 L1Chain, altSync AltSync, network Network, log log.Logger, snapshotLog log.Logger, metrics Metrics) *Driver {
+func NewDriver(driverCfg *Config, cfg *rollup.Config, daCfg *rollup.DAConfig, l2 L2Chain, l1 L1Chain, altSync AltSync, network Network, log log.Logger, snapshotLog log.Logger, metrics Metrics) *Driver {
l1State := NewL1State(log, metrics)
sequencerConfDepth := NewConfDepth(driverCfg.SequencerConfDepth, l1State.L1Head, l1)
findL1Origin := NewL1OriginSelector(log, cfg, sequencerConfDepth)
verifConfDepth := NewConfDepth(driverCfg.VerifierConfDepth, l1State.L1Head, l1)
- derivationPipeline := derive.NewDerivationPipeline(log, cfg, verifConfDepth, l2, metrics)
+ derivationPipeline := derive.NewDerivationPipeline(log, cfg, daCfg, verifConfDepth, l2, metrics)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2)
engine := derivationPipeline
meteredEngine := NewMeteredEngine(cfg, engine, metrics, log)
diff --git a/op-node/service.go b/op-node/service.go
index d1df687dd0ca..88e65d652589 100644
--- a/op-node/service.go
+++ b/op-node/service.go
@@ -57,12 +57,18 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
l2SyncEndpoint := NewL2SyncEndpointConfig(ctx)
+ daCfg, err := rollup.NewDAConfig(flags.DaRPC.Value, flags.NamespaceId.Value)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load da config: %w", err)
+ }
+
cfg := &node.Config{
- L1: l1Endpoint,
- L2: l2Endpoint,
- L2Sync: l2SyncEndpoint,
- Rollup: *rollupConfig,
- Driver: *driverConfig,
+ L1: l1Endpoint,
+ L2: l2Endpoint,
+ L2Sync: l2SyncEndpoint,
+ Rollup: *rollupConfig,
+ DAConfig: *daCfg,
+ Driver: *driverConfig,
RPC: node.RPCConfig{
ListenAddr: ctx.GlobalString(flags.RPCListenAddr.Name),
ListenPort: ctx.GlobalInt(flags.RPCListenPort.Name),
diff --git a/op-program/client/boot.go b/op-program/client/boot.go
index 064aa392c7f5..11d29fb20e31 100644
--- a/op-program/client/boot.go
+++ b/op-program/client/boot.go
@@ -14,6 +14,7 @@ import (
type BootInfo struct {
// TODO(CLI-XXX): The rollup config will be hardcoded. It's configurable for testing purposes.
Rollup *rollup.Config `json:"rollup"`
+ DAConfig *rollup.DAConfig `json:"da_config"`
L2ChainConfig *params.ChainConfig `json:"l2_chain_config"`
L1Head common.Hash `json:"l1_head"`
L2Head common.Hash `json:"l2_head"`
diff --git a/op-program/client/driver/driver.go b/op-program/client/driver/driver.go
index 8372d1996a82..4d98b807a6f4 100644
--- a/op-program/client/driver/driver.go
+++ b/op-program/client/driver/driver.go
@@ -34,8 +34,8 @@ type Driver struct {
targetBlockNum uint64
}
-func NewDriver(logger log.Logger, cfg *rollup.Config, l1Source derive.L1Fetcher, l2Source L2Source, targetBlockNum uint64) *Driver {
- pipeline := derive.NewDerivationPipeline(logger, cfg, l1Source, l2Source, metrics.NoopMetrics)
+func NewDriver(logger log.Logger, cfg *rollup.Config, daCfg *rollup.DAConfig, l1Source derive.L1Fetcher, l2Source L2Source, targetBlockNum uint64) *Driver {
+ pipeline := derive.NewDerivationPipeline(logger, cfg, daCfg, l1Source, l2Source, metrics.NoopMetrics)
pipeline.Reset()
return &Driver{
logger: logger,
diff --git a/op-program/client/program.go b/op-program/client/program.go
index fa14dcca6cbf..0d3a1669f446 100644
--- a/op-program/client/program.go
+++ b/op-program/client/program.go
@@ -52,6 +52,7 @@ func RunProgram(logger log.Logger, bootOracle io.Reader, preimageOracle io.ReadW
return runDerivation(
logger,
bootInfo.Rollup,
+ bootInfo.DAConfig,
bootInfo.L2ChainConfig,
bootInfo.L1Head,
bootInfo.L2Head,
@@ -63,7 +64,7 @@ func RunProgram(logger log.Logger, bootOracle io.Reader, preimageOracle io.ReadW
}
// runDerivation executes the L2 state transition, given a minimal interface to retrieve data.
-func runDerivation(logger log.Logger, cfg *rollup.Config, l2Cfg *params.ChainConfig, l1Head common.Hash, l2Head common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64, l1Oracle l1.Oracle, l2Oracle l2.Oracle) error {
+func runDerivation(logger log.Logger, cfg *rollup.Config, daCfg *rollup.DAConfig, l2Cfg *params.ChainConfig, l1Head common.Hash, l2Head common.Hash, l2Claim common.Hash, l2ClaimBlockNum uint64, l1Oracle l1.Oracle, l2Oracle l2.Oracle) error {
l1Source := l1.NewOracleL1Client(logger, l1Oracle, l1Head)
engineBackend, err := l2.NewOracleBackedL2Chain(logger, l2Oracle, l2Cfg, l2Head)
if err != nil {
@@ -72,7 +73,7 @@ func runDerivation(logger log.Logger, cfg *rollup.Config, l2Cfg *params.ChainCon
l2Source := l2.NewOracleEngine(cfg, logger, engineBackend)
logger.Info("Starting derivation")
- d := cldr.NewDriver(logger, cfg, l1Source, l2Source, l2ClaimBlockNum)
+ d := cldr.NewDriver(logger, cfg, daCfg, l1Source, l2Source, l2ClaimBlockNum)
for {
if err = d.Step(context.Background()); errors.Is(err, io.EOF) {
break
diff --git a/op-proposer/flags/flags.go b/op-proposer/flags/flags.go
index dcd5d9cfd047..b97af0b10865 100644
--- a/op-proposer/flags/flags.go
+++ b/op-proposer/flags/flags.go
@@ -38,6 +38,12 @@ var (
"creating a new batch",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "POLL_INTERVAL"),
}
+ DaRpcFlag = cli.StringFlag{
+ Name: "da-rpc",
+ Usage: "HTTP provider URL for DA node",
+ Required: true,
+ EnvVar: opservice.PrefixEnvVar(envVarPrefix, "DA_RPC"),
+ }
// Optional flags
AllowNonFinalizedFlag = cli.BoolFlag{
Name: "allow-non-finalized",
@@ -53,6 +59,7 @@ var requiredFlags = []cli.Flag{
RollupRpcFlag,
L2OOAddressFlag,
PollIntervalFlag,
+ DaRpcFlag,
}
var optionalFlags = []cli.Flag{
diff --git a/op-proposer/proposer/l2_output_submitter.go b/op-proposer/proposer/l2_output_submitter.go
index 0b6120877612..a977d5a526ca 100644
--- a/op-proposer/proposer/l2_output_submitter.go
+++ b/op-proposer/proposer/l2_output_submitter.go
@@ -328,9 +328,8 @@ func (l *L2OutputSubmitter) sendTransaction(ctx context.Context, output *eth.Out
return err
}
receipt, err := l.txMgr.Send(ctx, txmgr.TxCandidate{
- TxData: data,
- To: &l.l2ooContractAddr,
- GasLimit: 0,
+ TxData: data,
+ To: &l.l2ooContractAddr,
})
if err != nil {
return err
diff --git a/op-service/txmgr/cli.go b/op-service/txmgr/cli.go
index eb4ac7899b21..f05f23c8a1eb 100644
--- a/op-service/txmgr/cli.go
+++ b/op-service/txmgr/cli.go
@@ -31,6 +31,8 @@ const (
TxSendTimeoutFlagName = "txmgr.send-timeout"
TxNotInMempoolTimeoutFlagName = "txmgr.not-in-mempool-timeout"
ReceiptQueryIntervalFlagName = "txmgr.receipt-query-interval"
+ DaRpcFlagName = "da-rpc"
+ NamespaceIdFlagName = "namespace-id"
)
var (
@@ -109,6 +111,12 @@ func CLIFlags(envPrefix string) []cli.Flag {
Value: 12 * time.Second,
EnvVar: opservice.PrefixEnvVar(envPrefix, "TXMGR_RECEIPT_QUERY_INTERVAL"),
},
+ cli.StringFlag{
+ Name: NamespaceIdFlagName,
+ Usage: "Namespace ID of the DA layer",
+ Value: "000008e5f679bf7116cb",
+ EnvVar: opservice.PrefixEnvVar(envPrefix, "NAMESPACE_ID"),
+ },
}, client.CLIFlags(envPrefix)...)
}
@@ -127,6 +135,8 @@ type CLIConfig struct {
NetworkTimeout time.Duration
TxSendTimeout time.Duration
TxNotInMempoolTimeout time.Duration
+ DaRpc string
+ NamespaceId string
}
func (m CLIConfig) Check() error {
@@ -173,6 +183,8 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
NetworkTimeout: ctx.GlobalDuration(NetworkTimeoutFlagName),
TxSendTimeout: ctx.GlobalDuration(TxSendTimeoutFlagName),
TxNotInMempoolTimeout: ctx.GlobalDuration(TxNotInMempoolTimeoutFlagName),
+ DaRpc: ctx.GlobalString(DaRpcFlagName),
+ NamespaceId: ctx.GlobalString(NamespaceIdFlagName),
}
}
@@ -261,6 +273,12 @@ type Config struct {
// confirmation.
SafeAbortNonceTooLowCount uint64
+ // DaRpc is the HTTP provider URL for the Data Availability node.
+ DaRpc string
+
+ // NamespaceId is the id of the namespace of the Data Availability node.
+ NamespaceId string
+
// Signer is used to sign transactions when the gas price is increased.
Signer opcrypto.SignerFn
From common.Address
diff --git a/op-service/txmgr/txmgr.go b/op-service/txmgr/txmgr.go
index 16bd54abe59f..0a8ea8260322 100644
--- a/op-service/txmgr/txmgr.go
+++ b/op-service/txmgr/txmgr.go
@@ -1,7 +1,10 @@
package txmgr
import (
+ "bytes"
"context"
+ "encoding/binary"
+ "encoding/hex"
"errors"
"fmt"
"sync/atomic"
@@ -11,6 +14,7 @@ import (
"sync"
"time"
+ "github.com/celestiaorg/go-cnc"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
@@ -84,6 +88,9 @@ type SimpleTxManager struct {
name string
chainID *big.Int
+ daClient *cnc.Client
+ namespace cnc.Namespace
+
backend ETHBackend
l log.Logger
metr metrics.TxMetricer
@@ -103,14 +110,31 @@ func NewSimpleTxManager(name string, l log.Logger, m metrics.TxMetricer, cfg CLI
return nil, err
}
+ daClient, err := cnc.NewClient(cfg.DaRpc, cnc.WithTimeout(90*time.Second))
+ if err != nil {
+ return nil, err
+ }
+
+ if cfg.NamespaceId == "" {
+ return nil, errors.New("namespace id cannot be blank")
+ }
+ nsBytes, err := hex.DecodeString(cfg.NamespaceId)
+ if err != nil {
+ return nil, err
+ }
+
+ namespace := cnc.MustNewV0(nsBytes)
+
return &SimpleTxManager{
- chainID: conf.ChainID,
- name: name,
- cfg: conf,
- backend: conf.Backend,
- l: l.New("service", name),
- metr: m,
- resetC: make(chan struct{}),
+ chainID: conf.ChainID,
+ name: name,
+ cfg: conf,
+ daClient: daClient,
+ namespace: namespace,
+ backend: conf.Backend,
+ l: l.New("service", name),
+ metr: m,
+ resetC: make(chan struct{}),
}, nil
}
@@ -188,6 +212,45 @@ func (m *SimpleTxManager) send(ctx context.Context, candidate TxCandidate) (*typ
ctx, cancel = context.WithTimeout(ctx, m.cfg.TxSendTimeout)
defer cancel()
}
+ // TODO: this is a hack to route only batcher transactions through celestia
+ // SimpleTxManager is used by both batcher and proposer but since proposer
+ // writes to a smart contract, we overwrite _only_ batcher candidate as the
+ // frame pointer to celestia, while retaining the proposer pathway that
+ // writes the state commitment data to ethereum.
+ if candidate.To.Hex() == "0xfF00000000000000000000000000000000000000" {
+ res, err := m.daClient.SubmitPFB(ctx, m.namespace, candidate.TxData, 70000, 700000)
+ if err != nil {
+ m.l.Warn("unable to publish tx to celestia", "err", err)
+ return nil, err
+ }
+ fmt.Printf("res: %v\n", res)
+
+ height := res.Height
+
+ // FIXME: needs to be tx index / share index?
+ index := uint32(0) // res.Logs[0].MsgIndex
+
+ // DA pointer serialization format
+ // | -------------------------|
+ // | 8 bytes | 4 bytes |
+ // | block height | tx index |
+ // | -------------------------|
+
+ buf := new(bytes.Buffer)
+ err = binary.Write(buf, binary.BigEndian, height)
+ if err != nil {
+ return nil, fmt.Errorf("data pointer block height serialization failed: %w", err)
+ }
+ err = binary.Write(buf, binary.BigEndian, index)
+ if err != nil {
+ return nil, fmt.Errorf("data pointer tx index serialization failed: %w", err)
+ }
+
+ serialized := buf.Bytes()
+ fmt.Printf("TxData: %v\n", serialized)
+ candidate = TxCandidate{TxData: serialized, To: candidate.To, GasLimit: candidate.GasLimit}
+ }
+
tx, err := m.craftTx(ctx, candidate)
if err != nil {
return nil, fmt.Errorf("failed to create the tx: %w", err)
@@ -236,6 +299,7 @@ func (m *SimpleTxManager) craftTx(ctx context.Context, candidate TxCandidate) (*
GasTipCap: gasTipCap,
Data: rawTx.Data,
})
+ m.l.Warn("estimating gas", "candidate", candidate, "gasFeeCap", gasFeeCap, "gasTipCap", gasTipCap, "err", err)
if err != nil {
return nil, fmt.Errorf("failed to estimate gas: %w", err)
}
diff --git a/ops-bedrock/devnet-up.sh b/ops-bedrock/devnet-up.sh
index b055bd3e3a53..63c91656c1d4 100755
--- a/ops-bedrock/devnet-up.sh
+++ b/ops-bedrock/devnet-up.sh
@@ -82,8 +82,8 @@ fi
(
cd ops-bedrock
echo "Bringing up L1..."
- DOCKER_BUILDKIT=1 docker-compose build --progress plain
- docker-compose up -d l1
+ DOCKER_BUILDKIT=1 docker-compose -f docker-compose-devnet.yml build --progress plain
+ docker-compose -f docker-compose-devnet.yml up -d l1
wait_up $L1_URL
)
@@ -91,7 +91,7 @@ fi
(
cd ops-bedrock
echo "Bringing up L2..."
- docker-compose up -d l2
+ docker-compose -f docker-compose-devnet.yml up -d l2
wait_up $L2_URL
)
@@ -102,10 +102,10 @@ L2OO_ADDRESS="0x6900000000000000000000000000000000000000"
cd ops-bedrock
echo "Bringing up devnet..."
L2OO_ADDRESS="$L2OO_ADDRESS" \
- docker-compose up -d op-proposer op-batcher
+ docker-compose -f docker-compose-devnet.yml up -d op-proposer op-batcher
echo "Bringing up stateviz webserver..."
- docker-compose up -d stateviz
+ docker-compose -f docker-compose-devnet.yml up -d stateviz
)
echo "Devnet ready."
diff --git a/ops-bedrock/docker-compose.yml b/ops-bedrock/docker-compose-devnet.yml
similarity index 85%
rename from ops-bedrock/docker-compose.yml
rename to ops-bedrock/docker-compose-devnet.yml
index 0e181208f815..1b0b44f6503b 100644
--- a/ops-bedrock/docker-compose.yml
+++ b/ops-bedrock/docker-compose-devnet.yml
@@ -11,6 +11,19 @@ volumes:
services:
+ da:
+ platform: linux/x86_64
+ image: "ghcr.io/rollkit/local-celestia-devnet:v0.10.0"
+ ports:
+ - "26657:26657"
+ - "26659:26659"
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:26659/header/1"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+ start_period: 10s
+
l1:
build:
context: .
@@ -70,6 +83,8 @@ services:
--metrics.port=7300
--pprof.enabled
--rpc.enable-admin
+ --da-rpc=http://da:26659
+ --namespace-id=000008e5f679bf7116cb
ports:
- "7545:8545"
- "9003:9003"
@@ -105,13 +120,16 @@ services:
OP_PROPOSER_L2OO_ADDRESS: "${L2OO_ADDRESS}"
OP_PROPOSER_PPROF_ENABLED: "true"
OP_PROPOSER_METRICS_ENABLED: "true"
- OP_PROPOSER_ALLOW_NON_FINALIZED: "true"
+ OP_PROPOSER_ALLOW_NON_FINALIZED: "false"
+ OP_PROPOSER_NAMESPACE_ID: "000008e5f679bf7116cb"
+ OP_PROPOSER_DA_RPC: http://da:26659
op-batcher:
depends_on:
- l1
- l2
- op-node
+ - da
build:
context: ../
dockerfile: ./op-batcher/Dockerfile
@@ -119,11 +137,14 @@ services:
- "6061:6060"
- "7301:7300"
- "6545:8545"
+ depends_on:
+ da:
+ condition: service_healthy
environment:
OP_BATCHER_L1_ETH_RPC: http://l1:8545
OP_BATCHER_L2_ETH_RPC: http://l2:8545
OP_BATCHER_ROLLUP_RPC: http://op-node:8545
- OFFLINE_GAS_ESTIMATION: false
+ OFFLINE_GAS_ESTIMATION: null
OP_BATCHER_MAX_CHANNEL_DURATION: 1
OP_BATCHER_MAX_L1_TX_SIZE_BYTES: 120000
OP_BATCHER_TARGET_L1_TX_SIZE_BYTES: 100000
@@ -139,6 +160,8 @@ services:
OP_BATCHER_PPROF_ENABLED: "true"
OP_BATCHER_METRICS_ENABLED: "true"
OP_BATCHER_RPC_ENABLE_ADMIN: "true"
+ OP_BATCHER_NAMESPACE_ID: "000008e5f679bf7116cb"
+ OP_BATCHER_DA_RPC: http://da:26659
stateviz:
build:
diff --git a/ops-bedrock/docker-compose-testnet.yml b/ops-bedrock/docker-compose-testnet.yml
new file mode 100644
index 000000000000..59e57a3f385a
--- /dev/null
+++ b/ops-bedrock/docker-compose-testnet.yml
@@ -0,0 +1,184 @@
+version: '3.4'
+
+# This Compose file is expected to be used with the testnet-up.sh script.
+# The volumes below mount the configs generated by the script into each
+# service.
+
+volumes:
+ l1_data:
+ l2_data:
+ op_log:
+
+
+services:
+ da:
+ container_name: celestia-light-node
+ user: root
+ platform: "${PLATFORM}"
+ image: "ghcr.io/celestiaorg/celestia-node:v0.11.0-rc2"
+ command: celestia light start --core.ip consensus-full-arabica-8.celestia-arabica.com --gateway --gateway.addr da --gateway.port 26659 --p2p.network arabica
+ environment:
+ - NODE_TYPE=light
+ - P2P_NETWORK=arabica
+ volumes:
+ - $HOME/.celestia-light-arabica-8/:/home/celestia/.celestia-light-arabica-8/
+ ports:
+ - "26657:26657"
+ - "26659:26659"
+
+ l1:
+ build:
+ context: .
+ dockerfile: Dockerfile.l1
+ ports:
+ - "8545:8545"
+ - "7060:6060"
+ volumes:
+ - "l1_data:/db"
+ - "${PWD}/../.devnet/genesis-l1.json:/genesis.json"
+ - "${PWD}/test-jwt-secret.txt:/config/test-jwt-secret.txt"
+
+ l2:
+ build:
+ context: .
+ dockerfile: Dockerfile.l2
+ ports:
+ - "9545:8545"
+ - "8060:6060"
+ volumes:
+ - "l2_data:/db"
+ - "${PWD}/../.devnet/genesis-l2.json:/genesis.json"
+ - "${PWD}/test-jwt-secret.txt:/config/test-jwt-secret.txt"
+ entrypoint: # pass the L2 specific flags by overriding the entry-point and adding extra arguments
+ - "/bin/sh"
+ - "/entrypoint.sh"
+ - "--authrpc.jwtsecret=/config/test-jwt-secret.txt"
+
+ op-node:
+ depends_on:
+ - l1
+ - l2
+ build:
+ context: ../
+ dockerfile: ./op-node/Dockerfile
+ command: >
+ op-node
+ --l1=ws://l1:8546
+ --l2=http://l2:8551
+ --l2.jwt-secret=/config/test-jwt-secret.txt
+ --sequencer.enabled
+ --sequencer.l1-confs=0
+ --verifier.l1-confs=0
+ --p2p.sequencer.key=8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
+ --rollup.config=/rollup.json
+ --rpc.addr=0.0.0.0
+ --rpc.port=8545
+ --p2p.listen.ip=0.0.0.0
+ --p2p.listen.tcp=9003
+ --p2p.listen.udp=9003
+ --p2p.scoring.peers=light
+ --p2p.ban.peers=true
+ --snapshotlog.file=/op_log/snapshot.log
+ --p2p.priv.path=/config/p2p-node-key.txt
+ --metrics.enabled
+ --metrics.addr=0.0.0.0
+ --metrics.port=7300
+ --pprof.enabled
+ --rpc.enable-admin
+ --da-rpc=http://da:26659
+ --namespace-id=000008e5f679bf7116cb
+ ports:
+ - "7545:8545"
+ - "9003:9003"
+ - "7300:7300"
+ - "6060:6060"
+ volumes:
+ - "${PWD}/p2p-sequencer-key.txt:/config/p2p-sequencer-key.txt"
+ - "${PWD}/p2p-node-key.txt:/config/p2p-node-key.txt"
+ - "${PWD}/test-jwt-secret.txt:/config/test-jwt-secret.txt"
+ - "${PWD}/../.devnet/rollup.json:/rollup.json"
+ - op_log:/op_log
+
+ op-proposer:
+ depends_on:
+ - l1
+ - l2
+ - op-node
+ build:
+ context: ../
+ dockerfile: ./op-proposer/Dockerfile
+ ports:
+ - "6062:6060"
+ - "7302:7300"
+ environment:
+ OP_PROPOSER_L1_ETH_RPC: http://l1:8545
+ OP_PROPOSER_ROLLUP_RPC: http://op-node:8545
+ OP_PROPOSER_POLL_INTERVAL: 1s
+ OP_PROPOSER_NUM_CONFIRMATIONS: 1
+ OP_PROPOSER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
+ OP_PROPOSER_RESUBMISSION_TIMEOUT: 30s
+ OP_PROPOSER_MNEMONIC: test test test test test test test test test test test junk
+ OP_PROPOSER_L2_OUTPUT_HD_PATH: "m/44'/60'/0'/0/1"
+ OP_PROPOSER_L2OO_ADDRESS: "${L2OO_ADDRESS}"
+ OP_PROPOSER_PPROF_ENABLED: "true"
+ OP_PROPOSER_METRICS_ENABLED: "true"
+ OP_PROPOSER_ALLOW_NON_FINALIZED: "false"
+ OP_PROPOSER_NAMESPACE_ID: "000008e5f679bf7116cb"
+ OP_PROPOSER_DA_RPC: http://da:26659
+ OP_PROPOSER_NETWORK_TIMEOUT: 180s
+
+ op-batcher:
+ depends_on:
+ - l1
+ - l2
+ - op-node
+ - da
+ build:
+ context: ../
+ dockerfile: ./op-batcher/Dockerfile
+ ports:
+ - "6061:6060"
+ - "7301:7300"
+ - "6545:8545"
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://da:26659/header/1"]
+ interval: 5s
+ timeout: 5s
+ retries: 5
+ start_period: 10s
+ environment:
+ OP_BATCHER_L1_ETH_RPC: http://l1:8545
+ OP_BATCHER_L2_ETH_RPC: http://l2:8545
+ OP_BATCHER_ROLLUP_RPC: http://op-node:8545
+ OFFLINE_GAS_ESTIMATION: null
+ OP_BATCHER_MAX_CHANNEL_DURATION: 1
+ OP_BATCHER_MAX_L1_TX_SIZE_BYTES: 120000
+ OP_BATCHER_TARGET_L1_TX_SIZE_BYTES: 100000
+ OP_BATCHER_TARGET_NUM_FRAMES: 1
+ OP_BATCHER_APPROX_COMPR_RATIO: 0.4
+ OP_BATCHER_SUB_SAFETY_MARGIN: 4 # SWS is 15, ChannelTimeout is 40
+ OP_BATCHER_POLL_INTERVAL: 1s
+ OP_BATCHER_NUM_CONFIRMATIONS: 1
+ OP_BATCHER_SAFE_ABORT_NONCE_TOO_LOW_COUNT: 3
+ OP_BATCHER_RESUBMISSION_TIMEOUT: 30s
+ OP_BATCHER_MNEMONIC: test test test test test test test test test test test junk
+ OP_BATCHER_SEQUENCER_HD_PATH: "m/44'/60'/0'/0/2"
+ OP_BATCHER_PPROF_ENABLED: "true"
+ OP_BATCHER_METRICS_ENABLED: "true"
+ OP_BATCHER_RPC_ENABLE_ADMIN: "true"
+ OP_BATCHER_NAMESPACE_ID: "000008e5f679bf7116cb"
+ OP_BATCHER_DA_RPC: http://da:26659
+
+ stateviz:
+ build:
+ context: ../
+ dockerfile: ./ops-bedrock/Dockerfile.stateviz
+ command:
+ - stateviz
+ - -addr=0.0.0.0:8080
+ - -snapshot=/op_log/snapshot.log
+ - -refresh=10s
+ ports:
+ - "9090:8080"
+ volumes:
+ - op_log:/op_log:ro
diff --git a/ops-bedrock/testnet-up.sh b/ops-bedrock/testnet-up.sh
new file mode 100755
index 000000000000..d1bd52fbbd52
--- /dev/null
+++ b/ops-bedrock/testnet-up.sh
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+
+# This script starts a local devnet using Docker Compose. We have to use
+# this more complicated Bash script rather than Compose's native orchestration
+# tooling because we need to start each service in a specific order, and specify
+# their configuration along the way. The order is:
+#
+# 1. Start L1.
+# 2. Compile contracts.
+# 3. Deploy the contracts to L1 if necessary.
+# 4. Start L2, inserting the compiled contract artifacts into the genesis.
+# 5. Get the genesis hashes and timestamps from L1/L2.
+# 6. Generate the rollup driver's config using the genesis hashes and the
+# timestamps recovered in step 4 as well as the address of the OptimismPortal
+# contract deployed in step 3.
+# 7. Start the rollup driver.
+# 8. Start the L2 output submitter.
+#
+# The timestamps are critically important here, since the rollup driver will fill in
+# empty blocks if the tip of L1 lags behind the current timestamp. This can lead to
+# a perceived infinite loop. To get around this, we set the timestamp to the current
+# time in this script.
+#
+# This script is safe to run multiple times. It stores state in `.devnet`, and
+# contracts-bedrock/deployments/devnetL1.
+#
+# Don't run this script directly. Run it using the makefile, e.g. `make testnet-up`.
+# To clean up your devnet, run `make testnet-clean`.
+
+set -eu
+
+L1_URL="http://localhost:8545"
+L2_URL="http://localhost:9545"
+
+OP_NODE="$PWD/op-node"
+CONTRACTS_BEDROCK="$PWD/packages/contracts-bedrock"
+NETWORK=devnetL1
+DEVNET="$PWD/.devnet"
+
+# Helper method that waits for a given URL to be up. Can't use
+# cURL's built-in retry logic because connection reset errors
+# are ignored unless you're using a very recent version of cURL
+function wait_up {
+ echo -n "Waiting for $1 to come up..."
+ i=0
+ until curl -s -f -o /dev/null "$1"
+ do
+ echo -n .
+ sleep 0.25
+
+ ((i=i+1))
+ if [ "$i" -eq 300 ]; then
+ echo " Timeout!" >&2
+ exit 1
+ fi
+ done
+ echo "Done!"
+}
+
+mkdir -p ./.devnet
+
+# Regenerate the L1 genesis file if necessary. The existence of the genesis
+# file is used to determine if we need to recreate the devnet's state folder.
+if [ ! -f "$DEVNET/done" ]; then
+ echo "Regenerating genesis files"
+
+ TIMESTAMP=$(date +%s | xargs printf '0x%x')
+ cat "$CONTRACTS_BEDROCK/deploy-config/devnetL1.json" | jq -r ".l1GenesisBlockTimestamp = \"$TIMESTAMP\"" > /tmp/bedrock-devnet-deploy-config.json
+
+ (
+ cd "$OP_NODE"
+ go run cmd/main.go genesis devnet \
+ --deploy-config /tmp/bedrock-devnet-deploy-config.json \
+ --outfile.l1 $DEVNET/genesis-l1.json \
+ --outfile.l2 $DEVNET/genesis-l2.json \
+ --outfile.rollup $DEVNET/rollup.json
+ touch "$DEVNET/done"
+ )
+fi
+
+# Bring up L1.
+(
+ cd ops-bedrock
+ echo "Bringing up L1..."
+ DOCKER_BUILDKIT=1 docker-compose -f docker-compose-testnet.yml build --progress plain
+ docker-compose -f docker-compose-testnet.yml up -d l1
+ wait_up $L1_URL
+)
+
+# Bring up L2.
+(
+ cd ops-bedrock
+ echo "Bringing up L2..."
+ docker-compose -f docker-compose-testnet.yml up -d l2
+ wait_up $L2_URL
+)
+
+L2OO_ADDRESS="0x6900000000000000000000000000000000000000"
+
+# Bring up everything else.
+(
+ cd ops-bedrock
+ echo "Bringing up devnet..."
+ L2OO_ADDRESS="$L2OO_ADDRESS" \
+ docker-compose -f docker-compose-testnet.yml up -d op-proposer op-batcher
+
+ echo "Bringing up stateviz webserver..."
+ docker-compose -f docker-compose-testnet.yml up -d stateviz
+)
+
+echo "Devnet ready."
diff --git a/packages/contracts-bedrock/deploy-config/devnetL1.json b/packages/contracts-bedrock/deploy-config/devnetL1.json
index dd6c426e6ca6..aec479c85483 100644
--- a/packages/contracts-bedrock/deploy-config/devnetL1.json
+++ b/packages/contracts-bedrock/deploy-config/devnetL1.json
@@ -2,18 +2,18 @@
"l1ChainID": 900,
"l2ChainID": 901,
"l2BlockTime": 2,
- "maxSequencerDrift": 300,
- "sequencerWindowSize": 200,
- "channelTimeout": 120,
+ "maxSequencerDrift": 600,
+ "sequencerWindowSize": 3600,
+ "channelTimeout": 300,
"p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
"batchInboxAddress": "0xff00000000000000000000000000000000000000",
"batchSenderAddress": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
- "l2OutputOracleSubmissionInterval": 20,
+ "l2OutputOracleSubmissionInterval": 120,
"l2OutputOracleStartingTimestamp": -1,
"l2OutputOracleProposer": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"l2OutputOracleChallenger": "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65",
"l2GenesisBlockGasLimit": "0x1c9c380",
- "l1BlockTime": 3,
+ "l1BlockTime": 15,
"cliqueSignerAddress": "0xca062b0fd91172d89bcd4bb084ac4e21972cc467",
"baseFeeVaultRecipient": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"l1FeeVaultRecipient": "0x71bE63f3384f5fb98995898A86B02Fb2426c5788",
@@ -22,7 +22,7 @@
"finalSystemOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"portalGuardian": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"controller": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
- "finalizationPeriodSeconds": 2,
+ "finalizationPeriodSeconds": 12,
"deploymentWaitConfirmations": 1,
"fundDevAccounts": true,
"l2GenesisBlockBaseFeePerGas": "0x3B9ACA00",
diff --git a/packages/contracts-bedrock/tasks/deposits.ts b/packages/contracts-bedrock/tasks/deposits.ts
index cf07b54293b9..d0f0f0eb91fb 100644
--- a/packages/contracts-bedrock/tasks/deposits.ts
+++ b/packages/contracts-bedrock/tasks/deposits.ts
@@ -39,11 +39,11 @@ task('deposit', 'Deposits funds onto L2.')
)
.setAction(async (args, hre) => {
const { l1ProviderUrl, l2ProviderUrl, to, amountEth, privateKey } = args
- const proxy = await hre.deployments.get('OptimismPortalProxy')
+ // const proxy = await hre.deployments.get('OptimismPortalProxy')
const OptimismPortal = await hre.ethers.getContractAt(
'OptimismPortal',
- proxy.address
+ '0x6900000000000000000000000000000000000001'
)
const l1Provider = new providers.JsonRpcProvider(l1ProviderUrl)
diff --git a/yarn.lock b/yarn.lock
index f684f3b83a1b..85172cf87a0b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2297,9 +2297,9 @@
ts-interface-checker "^0.1.9"
"@grpc/grpc-js@^1.3.6":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.0.tgz#ebfbeff2b76e2991f2831e46cad27fa573396555"
- integrity sha512-ySMTXQuMvvswoobvN+0LsaPf7ITO2JVfJmHxQKI4cGehNrrUms+n81BlHEX7Hl/LExji6XE3fnI9U04GSkRruA==
+ version "1.8.17"
+ resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.17.tgz#a3a2f826fc033eae7d2f5ee41e0ab39cee948838"
+ integrity sha512-DGuSbtMFbaRsyffMf+VEkVu8HkSXEUfO3UyGJNtqxW9ABdtTIA+2UXAJpwbJS+xfQxuwqLUeELmL6FuZkOqPxw==
dependencies:
"@grpc/proto-loader" "^0.7.0"
"@types/node" ">=12.12.47"