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 +

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 +

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 @@ +Celestia-logo-color-black \ 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"