Commit 53f12201 authored by coolhill's avatar coolhill Committed by GitHub

Merge branch 'ethereum-optimism:develop' into increase-coverage-issue

parents 9c635da8 fde2c76a
---
'@eth-optimism/data-transport-layer': patch
---
Smaller filter query for searching for L1 start height. This number should be configured so that the search does not need to happen because using a smaller filter will cause it to take too long.
---
'@eth-optimism/gas-oracle': patch
'@eth-optimism/contracts': patch
'@eth-optimism/data-transport-layer': patch
---
String update to change the system name from OE to Optimism
---
'@eth-optimism/message-relayer': patch
---
Fix docker build
---
'@eth-optimism/l2geth': patch
---
expose ErrNonceTooHigh from miner
---
'@eth-optimism/contracts': patch
---
Remove legacy bin/deploy.ts script
version: 2.1
orbs:
gcp-gke: circleci/gcp-gke@1.3.0
slack: circleci/slack@4.5.1
slack-fail-post-step: &slack-fail-post-step
post-steps:
- slack/notify:
channel: $SLACK_DEFAULT_CHANNEL
event: fail
custom: |
{
"text": "",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "🔴 Nightly build failed!"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Job"
},
"url": "${CIRCLE_BUILD_URL}"
}
]
}
]
}
commands:
build-dockerfile:
parameters:
image-name:
description: Image name
type: string
target:
description: Dockerfile target
type: string
default: ""
dockerfile:
description: Dockerfile to use
type: string
steps:
- checkout
- setup_remote_docker:
version: 19.03.13
- run:
name: Build
command: |
echo -n "$STACKMAN_REPO_AUTH" | docker login -u _json_key --password-stdin https://us-east4-docker.pkg.dev
docker build -t "$STACKMAN_REPO/<<parameters.image-name>>:nightly" -f <<parameters.dockerfile>> <<#parameters.target>>--target <<parameters.target>><</parameters.target>> .
docker push "$STACKMAN_REPO/<<parameters.image-name>>:nightly"
jobs:
build-dtl:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: data-transport-layer
target: data-transport-layer
dockerfile: ./ops/docker/Dockerfile.packages
build-batch-submitter:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: batch-submitter
target: batch-submitter
dockerfile: ./ops/docker/Dockerfile.packages
build-go-batch-submitter:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: go-batch-submitter
dockerfile: ./ops/docker/Dockerfile.batch-submitter-service
build-deployer:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: deployer
target: deployer
dockerfile: ./ops/docker/Dockerfile.packages
build-l2geth:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: l2geth
dockerfile: ./ops/docker/Dockerfile.geth
build-gas-oracle:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: gas-oracle
dockerfile: ./ops/docker/Dockerfile.gas-oracle
build-integration-tests:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: integration-tests
target: integration-tests
dockerfile: ./ops/docker/Dockerfile.packages
build-proxyd:
docker:
- image: cimg/base:2021.04
steps:
- build-dockerfile:
image-name: proxyd
dockerfile: ./go/proxyd/Dockerfile
deploy-nightly:
docker:
- image: cimg/base:2021.04
steps:
- gcp-gke/install
- gcp-gke/update-kubeconfig-with-credentials:
cluster: $STACKMAN_CLUSTER
gcloud-service-key: STACKMAN_SERVICE_KEY
google-compute-region: STACKMAN_COMPUTE_REGION
google-compute-zone: STACKMAN_COMPUTE_ZONE
google-project-id: STACKMAN_PROJECT_ID
install-kubectl: yes
perform-login: yes
- run:
name: Deploy
command: |
echo "Current nightly pods:"
kubectl get pods --namespace nightly
echo "Redeploying pods:"
kubectl rollout restart statefulset nightly-sequencer --namespace nightly
kubectl rollout restart statefulset nightly-go-batch-submitter --namespace nightly
kubectl rollout restart statefulset nightly-dtl --namespace nightly
kubectl rollout restart deployment nightly-gas-oracle --namespace nightly
kubectl rollout restart deployment edge-proxyd --namespace nightly
notify:
docker:
- image: cimg/base:2021.04
steps:
- run:
name: Success
command: |
echo "Dummy job."
workflows:
nightly:
triggers:
- schedule:
cron: "0 0 * * * "
filters:
branches:
only:
- develop
jobs:
- build-dtl:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-batch-submitter:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-deployer:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-l2geth:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-gas-oracle:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-integration-tests:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-go-batch-submitter:
context:
- optimism
- slack
<<: *slack-fail-post-step
- build-proxyd:
context:
- optimism
- slack
<<: *slack-fail-post-step
- deploy-nightly:
context:
- optimism
- slack
<<: *slack-fail-post-step
requires:
- build-dtl
- build-batch-submitter
- build-go-batch-submitter
- build-deployer
- build-l2geth
- build-gas-oracle
- build-integration-tests
- build-proxyd
- notify:
context: slack
requires:
- deploy-nightly
post-steps:
- slack/notify:
custom: |
{
"text": "",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "✅ Nightly successfully deployed."
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "View Job"
},
"url": "${CIRCLE_BUILD_URL}"
}
]
}
]
}
event: always
\ No newline at end of file
...@@ -28,6 +28,7 @@ jobs: ...@@ -28,6 +28,7 @@ jobs:
proxyd: ${{ steps.packages.outputs.proxyd }} proxyd: ${{ steps.packages.outputs.proxyd }}
rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }} rpc-proxy : ${{ steps.packages.outputs.rpc-proxy }}
op-exporter : ${{ steps.packages.outputs.op-exporter }} op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
steps: steps:
- name: Check out source code - name: Check out source code
...@@ -443,6 +444,43 @@ jobs: ...@@ -443,6 +444,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }} GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }} GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
l2geth-exporter:
name: Publish l2geth-exporter Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish
if: needs.canary-publish.outputs.l2geth-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/l2geth-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.l2geth-exporter
push: true
tags: ethereumoptimism/l2geth-exporter:${{ needs.canary-publish.outputs.l2geth-exporter }}
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
rpc-proxy: rpc-proxy:
name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }} name: Publish rpc-proxy Version ${{ needs.canary-publish.outputs.canary-docker-tag }}
needs: canary-publish needs: canary-publish
......
...@@ -24,6 +24,7 @@ jobs: ...@@ -24,6 +24,7 @@ jobs:
rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }} rpc-proxy: ${{ steps.packages.outputs.rpc-proxy }}
hardhat-node: ${{ steps.packages.outputs.hardhat-node }} hardhat-node: ${{ steps.packages.outputs.hardhat-node }}
op-exporter : ${{ steps.packages.outputs.op-exporter }} op-exporter : ${{ steps.packages.outputs.op-exporter }}
l2geth-exporter : ${{ steps.packages.outputs.l2geth-exporter }}
steps: steps:
- name: Checkout Repo - name: Checkout Repo
...@@ -196,6 +197,43 @@ jobs: ...@@ -196,6 +197,43 @@ jobs:
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }} GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }} GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
l2geth-exporter:
name: Publish l2geth-exporter Version ${{ needs.release.outputs.l2geth-exporter}}
needs: release
if: needs.release.outputs.l2geth-exporter != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Set build args
id: build_args
run: |
echo ::set-output name=GITDATE::"$(date +%d-%m-%Y)"
echo ::set-output name=GITVERSION::$(jq -r .version ./go/l2geth-exporter/package.json)
echo ::set-output name=GITCOMMIT::"$GITHUB_SHA"
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.l2geth-exporter
push: true
tags: ethereumoptimism/l2geth-exporter:${{ needs.release.outputs.l2geth-exporter }},ethereumoptimism/l2geth-exporter:latest
build-args: |
GITDATE=${{ steps.build_args.outputs.GITDATE }}
GITCOMMIT=${{ steps.build_args.outputs.GITCOMMIT }}
GITVERSION=${{ steps.build_args.outputs.GITVERSION }}
op-exporter: op-exporter:
name: Publish op-exporter Version ${{ needs.release.outputs.op-exporter}} name: Publish op-exporter Version ${{ needs.release.outputs.op-exporter}}
needs: release needs: release
......
...@@ -131,6 +131,13 @@ jobs: ...@@ -131,6 +131,13 @@ jobs:
fail_ci_if_error: false fail_ci_if_error: false
verbose: true verbose: true
flags: message-relayer flags: message-relayer
- uses: codecov/codecov-action@v1
with:
files: ./packages/sdk/coverage.json
fail_ci_if_error: false
verbose: true
flags: sdk
lint: lint:
name: Linting name: Linting
runs-on: ubuntu-latest runs-on: ubuntu-latest
......
...@@ -98,7 +98,7 @@ Use the above commands to recompile the packages. ...@@ -98,7 +98,7 @@ Use the above commands to recompile the packages.
### Building the rest of the system ### Building the rest of the system
If you want to run an Optimistic Ethereum node OR **if you want to run the integration tests**, you'll need to build the rest of the system. If you want to run an Optimism node OR **if you want to run the integration tests**, you'll need to build the rest of the system.
```bash ```bash
cd ops cd ops
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
## TL;DR ## TL;DR
This is the primary place where [Optimism](https://optimism.io) works on stuff related to [Optimistic Ethereum](https://optimistic.etherscan.io/). This is where [Optimism](https://optimism.io) gets built.
## Documentation ## Documentation
...@@ -31,16 +31,16 @@ Then check out our list of [good first issues](https://github.com/ethereum-optim ...@@ -31,16 +31,16 @@ Then check out our list of [good first issues](https://github.com/ethereum-optim
<pre> <pre>
root root
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/contracts">contracts</a>: L1 and L2 smart contracts for Optimistic Ethereum │ ├── <a href="./packages/contracts">contracts</a>: L1 and L2 smart contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimistic Ethereum easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/data-transport-layer">data-transport-layer</a>: Service for indexing Optimistic Ethereum-related L1 data │ ├── <a href="./packages/data-transport-layer">data-transport-layer</a>: Service for indexing Optimism-related L1 data
│ ├── <a href="./packages/batch-submitter">batch-submitter</a>: Service for submitting batches of transactions and results to L1 │ ├── <a href="./packages/batch-submitter">batch-submitter</a>: Service for submitting batches of transactions and results to L1
│ ├── <a href="./packages/message-relayer">message-relayer</a>: Tool for automatically relaying L1<>L2 messages in development │ ├── <a href="./packages/message-relayer">message-relayer</a>: Tool for automatically relaying L1<>L2 messages in development
│ └── <a href="./packages/replica-healthcheck">replica-healthcheck</a>: Service for monitoring the health of a replica node │ └── <a href="./packages/replica-healthcheck">replica-healthcheck</a>: Service for monitoring the health of a replica node
├── <a href="./l2geth">l2geth</a>: Optimistic Ethereum client software, a fork of <a href="https://github.com/ethereum/go-ethereum/tree/v1.9.10">geth v1.9.10</a> ├── <a href="./l2geth">l2geth</a>: Optimism client software, a fork of <a href="https://github.com/ethereum/go-ethereum/tree/v1.9.10">geth v1.9.10</a>
├── <a href="./integration-tests">integration-tests</a>: Various integration tests for an Optimistic Ethereum network ├── <a href="./integration-tests">integration-tests</a>: Various integration tests for the Optimism network
└── <a href="./ops">ops</a>: Tools for running Optimistic Ethereum nodes and networks └── <a href="./ops">ops</a>: Tools for running Optimism nodes and networks
</pre> </pre>
## Branching Model and Releases ## Branching Model and Releases
...@@ -64,7 +64,7 @@ Please read the linked post if you're planning to make frequent PRs into this re ...@@ -64,7 +64,7 @@ Please read the linked post if you're planning to make frequent PRs into this re
The `master` branch contains the code for our latest "stable" releases. The `master` branch contains the code for our latest "stable" releases.
Updates from `master` always come from the `develop` branch. Updates from `master` always come from the `develop` branch.
We only ever update the `master` branch when we intend to deploy code within the `develop` to the Optimistic Ethereum mainnet. We only ever update the `master` branch when we intend to deploy code within the `develop` to the Optimism mainnet.
Our update process takes the form of a PR merging the `develop` branch into the `master` branch. Our update process takes the form of a PR merging the `develop` branch into the `master` branch.
### The `develop` branch ### The `develop` branch
......
# @eth-optimism/batch-submitter-service
## 0.0.2
### Patch Changes
- d6e0de5a: Fix metrics server
...@@ -119,8 +119,6 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) { ...@@ -119,8 +119,6 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
log.Root().SetHandler(log.LvlFilterHandler(logLevel, logHandler)) log.Root().SetHandler(log.LvlFilterHandler(logLevel, logHandler))
log.Info("Config", "config", fmt.Sprintf("%#v", cfg))
// Parse sequencer private key and CTC contract address. // Parse sequencer private key and CTC contract address.
sequencerPrivKey, ctcAddress, err := parseWalletPrivKeyAndContractAddr( sequencerPrivKey, ctcAddress, err := parseWalletPrivKeyAndContractAddr(
"Sequencer", cfg.Mnemonic, cfg.SequencerHDPath, "Sequencer", cfg.Mnemonic, cfg.SequencerHDPath,
...@@ -171,7 +169,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) { ...@@ -171,7 +169,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
var batchTxService *Service var batchTxService *Service
if cfg.RunTxBatchSubmitter { if cfg.RunTxBatchSubmitter {
batchTxDriver, err := sequencer.NewDriver(sequencer.Config{ batchTxDriver, err := sequencer.NewDriver(sequencer.Config{
Name: "SEQUENCER", Name: "Sequencer",
L1Client: l1Client, L1Client: l1Client,
L2Client: l2Client, L2Client: l2Client,
BlockOffset: cfg.BlockOffset, BlockOffset: cfg.BlockOffset,
...@@ -196,7 +194,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) { ...@@ -196,7 +194,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
var batchStateService *Service var batchStateService *Service
if cfg.RunStateBatchSubmitter { if cfg.RunStateBatchSubmitter {
batchStateDriver, err := proposer.NewDriver(proposer.Config{ batchStateDriver, err := proposer.NewDriver(proposer.Config{
Name: "PROPOSER", Name: "Proposer",
L1Client: l1Client, L1Client: l1Client,
L2Client: l2Client, L2Client: l2Client,
BlockOffset: cfg.BlockOffset, BlockOffset: cfg.BlockOffset,
...@@ -295,7 +293,7 @@ func parseWalletPrivKeyAndContractAddr( ...@@ -295,7 +293,7 @@ func parseWalletPrivKeyAndContractAddr(
// NOTE: This method MUST be run as a goroutine. // NOTE: This method MUST be run as a goroutine.
func runMetricsServer(hostname string, port uint64) { func runMetricsServer(hostname string, port uint64) {
metricsPortStr := strconv.FormatUint(port, 10) metricsPortStr := strconv.FormatUint(port, 10)
metricsAddr := fmt.Sprintf("%s: %s", hostname, metricsPortStr) metricsAddr := fmt.Sprintf("%s:%s", hostname, metricsPortStr)
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", promhttp.Handler())
_ = http.ListenAndServe(metricsAddr, nil) _ = http.ListenAndServe(metricsAddr, nil)
......
...@@ -5,9 +5,11 @@ import ( ...@@ -5,9 +5,11 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
"math/big" "math/big"
"time"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc" "github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/scc" "github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/scc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
l2types "github.com/ethereum-optimism/optimism/l2geth/core/types" l2types "github.com/ethereum-optimism/optimism/l2geth/core/types"
l2ethclient "github.com/ethereum-optimism/optimism/l2geth/ethclient" l2ethclient "github.com/ethereum-optimism/optimism/l2geth/ethclient"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
...@@ -36,6 +38,7 @@ type Driver struct { ...@@ -36,6 +38,7 @@ type Driver struct {
sccContract *scc.StateCommitmentChain sccContract *scc.StateCommitmentChain
ctcContract *ctc.CanonicalTransactionChain ctcContract *ctc.CanonicalTransactionChain
walletAddr common.Address walletAddr common.Address
metrics *metrics.Metrics
} }
func NewDriver(cfg Config) (*Driver, error) { func NewDriver(cfg Config) (*Driver, error) {
...@@ -60,6 +63,7 @@ func NewDriver(cfg Config) (*Driver, error) { ...@@ -60,6 +63,7 @@ func NewDriver(cfg Config) (*Driver, error) {
sccContract: sccContract, sccContract: sccContract,
ctcContract: ctcContract, ctcContract: ctcContract,
walletAddr: walletAddr, walletAddr: walletAddr,
metrics: metrics.NewMetrics(cfg.Name),
}, nil }, nil
} }
...@@ -73,6 +77,11 @@ func (d *Driver) WalletAddr() common.Address { ...@@ -73,6 +77,11 @@ func (d *Driver) WalletAddr() common.Address {
return d.walletAddr return d.walletAddr
} }
// Metrics returns the subservice telemetry object.
func (d *Driver) Metrics() *metrics.Metrics {
return d.metrics
}
// GetBatchBlockRange returns the start and end L2 block heights that need to be // GetBatchBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned // processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed. // values are identical nothing needs to be processed.
...@@ -121,6 +130,8 @@ func (d *Driver) SubmitBatchTx( ...@@ -121,6 +130,8 @@ func (d *Driver) SubmitBatchTx(
ctx context.Context, ctx context.Context,
start, end, nonce, gasPrice *big.Int) (*types.Transaction, error) { start, end, nonce, gasPrice *big.Int) (*types.Transaction, error) {
batchTxBuildStart := time.Now()
var blocks []*l2types.Block var blocks []*l2types.Block
for i := new(big.Int).Set(start); i.Cmp(end) < 0; i.Add(i, bigOne) { for i := new(big.Int).Set(start); i.Cmp(end) < 0; i.Add(i, bigOne) {
block, err := d.cfg.L2Client.BlockByNumber(ctx, i) block, err := d.cfg.L2Client.BlockByNumber(ctx, i)
...@@ -139,6 +150,10 @@ func (d *Driver) SubmitBatchTx( ...@@ -139,6 +150,10 @@ func (d *Driver) SubmitBatchTx(
stateRoots = append(stateRoots, block.Root()) stateRoots = append(stateRoots, block.Root())
} }
batchTxBuildTime := float64(time.Since(batchTxBuildStart) / time.Millisecond)
d.metrics.BatchTxBuildTime.Set(batchTxBuildTime)
d.metrics.NumTxPerBatch.Observe(float64(len(blocks)))
opts, err := bind.NewKeyedTransactorWithChainID( opts, err := bind.NewKeyedTransactorWithChainID(
d.cfg.PrivKey, d.cfg.ChainID, d.cfg.PrivKey, d.cfg.ChainID,
) )
......
...@@ -7,8 +7,10 @@ import ( ...@@ -7,8 +7,10 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"strings" "strings"
"time"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc" "github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
l2types "github.com/ethereum-optimism/optimism/l2geth/core/types" l2types "github.com/ethereum-optimism/optimism/l2geth/core/types"
l2ethclient "github.com/ethereum-optimism/optimism/l2geth/ethclient" l2ethclient "github.com/ethereum-optimism/optimism/l2geth/ethclient"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
...@@ -43,6 +45,7 @@ type Driver struct { ...@@ -43,6 +45,7 @@ type Driver struct {
rawCtcContract *bind.BoundContract rawCtcContract *bind.BoundContract
walletAddr common.Address walletAddr common.Address
ctcABI *abi.ABI ctcABI *abi.ABI
metrics *metrics.Metrics
} }
func NewDriver(cfg Config) (*Driver, error) { func NewDriver(cfg Config) (*Driver, error) {
...@@ -78,6 +81,7 @@ func NewDriver(cfg Config) (*Driver, error) { ...@@ -78,6 +81,7 @@ func NewDriver(cfg Config) (*Driver, error) {
rawCtcContract: rawCtcContract, rawCtcContract: rawCtcContract,
walletAddr: walletAddr, walletAddr: walletAddr,
ctcABI: ctcABI, ctcABI: ctcABI,
metrics: metrics.NewMetrics(cfg.Name),
}, nil }, nil
} }
...@@ -91,6 +95,11 @@ func (d *Driver) WalletAddr() common.Address { ...@@ -91,6 +95,11 @@ func (d *Driver) WalletAddr() common.Address {
return d.walletAddr return d.walletAddr
} }
// Metrics returns the subservice telemetry object.
func (d *Driver) Metrics() *metrics.Metrics {
return d.metrics
}
// GetBatchBlockRange returns the start and end L2 block heights that need to be // GetBatchBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned // processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed. // values are identical nothing needs to be processed.
...@@ -136,6 +145,8 @@ func (d *Driver) SubmitBatchTx( ...@@ -136,6 +145,8 @@ func (d *Driver) SubmitBatchTx(
log.Info(name+" submitting batch tx", "start", start, "end", end, log.Info(name+" submitting batch tx", "start", start, "end", end,
"gasPrice", gasPrice) "gasPrice", gasPrice)
batchTxBuildStart := time.Now()
var blocks []*l2types.Block var blocks []*l2types.Block
for i := new(big.Int).Set(start); i.Cmp(end) < 0; i.Add(i, bigOne) { for i := new(big.Int).Set(start); i.Cmp(end) < 0; i.Add(i, bigOne) {
block, err := d.cfg.L2Client.BlockByNumber(ctx, i) block, err := d.cfg.L2Client.BlockByNumber(ctx, i)
...@@ -176,6 +187,11 @@ func (d *Driver) SubmitBatchTx( ...@@ -176,6 +187,11 @@ func (d *Driver) SubmitBatchTx(
panic("call data too large") panic("call data too large")
} }
// Record the batch_tx_build_time.
batchTxBuildTime := float64(time.Since(batchTxBuildStart) / time.Millisecond)
d.metrics.BatchTxBuildTime.Set(batchTxBuildTime)
d.metrics.NumTxPerBatch.Observe(float64(len(blocks)))
log.Info(name+" batch call data", "data", hex.EncodeToString(batchCallData)) log.Info(name+" batch call data", "data", hex.EncodeToString(batchCallData))
opts, err := bind.NewKeyedTransactorWithChainID( opts, err := bind.NewKeyedTransactorWithChainID(
......
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
type Metrics struct {
// ETHBalance tracks the amount of ETH in the submitter's account.
ETHBalance prometheus.Gauge
// BatchSizeInBytes tracks the size of batch submission transactions.
BatchSizeInBytes prometheus.Histogram
// NumTxPerBatch tracks the number of L2 transactions in each batch
// submission.
NumTxPerBatch prometheus.Histogram
// SubmissionGasUsed tracks the amount of gas used to submit each batch.
SubmissionGasUsed prometheus.Histogram
// BatchsSubmitted tracks the total number of successful batch submissions.
BatchesSubmitted prometheus.Counter
// FailedSubmissions tracks the total number of failed batch submissions.
FailedSubmissions prometheus.Counter
// BatchTxBuildTime tracks the duration it takes to construct a batch
// transaction.
BatchTxBuildTime prometheus.Gauge
// BatchConfirmationTime tracks the duration it takes to confirm a batch
// transaction.
BatchConfirmationTime prometheus.Gauge
}
func NewMetrics(subsystem string) *Metrics {
return &Metrics{
ETHBalance: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_submitter_eth_balance",
Help: "ETH balance of the batch submitter",
Subsystem: subsystem,
}),
BatchSizeInBytes: promauto.NewHistogram(prometheus.HistogramOpts{
Name: "batch_submitter_batch_size_in_bytes",
Help: "Size of batches in bytes",
Subsystem: subsystem,
}),
NumTxPerBatch: promauto.NewHistogram(prometheus.HistogramOpts{
Name: "batch_submitter_num_txs_per_batch",
Help: "Number of transaction in each batch",
Subsystem: subsystem,
}),
SubmissionGasUsed: promauto.NewHistogram(prometheus.HistogramOpts{
Name: "batch_submitter_submission_gas_used",
Help: "Gas used to submit each batch",
Subsystem: subsystem,
}),
BatchesSubmitted: promauto.NewCounter(prometheus.CounterOpts{
Name: "batch_submitter_batches_submitted",
Help: "Count of batches submitted",
Subsystem: subsystem,
}),
FailedSubmissions: promauto.NewCounter(prometheus.CounterOpts{
Name: "batch_submitter_failed_submissions",
Help: "Count of failed batch submissions",
Subsystem: subsystem,
}),
BatchTxBuildTime: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_submitter_batch_tx_build_time",
Help: "Time to construct batch transactions",
Subsystem: subsystem,
}),
BatchConfirmationTime: promauto.NewGauge(prometheus.GaugeOpts{
Name: "batch_submitter_batch_confirmation_time",
Help: "Time to confirm batch transactions",
Subsystem: subsystem,
}),
}
}
{ {
"name": "@eth-optimism/batch-submitter-service", "name": "@eth-optimism/batch-submitter-service",
"version": "0.0.1", "version": "0.0.2",
"private": true, "private": true,
"devDependencies": {} "devDependencies": {}
} }
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr" "github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -13,6 +14,11 @@ import ( ...@@ -13,6 +14,11 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
var (
// weiToGwei is the conversion rate from wei to gwei.
weiToGwei = new(big.Float).SetFloat64(1e-18)
)
// Driver is an interface for creating and submitting batch transactions for a // Driver is an interface for creating and submitting batch transactions for a
// specific contract. // specific contract.
type Driver interface { type Driver interface {
...@@ -23,6 +29,9 @@ type Driver interface { ...@@ -23,6 +29,9 @@ type Driver interface {
// fees. // fees.
WalletAddr() common.Address WalletAddr() common.Address
// Metrics returns the subservice telemetry object.
Metrics() *metrics.Metrics
// GetBatchBlockRange returns the start and end L2 block heights that // GetBatchBlockRange returns the start and end L2 block heights that
// need to be processed. Note that the end value is *exclusive*, // need to be processed. Note that the end value is *exclusive*,
// therefore if the returned values are identical nothing needs to be // therefore if the returned values are identical nothing needs to be
...@@ -51,7 +60,8 @@ type Service struct { ...@@ -51,7 +60,8 @@ type Service struct {
ctx context.Context ctx context.Context
cancel func() cancel func()
txMgr txmgr.TxManager txMgr txmgr.TxManager
metrics *metrics.Metrics
wg sync.WaitGroup wg sync.WaitGroup
} }
...@@ -64,10 +74,11 @@ func NewService(cfg ServiceConfig) *Service { ...@@ -64,10 +74,11 @@ func NewService(cfg ServiceConfig) *Service {
) )
return &Service{ return &Service{
cfg: cfg, cfg: cfg,
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
txMgr: txMgr, txMgr: txMgr,
metrics: cfg.Driver.Metrics(),
} }
} }
...@@ -91,21 +102,35 @@ func (s *Service) eventLoop() { ...@@ -91,21 +102,35 @@ func (s *Service) eventLoop() {
for { for {
select { select {
case <-time.After(s.cfg.PollInterval): case <-time.After(s.cfg.PollInterval):
log.Info(name + " fetching current block range") // Record the submitter's current ETH balance. This is done first in
// case any of the remaining steps fail, we can at least have an
// accurate view of the submitter's balance.
balance, err := s.cfg.L1Client.BalanceAt(
s.ctx, s.cfg.Driver.WalletAddr(), nil,
)
if err != nil {
log.Error(name+" unable to get current balance", "err", err)
continue
}
s.metrics.ETHBalance.Set(weiToGwei64(balance))
// Determine the range of L2 blocks that the batch submitter has not
// processed, and needs to take action on.
log.Info(name + " fetching current block range")
start, end, err := s.cfg.Driver.GetBatchBlockRange(s.ctx) start, end, err := s.cfg.Driver.GetBatchBlockRange(s.ctx)
if err != nil { if err != nil {
log.Error(name+" unable to get block range", "err", err) log.Error(name+" unable to get block range", "err", err)
continue continue
} }
log.Info(name+" block range", "start", start, "end", end)
// No new updates. // No new updates.
if start.Cmp(end) == 0 { if start.Cmp(end) == 0 {
log.Info(name+" no updates", "start", start, "end", end)
continue continue
} }
log.Info(name+" block range", "start", start, "end", end)
// Query for the submitter's current nonce.
nonce64, err := s.cfg.L1Client.NonceAt( nonce64, err := s.cfg.L1Client.NonceAt(
s.ctx, s.cfg.Driver.WalletAddr(), nil, s.ctx, s.cfg.Driver.WalletAddr(), nil,
) )
...@@ -116,6 +141,8 @@ func (s *Service) eventLoop() { ...@@ -116,6 +141,8 @@ func (s *Service) eventLoop() {
} }
nonce := new(big.Int).SetUint64(nonce64) nonce := new(big.Int).SetUint64(nonce64)
// Construct the transaction submission clousure that will attempt
// to send the next transaction at the given nonce and gas price.
sendTx := func( sendTx := func(
ctx context.Context, ctx context.Context,
gasPrice *big.Int, gasPrice *big.Int,
...@@ -123,20 +150,38 @@ func (s *Service) eventLoop() { ...@@ -123,20 +150,38 @@ func (s *Service) eventLoop() {
log.Info(name+" attempting batch tx", "start", start, log.Info(name+" attempting batch tx", "start", start,
"end", end, "nonce", nonce, "end", end, "nonce", nonce,
"gasPrice", gasPrice) "gasPrice", gasPrice)
return s.cfg.Driver.SubmitBatchTx(
tx, err := s.cfg.Driver.SubmitBatchTx(
ctx, start, end, nonce, gasPrice, ctx, start, end, nonce, gasPrice,
) )
if err != nil {
return nil, err
}
s.metrics.BatchSizeInBytes.Observe(float64(tx.Size()))
return tx, nil
} }
// Wait until one of our submitted transactions confirms. If no
// receipt is received it's likely our gas price was too low.
batchConfirmationStart := time.Now()
receipt, err := s.txMgr.Send(s.ctx, sendTx) receipt, err := s.txMgr.Send(s.ctx, sendTx)
if err != nil { if err != nil {
log.Error(name+" unable to publish batch tx", log.Error(name+" unable to publish batch tx",
"err", err) "err", err)
s.metrics.FailedSubmissions.Inc()
continue continue
} }
// The transaction was successfully submitted.
log.Info(name+" batch tx successfully published", log.Info(name+" batch tx successfully published",
"tx_hash", receipt.TxHash) "tx_hash", receipt.TxHash)
batchConfirmationTime := time.Since(batchConfirmationStart) /
time.Millisecond
s.metrics.BatchConfirmationTime.Set(float64(batchConfirmationTime))
s.metrics.BatchesSubmitted.Inc()
s.metrics.SubmissionGasUsed.Observe(float64(receipt.GasUsed))
case err := <-s.ctx.Done(): case err := <-s.ctx.Done():
log.Error(name+" service shutting down", "err", err) log.Error(name+" service shutting down", "err", err)
...@@ -144,3 +189,10 @@ func (s *Service) eventLoop() { ...@@ -144,3 +189,10 @@ func (s *Service) eventLoop() {
} }
} }
} }
func weiToGwei64(wei *big.Int) float64 {
gwei := new(big.Float).SetInt(wei)
gwei.Mul(gwei, weiToGwei)
gwei64, _ := gwei.Float64()
return gwei64
}
...@@ -40,7 +40,7 @@ options. ...@@ -40,7 +40,7 @@ options.
``` ```
NAME: NAME:
gas-oracle - Remotely Control the Optimistic Ethereum Gas Price gas-oracle - Remotely Control the Optimism Gas Price
USAGE: USAGE:
gas-oracle [global options] command [command options] [arguments...] gas-oracle [global options] command [command options] [arguments...]
...@@ -49,7 +49,7 @@ VERSION: ...@@ -49,7 +49,7 @@ VERSION:
0.0.0-1.10.4-stable 0.0.0-1.10.4-stable
DESCRIPTION: DESCRIPTION:
Configure with a private key and an Optimistic Ethereum HTTP endpoint to send transactions that update the L2 gas price. Configure with a private key and an Optimism HTTP endpoint to send transactions that update the L2 gas price.
COMMANDS: COMMANDS:
help, h Shows a list of commands or help for one command help, h Shows a list of commands or help for one command
......
...@@ -26,8 +26,8 @@ func main() { ...@@ -26,8 +26,8 @@ func main() {
app.Version = GitVersion + "-" + params.VersionWithCommit(GitCommit, GitDate) app.Version = GitVersion + "-" + params.VersionWithCommit(GitCommit, GitDate)
app.Name = "gas-oracle" app.Name = "gas-oracle"
app.Usage = "Remotely Control the Optimistic Ethereum Gas Price" app.Usage = "Remotely Control the Optimism Gas Price"
app.Description = "Configure with a private key and an Optimistic Ethereum HTTP endpoint " + app.Description = "Configure with a private key and an Optimism HTTP endpoint " +
"to send transactions that update the L2 gas price." "to send transactions that update the L2 gas price."
// Configure the logging // Configure the logging
......
# @eth-optimism/l2geth-exporter
## 0.0.2
### Patch Changes
- 71bfa3fe: Initial build
SHELL := /bin/bash
VERSION := `git describe --abbrev=0`
GITCOMMIT := `git rev-parse HEAD`
BUILDDATE := `date +%Y-%m-%d`
BUILDUSER := `whoami`
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
LDFLAGSSTRING +=-X main.GitVersion=$(GITVERSION)
LDFLAGS :=-ldflags "$(LDFLAGSSTRING)"
all: build
build:
CGO_ENABLED=0 go build $(LDFLAGS)
clean:
rm l2geth-exporter
test:
go test -v ./...
lint:
golangci-lint run ./...
binding:
$(eval temp := $(shell mktemp))
cat ../../packages/contracts/deployments/mainnet/CanonicalTransactionChain.json \
| jq -r .bytecode > $(temp)
cat ../../packages/contracts/deployments/mainnet/CanonicalTransactionChain.json \
| jq .abi \
| abigen --pkg bindings \
--abi - \
--out bindings/CanonicalTransactionChain.go \
--type CanonicalTransactionChain \
--bin $(temp)
rm $(temp)
This diff is collapsed.
package main
import (
"github.com/prometheus/client_golang/prometheus"
)
//Define the metrics we wish to expose
var (
ctcTotalElements = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "l2geth_ctc_total_elements",
Help: "CTC GetTotalElements value."},
[]string{"state"},
)
ctcTotalElementsCallSuccess = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "l2geth_ctc_total_elements_call_success",
Help: "CTC GetTotalElements call success."},
)
)
func init() {
//Register metrics with prometheus
prometheus.MustRegister(ctcTotalElements)
prometheus.MustRegister(ctcTotalElementsCallSuccess)
}
module github.com/ethereum-optimism/optimism/go/l2geth-exporter
go 1.16
require (
github.com/ethereum/go-ethereum v1.10.8
github.com/prometheus/client_golang v1.11.0
)
This diff is collapsed.
package l1contracts
import (
"context"
"math/big"
"github.com/ethereum-optimism/optimism/go/l2geth-exporter/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
// CTC interacts with the OVM CTC contract
type CTC struct {
Address common.Address
Client *ethclient.Client
}
func (ctc *CTC) GetTotalElements(ctx context.Context) (*big.Int, error) {
contract, err := bindings.NewCanonicalTransactionChainCaller(ctc.Address, ctc.Client)
if err != nil {
return nil, err
}
totalElements, err := contract.GetTotalElements(&bind.CallOpts{
Context: ctx,
})
if err != nil {
return nil, err
}
return totalElements, nil
}
package main
import (
"context"
"math/big"
"net/http"
"os"
"time"
"github.com/ethereum-optimism/optimism/go/l2geth-exporter/l1contracts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
l1TimeoutSeconds = 5
)
func main() {
listenAddress := os.Getenv("LISTEN_ADDRESS")
if listenAddress == "" {
listenAddress = ":9100"
}
log.Root().SetHandler(log.CallerFileHandler(log.StdoutHandler))
l1Url := os.Getenv("L1_URL")
if l1Url == "" {
log.Error("L1_URL environmental variable is required")
os.Exit(1)
}
ctcAddress := os.Getenv("CTC_ADDRESS")
if ctcAddress == "" {
log.Error("CTC_ADDRESS environmental variable is required")
os.Exit(1)
}
client, err := ethclient.Dial(l1Url)
if err != nil {
log.Error("Problem connecting to L1: %s", err)
}
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>L2geth Exporter</title></head>
<body>
<h1>L2geth Exporter</h1>
<p><a href="/metrics">Metrics</a></p>
</body>
</html>`))
})
go getCTCTotalElements(ctcAddress, client)
log.Info("Program starting", "listenAddress", listenAddress, "GETH_URL", l1Url, "CTC_ADDRESS", ctcAddress)
if err := http.ListenAndServe(listenAddress, nil); err != nil {
log.Error("Can't start http server", "error", err)
}
}
func getCTCTotalElements(address string, client *ethclient.Client) {
ctc := l1contracts.CTC{
Address: common.HexToAddress(address),
Client: client,
}
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(l1TimeoutSeconds))
totalElements, err := ctc.GetTotalElements(ctx)
if err != nil {
ctcTotalElementsCallSuccess.Set(0)
log.Error("Error calling GetTotalElements", "error", err)
cancel()
continue
}
ctcTotalElementsCallSuccess.Set(1)
totalElementsFloat, _ := new(big.Float).SetInt(totalElements).Float64()
ctcTotalElements.WithLabelValues(
"latest").Set(totalElementsFloat)
log.Info("ctc updated", "ctcTotalElements", totalElementsFloat)
cancel()
<-ticker.C
}
}
{
"name": "@eth-optimism/l2geth-exporter",
"version": "0.0.2",
"private": true,
"devDependencies": {}
}
# op_exporter # op_exporter
A prometheus exporter to collect information from an Optimistic Ethereum node and serve metrics for collection A prometheus exporter to collect information from an Optimism node and serve metrics for collection
## Usage ## Usage
......
# @eth-optimism/proxyd # @eth-optimism/proxyd
## 3.4.1
### Patch Changes
- 415164e1: Force proxyd build
## 3.4.0 ## 3.4.0
### Minor Changes ### Minor Changes
......
{ {
"name": "@eth-optimism/proxyd", "name": "@eth-optimism/proxyd",
"version": "3.4.0", "version": "3.4.1",
"private": true, "private": true,
"dependencies": {} "dependencies": {}
} }
...@@ -14,7 +14,7 @@ program ...@@ -14,7 +14,7 @@ program
.option('-r, --runs <n>', 'number of runs. cannot be use with -t/--time') .option('-r, --runs <n>', 'number of runs. cannot be use with -t/--time')
.option( .option(
'-t, --time <ms>', '-t, --time <ms>',
'how long to run in milliseconds. cannot be used with -r/--runs', 'how long to run in milliseconds. cannot be used with -r/--runs'
) )
.option('-c, --concurrency <n>', 'number of concurrent workers to spawn', '1') .option('-c, --concurrency <n>', 'number of concurrent workers to spawn', '1')
.option('--think-time <n>', 'how long to wait between each run', '0') .option('--think-time <n>', 'how long to wait between each run', '0')
......
...@@ -87,7 +87,10 @@ actor('Uniswap swapper', () => { ...@@ -87,7 +87,10 @@ actor('Uniswap swapper', () => {
let tx = await token.transfer(wallet.address, 1000000) let tx = await token.transfer(wallet.address, 1000000)
await tx.wait() await tx.wait()
const boundToken = token.connect(wallet) const boundToken = token.connect(wallet)
tx = await boundToken.approve(contracts.positionManager.address, 1000000000) tx = await boundToken.approve(
contracts.positionManager.address,
1000000000
)
await tx.wait() await tx.wait()
tx = await boundToken.approve(contracts.router.address, 1000000000) tx = await boundToken.approve(contracts.router.address, 1000000000)
await tx.wait() await tx.wait()
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"build": "hardhat compile", "build": "hardhat compile",
"test:integration": "hardhat --network optimism test", "test:integration": "hardhat --network optimism test",
"test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts", "test:actor": "IS_LIVE_NETWORK=true ts-node actor-tests/lib/runner.ts",
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
"devDependencies": { "devDependencies": {
"@eth-optimism/contracts": "0.5.7", "@eth-optimism/contracts": "0.5.7",
"@eth-optimism/core-utils": "0.7.3", "@eth-optimism/core-utils": "0.7.3",
"@eth-optimism/message-relayer": "0.2.10", "@eth-optimism/message-relayer": "0.2.11",
"@ethersproject/abstract-provider": "^5.5.1", "@ethersproject/abstract-provider": "^5.5.1",
"@ethersproject/providers": "^5.4.5", "@ethersproject/providers": "^5.4.5",
"@ethersproject/transactions": "^5.4.0", "@ethersproject/transactions": "^5.4.0",
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
"envalid": "^7.1.0", "envalid": "^7.1.0",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
import { expect } from 'chai' import { expect } from './shared/setup'
/* Imports: External */ /* Imports: External */
import { Contract, ContractFactory } from 'ethers' import { Contract, ContractFactory } from 'ethers'
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers' import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import * as L2Artifact from '@eth-optimism/contracts/artifacts/contracts/standards/L2StandardERC20.sol/L2StandardERC20.json' import * as L2Artifact from '@eth-optimism/contracts/artifacts/contracts/standards/L2StandardERC20.sol/L2StandardERC20.json'
import { expect } from 'chai'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { isLiveNetwork, isMainnet } from './shared/utils' import { isLiveNetwork, isMainnet } from './shared/utils'
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers' import { BigNumber, Contract, ContractFactory, utils, Wallet } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import { solidity } from 'ethereum-waffle'
import chai, { expect } from 'chai'
import { UniswapV3Deployer } from 'uniswap-v3-deploy-plugin/dist/deployer/UniswapV3Deployer' import { UniswapV3Deployer } from 'uniswap-v3-deploy-plugin/dist/deployer/UniswapV3Deployer'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
...@@ -10,8 +10,6 @@ import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk' ...@@ -10,8 +10,6 @@ import { FeeAmount, TICK_SPACINGS } from '@uniswap/v3-sdk'
import { abi as NFTABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json' import { abi as NFTABI } from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
import { abi as RouterABI } from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json' import { abi as RouterABI } from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'
chai.use(solidity)
// Below methods taken from the Uniswap test suite, see // Below methods taken from the Uniswap test suite, see
// https://github.com/Uniswap/v3-periphery/blob/main/test/shared/ticks.ts // https://github.com/Uniswap/v3-periphery/blob/main/test/shared/ticks.ts
const getMinTick = (tickSpacing: number) => const getMinTick = (tickSpacing: number) =>
......
import chai, { expect } from 'chai' import { expect } from './shared/setup'
import chaiAsPromised from 'chai-as-promised'
chai.use(chaiAsPromised)
/* Imports: External */ /* Imports: External */
import { BigNumber, utils } from 'ethers' import { BigNumber, utils } from 'ethers'
......
import { expect } from './shared/setup'
import { BigNumber, Contract, ContractFactory, Wallet } from 'ethers' import { BigNumber, Contract, ContractFactory, Wallet } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import chai, { expect } from 'chai'
import { import {
fundUser, fundUser,
encodeSolidityRevertMessage, encodeSolidityRevertMessage,
gasPriceForL2, gasPriceForL2,
} from './shared/utils' } from './shared/utils'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { solidity } from 'ethereum-waffle'
chai.use(solidity)
describe('Native ETH value integration tests', () => { describe('Native ETH value integration tests', () => {
let env: OptimismEnv let env: OptimismEnv
......
import { expect } from 'chai' import { expect } from './shared/setup'
/* Imports: External */ /* Imports: External */
import { Wallet, utils, BigNumber } from 'ethers' import { Wallet, utils, BigNumber } from 'ethers'
......
import { expect } from 'chai' import { expect } from './shared/setup'
/* Imports: External */ /* Imports: External */
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
......
import chai, { expect } from 'chai' import { expect } from './shared/setup'
import { solidity } from 'ethereum-waffle'
chai.use(solidity)
/* Imports: Internal */ /* Imports: Internal */
import { ethers } from 'ethers' import { ethers } from 'ethers'
......
import { expect } from 'chai' import { expect } from './shared/setup'
/* Imports: Internal */ /* Imports: Internal */
import { providers } from 'ethers' import { providers } from 'ethers'
......
import { expect } from './shared/setup'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { import {
defaultTransactionFactory, defaultTransactionFactory,
...@@ -5,7 +6,6 @@ import { ...@@ -5,7 +6,6 @@ import {
sleep, sleep,
isLiveNetwork, isLiveNetwork,
} from './shared/utils' } from './shared/utils'
import { expect } from 'chai'
import { TransactionReceipt } from '@ethersproject/abstract-provider' import { TransactionReceipt } from '@ethersproject/abstract-provider'
describe('Replica Tests', () => { describe('Replica Tests', () => {
......
import { expect } from './shared/setup'
import { expectApprox, injectL2Context } from '@eth-optimism/core-utils' import { expectApprox, injectL2Context } from '@eth-optimism/core-utils'
import { Wallet, BigNumber, Contract, ContractFactory } from 'ethers' import { Wallet, BigNumber, Contract, ContractFactory } from 'ethers'
import { serialize } from '@ethersproject/transactions' import { serialize } from '@ethersproject/transactions'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import chai, { expect } from 'chai'
import { import {
sleep, sleep,
l2Provider, l2Provider,
...@@ -12,18 +13,13 @@ import { ...@@ -12,18 +13,13 @@ import {
isLiveNetwork, isLiveNetwork,
gasPriceForL2, gasPriceForL2,
} from './shared/utils' } from './shared/utils'
import chaiAsPromised from 'chai-as-promised'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { import {
TransactionReceipt, TransactionReceipt,
TransactionRequest, TransactionRequest,
} from '@ethersproject/providers' } from '@ethersproject/providers'
import { solidity } from 'ethereum-waffle'
import simpleStorageJson from '../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json' import simpleStorageJson from '../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json'
chai.use(chaiAsPromised)
chai.use(solidity)
describe('Basic RPC tests', () => { describe('Basic RPC tests', () => {
let env: OptimismEnv let env: OptimismEnv
let wallet: Wallet let wallet: Wallet
...@@ -286,7 +282,7 @@ describe('Basic RPC tests', () => { ...@@ -286,7 +282,7 @@ describe('Basic RPC tests', () => {
expect(receipt.status).to.eq(0) expect(receipt.status).to.eq(0)
}) })
// Optimistic Ethereum special fields on the receipt // Optimism special fields on the receipt
it('includes L1 gas price and L1 gas used', async () => { it('includes L1 gas price and L1 gas used', async () => {
const tx = await env.l2Wallet.populateTransaction({ const tx = await env.l2Wallet.populateTransaction({
to: env.l2Wallet.address, to: env.l2Wallet.address,
......
/* External Imports */
import chai = require('chai')
import chaiAsPromised from 'chai-as-promised'
import { solidity } from 'ethereum-waffle'
chai.use(solidity)
chai.use(chaiAsPromised)
const expect = chai.expect
export { expect }
import { expect } from 'chai' import { expect } from './shared/setup'
/* Imports: External */ /* Imports: External */
import { Contract, ContractFactory, Wallet, utils } from 'ethers' import { Contract, ContractFactory, Wallet, utils } from 'ethers'
......
import { expect } from './shared/setup'
/* Imports: External */ /* Imports: External */
import { ContractFactory } from 'ethers' import { ContractFactory } from 'ethers'
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import chai, { expect } from 'chai'
import { solidity } from 'ethereum-waffle'
import { predeploys } from '@eth-optimism/contracts' import { predeploys } from '@eth-optimism/contracts'
/* Imports: Internal */ /* Imports: Internal */
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { l2Provider } from './shared/utils' import { l2Provider } from './shared/utils'
chai.use(solidity)
describe('Whitelist', async () => { describe('Whitelist', async () => {
const initialAmount = 1000 const initialAmount = 1000
const tokenName = 'OVM Test' const tokenName = 'OVM Test'
......
# Changelog # Changelog
## 0.5.5
### Patch Changes
- 2924845d: expose ErrNonceTooHigh from miner
## 0.5.4 ## 0.5.4
### Patch Changes ### Patch Changes
......
{ {
"name": "@eth-optimism/l2geth", "name": "@eth-optimism/l2geth",
"version": "0.5.4", "version": "0.5.5",
"private": true, "private": true,
"devDependencies": {} "devDependencies": {}
} }
...@@ -22,28 +22,33 @@ services: ...@@ -22,28 +22,33 @@ services:
target: deployer target: deployer
entrypoint: ./deployer.sh entrypoint: ./deployer.sh
environment: environment:
FRAUD_PROOF_WINDOW_SECONDS: 0 # Env vars for the deployment script.
L1_NODE_WEB3_URL: http://l1_chain:8545 CONTRACTS_RPC_URL: http://l1_chain:8545
# these keys are hardhat's first 3 accounts, DO NOT use in production CONTRACTS_DEPLOYER_KEY: "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
DEPLOYER_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" CONTRACTS_TARGET_NETWORK: "custom"
SEQUENCER_PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" OVM_ADDRESS_MANAGER_OWNER: "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266"
PROPOSER_PRIVATE_KEY: "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" OVM_PROPOSER_ADDRESS: "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc"
# Default hardhat account 5 OVM_SEQUENCER_ADDRESS: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8"
GAS_PRICE_ORACLE_OWNER: "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc" SCC_FRAUD_PROOF_WINDOW: 0
# setting the whitelist owner to address(0) disables the whitelist NUM_DEPLOY_CONFIRMATIONS: 0
WHITELIST_OWNER: "0x0000000000000000000000000000000000000000" # skip compilation when run in docker-compose, since the contracts
L1_FEE_WALLET_ADDRESS: "0x391716d440c151c42cdf1c95c1d83a5427bca52c" # were already compiled in the builder step
L2_CHAIN_ID: 420 NO_COMPILE: 1
L2_BLOCK_GAS_LIMIT: 15000000
BLOCK_SIGNER_ADDRESS: "0x00000398232E2064F896018496b4b44b3D62751F" # Env vars for the dump script.
GAS_PRICE_ORACLE_OVERHEAD: "2750" # Default hardhat account 5
GAS_PRICE_ORACLE_SCALAR: "1500000" GAS_PRICE_ORACLE_OWNER: "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc"
GAS_PRICE_ORACLE_L1_BASE_FEE: "1" # setting the whitelist owner to address(0) disables the whitelist
GAS_PRICE_ORACLE_GAS_PRICE: "1" WHITELIST_OWNER: "0x0000000000000000000000000000000000000000"
GAS_PRICE_ORACLE_DECIMALS: "6" L1_FEE_WALLET_ADDRESS: "0x391716d440c151c42cdf1c95c1d83a5427bca52c"
# skip compilation when run in docker-compose, since the contracts L2_CHAIN_ID: 420
# were already compiled in the builder step L2_BLOCK_GAS_LIMIT: 15000000
NO_COMPILE: 1 BLOCK_SIGNER_ADDRESS: "0x00000398232E2064F896018496b4b44b3D62751F"
GAS_PRICE_ORACLE_OVERHEAD: 2750
GAS_PRICE_ORACLE_SCALAR: 1500000
GAS_PRICE_ORACLE_L1_BASE_FEE: 1
GAS_PRICE_ORACLE_GAS_PRICE: 1
GAS_PRICE_ORACLE_DECIMALS: 6
ports: ports:
# expose the service to the host for getting the contract addrs # expose the service to the host for getting the contract addrs
- ${DEPLOYER_PORT:-8080}:8081 - ${DEPLOYER_PORT:-8080}:8081
......
...@@ -34,4 +34,4 @@ COPY packages/contracts/test/helpers/constants.ts ./test/helpers/constants.ts ...@@ -34,4 +34,4 @@ COPY packages/contracts/test/helpers/constants.ts ./test/helpers/constants.ts
COPY packages/contracts/scripts ./scripts COPY packages/contracts/scripts ./scripts
COPY ./ops/scripts/deployer.sh . COPY ./ops/scripts/deployer.sh .
ENTRYPOINT yarn run deploy CMD ./ops/scripts/deployer.sh
FROM golang:1.16 as builder
ADD ./go/l2geth-exporter /app/
WORKDIR /app/
RUN make build
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/l2geth-exporter /usr/local/bin/
ENTRYPOINT ["l2geth-exporter"]
CMD ["--help"]
...@@ -28,7 +28,6 @@ COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/ ...@@ -28,7 +28,6 @@ COPY --from=builder /optimism/packages/contracts/artifacts ./packages/contracts/
WORKDIR /opt/optimism/packages/message-relayer WORKDIR /opt/optimism/packages/message-relayer
COPY --from=builder /optimism/packages/message-relayer/dist ./dist COPY --from=builder /optimism/packages/message-relayer/dist ./dist
COPY --from=builder /optimism/packages/message-relayer/package.json . COPY --from=builder /optimism/packages/message-relayer/package.json .
COPY --from=builder /optimism/packages/message-relayer/exec ./exec
COPY --from=builder /optimism/packages/message-relayer/node_modules ./node_modules COPY --from=builder /optimism/packages/message-relayer/node_modules ./node_modules
# copy this over in case you want to run alongside other services # copy this over in case you want to run alongside other services
......
...@@ -11,7 +11,7 @@ RUN apt-get update -y && apt-get install -y git curl jq python3 ...@@ -11,7 +11,7 @@ RUN apt-get update -y && apt-get install -y git curl jq python3
# copy over the needed configs to run the dep installation # copy over the needed configs to run the dep installation
# note: this approach can be a bit unhandy to maintain, but it allows # note: this approach can be a bit unhandy to maintain, but it allows
# us to cache the installation steps # us to cache the installation steps
WORKDIR /optimism WORKDIR /opt/optimism
COPY *.json yarn.lock ./ COPY *.json yarn.lock ./
COPY packages/core-utils/package.json ./packages/core-utils/package.json COPY packages/core-utils/package.json ./packages/core-utils/package.json
COPY packages/common-ts/package.json ./packages/common-ts/package.json COPY packages/common-ts/package.json ./packages/common-ts/package.json
...@@ -33,30 +33,30 @@ RUN yarn build ...@@ -33,30 +33,30 @@ RUN yarn build
FROM base as deployer FROM base as deployer
WORKDIR /optimism/packages/contracts WORKDIR /opt/optimism/packages/contracts
COPY ./ops/scripts/deployer.sh . COPY ./ops/scripts/deployer.sh .
CMD ["yarn", "run", "deploy"] CMD ["yarn", "run", "deploy"]
FROM base as batch-submitter FROM base as batch-submitter
WORKDIR /optimism/packages/batch-submitter WORKDIR /opt/optimism/packages/batch-submitter
COPY ./ops/scripts/batches.sh . COPY ./ops/scripts/batches.sh .
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
FROM base as data-transport-layer FROM base as data-transport-layer
WORKDIR /optimism/packages/data-transport-layer WORKDIR /opt/optimism/packages/data-transport-layer
COPY ./ops/scripts/dtl.sh . COPY ./ops/scripts/dtl.sh .
CMD ["node", "dist/src/services/run.js"] CMD ["node", "dist/src/services/run.js"]
FROM base as integration-tests FROM base as integration-tests
WORKDIR /optimism/integration-tests WORKDIR /opt/optimism/integration-tests
COPY ./ops/scripts/integration-tests.sh ./ COPY ./ops/scripts/integration-tests.sh ./
CMD ["yarn", "test:integration"] CMD ["yarn", "test:integration"]
FROM base as relayer FROM base as relayer
WORKDIR /optimism/packages/message-relayer WORKDIR /opt/optimism/packages/message-relayer
COPY ./ops/scripts/relayer.sh . COPY ./ops/scripts/relayer.sh .
CMD ["npm", "run", "start"] CMD ["npm", "run", "start"]
#!/bin/bash #!/bin/bash
set -e set -euo
RETRIES=${RETRIES:-20} RETRIES=${RETRIES:-20}
JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}' JSON='{"jsonrpc":"2.0","id":0,"method":"net_version","params":[]}'
if [ -z "$CONTRACTS_RPC_URL" ]; then
echo "Must specify \$CONTRACTS_RPC_URL."
exit 1
fi
# wait for the base layer to be up # wait for the base layer to be up
curl \ curl \
--fail \ --fail \
...@@ -14,30 +19,82 @@ curl \ ...@@ -14,30 +19,82 @@ curl \
--retry $RETRIES \ --retry $RETRIES \
--retry-delay 1 \ --retry-delay 1 \
-d $JSON \ -d $JSON \
$L1_NODE_WEB3_URL $CONTRACTS_RPC_URL > /dev/null
yarn run deploy echo "Connected to L1."
echo "Building deployment command."
function envSet() { DEPLOY_CMD="npx hardhat deploy"
VAR=$1
export $VAR=$(cat ./dist/dumps/addresses.json | jq -r ".$2") # Helper method to concatenate things onto $DEPLOY_CMD.
# Usage: concat_cmd "str-to-concat"
function concat_cmd() {
DEPLOY_CMD="$DEPLOY_CMD $1"
} }
# set the address to the proxy gateway if possible # Helper method to conditionally concatenate CLI arguments
envSet L1_STANDARD_BRIDGE_ADDRESS Proxy__OVM_L1StandardBridge # when a given env var is defined.
if [ $L1_STANDARD_BRIDGE_ADDRESS == null ]; then # Usage: concat_arg "--arg-name" "env-var-name"
envSet L1_STANDARD_BRIDGE_ADDRESS L1StandardBridge function concat_arg() {
fi ARG=$1
ENV_VAR=$2
if [ -n "${!ENV_VAR+x}" ]; then
echo "$ENV_VAR set to ${!ENV_VAR}, applying $ARG argument."
concat_cmd "$ARG \"${!ENV_VAR}\""
else
echo "$ENV_VAR is not not set, skipping $ARG argument."
fi
}
concat_arg "--network" "CONTRACTS_TARGET_NETWORK"
concat_arg "--ovm-address-manager-owner" "OVM_ADDRESS_MANAGER_OWNER"
concat_arg "--ovm-proposer-address" "OVM_PROPOSER_ADDRESS"
concat_arg "--ovm-sequencer-address" "OVM_SEQUENCER_ADDRESS"
concat_arg "--l1-block-time-seconds" "L1_BLOCK_TIME_SECONDS"
concat_arg "--ctc-max-transaction-gas-limit" "CTC_MAX_TRANSACTION_GAS_LIMIT"
concat_arg "--ctc-l2-gas-discount-divisor" "CTC_L2_GAS_DISCOUNT_DIVISOR"
concat_arg "--ctc-enqueue-gas-cost" "CTC_ENQUEUE_GAS_COST"
concat_arg "--scc-fraud-proof-window" "SCC_FRAUD_PROOF_WINDOW"
concat_arg "--num-deploy-confirmations" "NUM_DEPLOY_CONFIRMATIONS"
concat_arg "--forked" "FORKED"
echo "Deploying contracts. Deployment command:"
echo "$DEPLOY_CMD"
eval "$DEPLOY_CMD"
echo "Building addresses.json."
export ADDRESS_MANAGER_ADDRESS=$(cat "./deployments/$CONTRACTS_TARGET_NETWORK/Lib_AddressManager.json" | jq -r .address)
# First, create two files. One of them contains a list of addresses, the other contains a list of contract names.
find "./deployments/$CONTRACTS_TARGET_NETWORK" -maxdepth 1 -name '*.json' | xargs cat | jq -r '.address' > addresses.txt
find "./deployments/$CONTRACTS_TARGET_NETWORK" -maxdepth 1 -name '*.json' | sed -e "s/.\/deployments\/$CONTRACTS_TARGET_NETWORK\///g" | sed -e 's/.json//g' > filenames.txt
# Start building addresses.json.
echo "{" >> addresses.json
# Zip the two files describe above together, then, switch their order and format as JSON.
paste addresses.txt filenames.txt | sed -e "s/^\([^ ]\+\)\s\+\([^ ]\+\)/\"\2\": \"\1\",/" >> addresses.json
# Add the address manager alias.
echo "\"AddressManager\": \"$ADDRESS_MANAGER_ADDRESS\"" >> addresses.json
# End addresses.json
echo "}" >> addresses.json
echo "Built addresses.json. Content:"
jq . addresses.json
echo "Env vars for the dump script:"
export L1_STANDARD_BRIDGE_ADDRESS=$(cat "./addresses.json" | jq -r .Proxy__OVM_L1StandardBridge)
export L1_CROSS_DOMAIN_MESSENGER_ADDRESS=$(cat "./addresses.json" | jq -r .Proxy__OVM_L1CrossDomainMessenger)
echo "ADDRESS_MANAGER_ADDRESS=$ADDRESS_MANAGER_ADDRESS"
echo "L1_STANDARD_BRIDGE_ADDRESS=$L1_STANDARD_BRIDGE_ADDRESS"
echo "L1_CROSS_DOMAIN_MESSENGER_ADDRESS=$L1_CROSS_DOMAIN_MESSENGER_ADDRESS"
envSet L1_CROSS_DOMAIN_MESSENGER_ADDRESS Proxy__OVM_L1CrossDomainMessenger
if [ $L1_CROSS_DOMAIN_MESSENGER_ADDRESS == null ]; then
envSet L1_CROSS_DOMAIN_MESSENGER_ADDRESS L1CrossDomainMessenger
fi
# build the dump file echo "Building dump file."
yarn run build:dump yarn run build:dump
mv addresses.json ./dist/dumps
# service the addresses and dumps # service the addresses and dumps
echo "Starting server."
python3 -m http.server \ python3 -m http.server \
--bind "0.0.0.0" 8081 \ --bind "0.0.0.0" 8081 \
--directory ./dist/dumps --directory ./dist/dumps
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"specs", "specs",
"go/gas-oracle", "go/gas-oracle",
"go/batch-submitter", "go/batch-submitter",
"go/l2geth-exporter",
"go/proxyd", "go/proxyd",
"go/op-exporter", "go/op-exporter",
"ops/docker/rpc-proxy", "ops/docker/rpc-proxy",
...@@ -27,7 +28,6 @@ ...@@ -27,7 +28,6 @@
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
# Changelog # Changelog
## 0.4.12
### Patch Changes
- 07f1ad01: Fix the numTxPerBatch metric
## 0.4.11 ## 0.4.11
### Patch Changes ### Patch Changes
......
{ {
"private": true, "private": true,
"name": "@eth-optimism/batch-submitter", "name": "@eth-optimism/batch-submitter",
"version": "0.4.11", "version": "0.4.12",
"description": "[Optimism] Service for submitting transactions and transaction results", "description": "[Optimism] Service for submitting transactions and transaction results",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"test": "hardhat test --show-stack-traces", "test": "hardhat test --show-stack-traces",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json" "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
}, },
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
"chai": "^4.3.4", "chai": "^4.3.4",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
...@@ -154,7 +154,6 @@ export class StateBatchSubmitter extends BatchSubmitter { ...@@ -154,7 +154,6 @@ export class StateBatchSubmitter extends BatchSubmitter {
startBlock: number, startBlock: number,
endBlock: number endBlock: number
): Promise<TransactionReceipt> { ): Promise<TransactionReceipt> {
const batchTxBuildStart = performance.now() const batchTxBuildStart = performance.now()
const batch = await this._generateStateCommitmentBatch(startBlock, endBlock) const batch = await this._generateStateCommitmentBatch(startBlock, endBlock)
......
...@@ -232,7 +232,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter { ...@@ -232,7 +232,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
const batchTxBuildEnd = performance.now() const batchTxBuildEnd = performance.now()
this.metrics.batchTxBuildTime.set(batchTxBuildEnd - batchTxBuildStart) this.metrics.batchTxBuildTime.set(batchTxBuildEnd - batchTxBuildStart)
this.metrics.numTxPerBatch.observe(endBlock - startBlock) this.metrics.numTxPerBatch.observe(batchParams.totalElementsToAppend)
const l1tipHeight = await this.signer.provider.getBlockNumber() const l1tipHeight = await this.signer.provider.getBlockNumber()
this.logger.debug('Submitting batch.', { this.logger.debug('Submitting batch.', {
calldata: batchParams, calldata: batchParams,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint", "all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
...@@ -50,7 +50,6 @@ ...@@ -50,7 +50,6 @@
"chai": "^4.3.4", "chai": "^4.3.4",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=contracts)](https://codecov.io/gh/ethereum-optimism/optimism) [![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/master/graph/badge.svg?token=0VTG7PG7YR&flag=contracts)](https://codecov.io/gh/ethereum-optimism/optimism)
# Optimistic Ethereum Smart Contracts # Optimism Smart Contracts
`@eth-optimism/contracts` contains the various Solidity smart contracts used within the Optimistic Ethereum system. `@eth-optimism/contracts` contains the various Solidity smart contracts used within the Optimism system.
Some of these contracts are deployed on Ethereum ("Layer 1"), while others are meant to be deployed to Optimistic Ethereum ("Layer 2"). Some of these contracts are deployed on Ethereum ("Layer 1"), while others are meant to be deployed to Optimism ("Layer 2").
Within each contract file you'll find a comment that lists: Within each contract file you'll find a comment that lists:
1. The compiler with which a contract is intended to be compiled, `solc` or `optimistic-solc`. 1. The compiler with which a contract is intended to be compiled, `solc` or `optimistic-solc`.
......
// WARNING: DO NOT USE THIS FILE TO DEPLOY CONTRACTS TO PRODUCTION
// WE ARE REMOVING THIS FILE IN A FUTURE RELEASE, IT IS ONLY TO BE USED AS PART OF THE LOCAL
// DEPLOYMENT PROCESS. USE A DEPLOYMENT SCRIPT LOCATED IN scripts/deploy-scripts/ WHEN DEPLOYING
// TO A PRODUCTION ENVIRONMENT.
import { Wallet } from 'ethers'
import path from 'path'
import dirtree from 'directory-tree'
import fs from 'fs'
// Ensures that all relevant environment vars are properly set. These lines *must* come before the
// hardhat import because importing will load the config (which relies on these vars). Necessary
// because CI currently uses different var names than the ones we've chosen here.
// TODO: Update CI so that we don't have to do this anymore.
process.env.HARDHAT_NETWORK = 'custom' // "custom" here is an arbitrary name. only used for CI.
process.env.CONTRACTS_TARGET_NETWORK = 'custom'
process.env.CONTRACTS_DEPLOYER_KEY = process.env.DEPLOYER_PRIVATE_KEY
process.env.CONTRACTS_RPC_URL =
process.env.L1_NODE_WEB3_URL || 'http://127.0.0.1:8545'
import hre from 'hardhat'
const sequencer = new Wallet(process.env.SEQUENCER_PRIVATE_KEY)
const proposer = new Wallet(process.env.PROPOSER_PRIVATE_KEY)
const deployer = new Wallet(process.env.DEPLOYER_PRIVATE_KEY)
const parseEnv = () => {
const ensure = (env, type) => {
if (typeof process.env[env] === 'undefined') {
return undefined
}
if (type === 'number') {
return parseInt(process.env[env], 10)
}
return process.env[env]
}
return {
l1BlockTimeSeconds: ensure('BLOCK_TIME_SECONDS', 'number'),
ctcMaxTransactionGasLimit: ensure('MAX_TRANSACTION_GAS_LIMIT', 'number'),
ctcL2GasDiscountDivisor: ensure('L2_GAS_DISCOUNT_DIVISOR', 'number'),
ctcEnqueueGasCost: ensure('ENQUEUE_GAS_COST', 'number'),
sccFraudProofWindow: ensure('FRAUD_PROOF_WINDOW_SECONDS', 'number'),
sccSequencerPublishWindow: ensure(
'SEQUENCER_PUBLISH_WINDOW_SECONDS',
'number'
),
}
}
const main = async () => {
// Just be really verbose about this...
console.log(
`WARNING: DO NOT USE THIS FILE IN PRODUCTION! FOR LOCAL DEVELOPMENT ONLY!`
)
const config = parseEnv()
await hre.run('deploy', {
l1BlockTimeSeconds: config.l1BlockTimeSeconds,
ctcMaxTransactionGasLimit: config.ctcMaxTransactionGasLimit,
ctcL2GasDiscountDivisor: config.ctcL2GasDiscountDivisor,
ctcEnqueueGasCost: config.ctcEnqueueGasCost,
sccFraudProofWindow: config.sccFraudProofWindow,
sccSequencerPublishWindow: config.sccFraudProofWindow,
ovmSequencerAddress: sequencer.address,
ovmProposerAddress: proposer.address,
ovmAddressManagerOwner: deployer.address,
numDeployConfirmations: 0,
noCompile: process.env.NO_COMPILE ? true : false,
})
// Stuff below this line is currently required for CI to work properly. We probably want to
// update our CI so this is no longer necessary. But I'm adding it for backwards compat so we can
// get the hardhat-deploy stuff merged. Woot.
const nicknames = {
Lib_AddressManager: 'AddressManager',
}
const contracts: any = dirtree(
path.resolve(__dirname, `../deployments/custom`)
)
.children.filter((child) => {
return child.extension === '.json'
})
.reduce((contractsAccumulator, child) => {
const contractName = child.name.replace('.json', '')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const artifact = require(path.resolve(
__dirname,
`../deployments/custom/${child.name}`
))
contractsAccumulator[nicknames[contractName] || contractName] =
artifact.address
return contractsAccumulator
}, {})
contracts.OVM_Sequencer = await sequencer.getAddress()
contracts.Deployer = await deployer.getAddress()
const addresses = JSON.stringify(contracts, null, 2)
const dumpsPath = path.resolve(__dirname, '../dist/dumps')
if (!fs.existsSync(dumpsPath)) {
fs.mkdirSync(dumpsPath)
}
const addrsPath = path.resolve(dumpsPath, 'addresses.json')
fs.writeFileSync(addrsPath, addresses)
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.log(
JSON.stringify({ error: error.message, stack: error.stack }, null, 2)
)
process.exit(1)
})
# Optimistic Ethereum Deployments # Optimism Deployments
- [Optimistic Ethereum (mainnet)](./mainnet#readme) - [Optimism (mainnet)](./mainnet#readme)
- [Optimistic Kovan (public testnet)](./kovan#readme) - [Optimism Kovan (public testnet)](./kovan#readme)
- [Optimistic Goerli (internal devnet)](./goerli#readme) - [Optimism Goerli (internal devnet)](./goerli#readme)
# Optimistic Goerli (internal devnet) # Optimism Goerli (internal devnet)
## Notice ## Notice
Optimistic Goerli is an internal Optimism development network. You're probably looking for [Optimistic Kovan](../kovan#readme), the public Optimistic Ethereum testnet. Optimism Goerli is an internal Optimism development network. You're probably looking for [Optimism Kovan](../kovan#readme), the public Optimism testnet.
## Network Info ## Network Info
- **Chain ID**: 420 - **Chain ID**: 420
## Layer 1 Contracts ## Layer 1 Contracts
......
# Optimistic Kovan (public testnet) # Optimism Kovan (public testnet)
## Network Info ## Network Info
- **Chain ID**: 69 - **Chain ID**: 69
- **Public RPC**: https://kovan.optimism.io - **Public RPC**: https://kovan.optimism.io
......
# Optimistic Ethereum (mainnet) # Optimism (mainnet)
## Network Info ## Network Info
- **Chain ID**: 10 - **Chain ID**: 10
- **Public RPC**: https://mainnet.optimism.io - **Public RPC**: https://mainnet.optimism.io
......
{ {
"name": "@eth-optimism/contracts", "name": "@eth-optimism/contracts",
"version": "0.5.7", "version": "0.5.7",
"description": "[Optimism] L1 and L2 smart contracts for Optimistic Ethereum", "description": "[Optimism] L1 and L2 smart contracts for Optimism",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
"files": [ "files": [
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
"test:slither": "slither .", "test:slither": "slither .",
"pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat", "pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat",
"posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat", "posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat",
"lint:ts:check": "eslint .", "lint:ts:check": "eslint . --max-warnings=0",
"lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'", "lint:contracts:check": "yarn solhint -f table 'contracts/**/*.sol'",
"lint:check": "yarn lint:contracts:check && yarn lint:ts:check", "lint:check": "yarn lint:contracts:check && yarn lint:ts:check",
"lint:ts:fix": "eslint --fix .", "lint:ts:fix": "eslint --fix .",
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
"lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix", "lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.build.tsbuildinfo", "clean": "rm -rf ./dist ./artifacts ./cache ./coverage ./tsconfig.build.tsbuildinfo",
"deploy": "ts-node bin/deploy.ts && yarn autogen:markdown",
"prepublishOnly": "yarn copyfiles -u 1 -e \"**/test-*/**/*\" \"contracts/**/*\" ./", "prepublishOnly": "yarn copyfiles -u 1 -e \"**/test-*/**/*\" \"contracts/**/*\" ./",
"postpublish": "rimraf chugsplash L1 L2 libraries standards", "postpublish": "rimraf chugsplash L1 L2 libraries standards",
"prepack": "yarn prepublishOnly", "prepack": "yarn prepublishOnly",
...@@ -88,7 +87,6 @@ ...@@ -88,7 +87,6 @@
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
...@@ -16,7 +16,7 @@ interface DeploymentInfo { ...@@ -16,7 +16,7 @@ interface DeploymentInfo {
const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [ const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [
{ {
folder: 'mainnet', folder: 'mainnet',
name: 'Optimistic Ethereum (mainnet)', name: 'Optimism (mainnet)',
chainid: 10, chainid: 10,
rpc: 'https://mainnet.optimism.io', rpc: 'https://mainnet.optimism.io',
l1Explorer: 'https://etherscan.io', l1Explorer: 'https://etherscan.io',
...@@ -24,7 +24,7 @@ const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [ ...@@ -24,7 +24,7 @@ const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [
}, },
{ {
folder: 'kovan', folder: 'kovan',
name: 'Optimistic Kovan (public testnet)', name: 'Optimism Kovan (public testnet)',
chainid: 69, chainid: 69,
rpc: 'https://kovan.optimism.io', rpc: 'https://kovan.optimism.io',
l1Explorer: 'https://kovan.etherscan.io', l1Explorer: 'https://kovan.etherscan.io',
...@@ -32,9 +32,9 @@ const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [ ...@@ -32,9 +32,9 @@ const PUBLIC_DEPLOYMENTS: DeploymentInfo[] = [
}, },
{ {
folder: 'goerli', folder: 'goerli',
name: 'Optimistic Goerli (internal devnet)', name: 'Optimism Goerli (internal devnet)',
chainid: 420, chainid: 420,
notice: `Optimistic Goerli is an internal Optimism development network. You're probably looking for [Optimistic Kovan](../kovan#readme), the public Optimistic Ethereum testnet.`, notice: `Optimism Goerli is an internal Optimism development network. You're probably looking for [Optimism Kovan](../kovan#readme), the public Optimism testnet.`,
l1Explorer: 'https://goerli.etherscan.io', l1Explorer: 'https://goerli.etherscan.io',
}, },
] ]
...@@ -221,7 +221,7 @@ const main = async () => { ...@@ -221,7 +221,7 @@ const main = async () => {
} }
let primary = `` let primary = ``
primary = addline(primary, `# Optimistic Ethereum Deployments`) primary = addline(primary, `# Optimism Deployments`)
for (const deployment of PUBLIC_DEPLOYMENTS) { for (const deployment of PUBLIC_DEPLOYMENTS) {
primary = addline( primary = addline(
primary, primary,
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "ts-mocha test/*.spec.ts", "test": "ts-mocha test/*.spec.ts",
...@@ -49,7 +49,6 @@ ...@@ -49,7 +49,6 @@
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
## What is this? ## What is this?
The Optimistic Ethereum Data Transport Layer is a long-running software service (written in TypeScript) designed to reliably index Optimistic Ethereum transaction data from Layer 1 (Ethereum). Specifically, this service indexes: The Optimism Data Transport Layer is a long-running software service (written in TypeScript) designed to reliably index Optimism transaction data from Layer 1 (Ethereum). Specifically, this service indexes:
* Transactions that have been enqueued for submission to the CanonicalTransactionChain via [`CanonicalTransactionChain.enqueue`]. * Transactions that have been enqueued for submission to the CanonicalTransactionChain via [`CanonicalTransactionChain.enqueue`].
* Transactions that have been included in the CanonicalTransactionChain via [`CanonicalTransactionChain.appendQueueBatch`] or [`CanonicalTransactionChain.appendSequencerBatch`]. * Transactions that have been included in the CanonicalTransactionChain via [`CanonicalTransactionChain.appendQueueBatch`] or [`CanonicalTransactionChain.appendSequencerBatch`].
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
"clean:db": "rimraf ./db", "clean:db": "rimraf ./db",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"start": "ts-node ./src/services/run.ts", "start": "ts-node ./src/services/run.ts",
"start:local": "ts-node ./src/services/run.ts | pino-pretty", "start:local": "ts-node ./src/services/run.ts | pino-pretty",
"test": "hardhat --config test/config/hardhat.config.ts test", "test": "hardhat --config test/config/hardhat.config.ts test",
...@@ -74,7 +74,6 @@ ...@@ -74,7 +74,6 @@
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
...@@ -167,7 +167,7 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> { ...@@ -167,7 +167,7 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> {
startingL1BlockNumber = this.options.l1StartHeight startingL1BlockNumber = this.options.l1StartHeight
} else { } else {
this.logger.info( this.logger.info(
'Attempting to find an appropriate L1 block height to begin sync...' 'Attempting to find an appropriate L1 block height to begin sync. This may take a long time.'
) )
startingL1BlockNumber = await this._findStartingL1BlockNumber() startingL1BlockNumber = await this._findStartingL1BlockNumber()
} }
...@@ -453,12 +453,18 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> { ...@@ -453,12 +453,18 @@ export class L1IngestionService extends BaseService<L1IngestionServiceOptions> {
private async _findStartingL1BlockNumber(): Promise<number> { private async _findStartingL1BlockNumber(): Promise<number> {
const currentL1Block = await this.state.l1RpcProvider.getBlockNumber() const currentL1Block = await this.state.l1RpcProvider.getBlockNumber()
const filter =
this.state.contracts.Lib_AddressManager.filters.OwnershipTransferred()
for (let i = 0; i < currentL1Block; i += 2000) {
const start = i
const end = Math.min(i + 2000, currentL1Block)
this.logger.info(`Searching for ${filter} from ${start} to ${end}`)
for (let i = 0; i < currentL1Block; i += 1000000) {
const events = await this.state.contracts.Lib_AddressManager.queryFilter( const events = await this.state.contracts.Lib_AddressManager.queryFilter(
this.state.contracts.Lib_AddressManager.filters.OwnershipTransferred(), filter,
i, start,
Math.min(i + 1000000, currentL1Block) end
) )
if (events.length > 0) { if (events.length > 0) {
......
...@@ -121,7 +121,7 @@ export class L2IngestionService extends BaseService<L2IngestionServiceOptions> { ...@@ -121,7 +121,7 @@ export class L2IngestionService extends BaseService<L2IngestionServiceOptions> {
} }
this.logger.info( this.logger.info(
'Synchronizing unconfirmed transactions from Layer 2 (Optimistic Ethereum)', 'Synchronizing unconfirmed transactions from Layer 2 (Optimism)',
{ {
fromBlock: highestSyncedL2BlockNumber, fromBlock: highestSyncedL2BlockNumber,
toBlock: targetL2Block, toBlock: targetL2Block,
......
# @eth-optimism/message-relayer # @eth-optimism/message-relayer
## 0.2.11
### Patch Changes
- 3a673322: Removed old node.js service running script
## 0.2.10 ## 0.2.10
### Patch Changes ### Patch Changes
......
#!/usr/bin/env node
const main = require('../dist/exec/run').default
;(async () => {
await main()
})().catch((err) => {
console.log(err)
process.exit(1)
})
{ {
"name": "@eth-optimism/message-relayer", "name": "@eth-optimism/message-relayer",
"version": "0.2.10", "version": "0.2.11",
"description": "[Optimism] Service for automatically relaying L2 to L1 transactions", "description": "[Optimism] Service for automatically relaying L2 to L1 transactions",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
...@@ -11,13 +11,13 @@ ...@@ -11,13 +11,13 @@
"withdraw": "./src/exec/withdraw.ts" "withdraw": "./src/exec/withdraw.ts"
}, },
"scripts": { "scripts": {
"start": "node ./exec/run-message-relayer.js", "start": "ts-node ./src/exec/run.ts",
"build": "tsc -p ./tsconfig.build.json", "build": "tsc -p ./tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"test": "hardhat test --show-stack-traces", "test": "hardhat test --show-stack-traces",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json" "test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
}, },
...@@ -59,7 +59,6 @@ ...@@ -59,7 +59,6 @@
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
...@@ -72,6 +71,7 @@ ...@@ -72,6 +71,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mocha": "^8.4.0", "mocha": "^8.4.0",
"prettier": "^2.3.1", "prettier": "^2.3.1",
"ts-node": "^10.0.0",
"typescript": "^4.3.5" "typescript": "^4.3.5"
} }
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo", "clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test:surgery": "ts-mocha --timeout 50000000 test/*", "test:surgery": "ts-mocha --timeout 50000000 test/*",
"start": "ts-node ./scripts/surgery.ts" "start": "ts-node ./scripts/surgery.ts"
......
...@@ -68,7 +68,7 @@ describe('EOAs', () => { ...@@ -68,7 +68,7 @@ describe('EOAs', () => {
// eslint-disable-next-line // eslint-disable-next-line
before(function() { before(function() {
if (env.surgeryDataSources.configs.l2NetworkName === 'kovan') { if (env.surgeryDataSources.configs.l2NetworkName === 'kovan') {
console.log('1inch deployer does not exist on optimistic kovan') console.log('1inch deployer does not exist on Optimism Kovan')
this.skip() this.skip()
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo", "clean": "rimraf ./dist ./tsconfig.build.tsbuildinfo",
"lint": "yarn run lint:fix && yarn run lint:check", "lint": "yarn run lint:fix && yarn run lint:check",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "ts-mocha test/*.spec.ts", "test": "ts-mocha test/*.spec.ts",
......
...@@ -2,7 +2,14 @@ ...@@ -2,7 +2,14 @@
# @eth-optimism/sdk # @eth-optimism/sdk
The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimistic Ethereum. The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimism.
## NOTICE
WARNING: This package is currently under construction.
You can definitely try to use it, but you probably won't have a good time.
Lots of pieces are missing.
We will announce the 1.0.0 release on Discord and on Twitter once it's ready, keep an eye out!
## Installation ## Installation
......
{ {
"name": "@eth-optimism/sdk", "name": "@eth-optimism/sdk",
"version": "0.0.3", "version": "0.0.3",
"description": "[Optimism] Tools for working with Optimistic Ethereum", "description": "[Optimism] Tools for working with Optimism",
"main": "dist/index", "main": "dist/index",
"types": "dist/index", "types": "dist/index",
"files": [ "files": [
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
"build": "tsc -p tsconfig.build.json", "build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo", "clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check", "lint": "yarn lint:fix && yarn lint:check",
"lint:check": "eslint .", "lint:check": "eslint . --max-warnings=0",
"lint:fix": "yarn lint:check --fix", "lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"test": "hardhat test", "test": "hardhat test",
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2", "eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
......
This diff is collapsed.
export * from './interfaces' export * from './interfaces'
export * from './utils' export * from './utils'
export * from './cross-chain-provider'
...@@ -11,6 +11,7 @@ import { ...@@ -11,6 +11,7 @@ import {
TokenBridgeMessage, TokenBridgeMessage,
OEContracts, OEContracts,
MessageReceipt, MessageReceipt,
CustomBridges,
} from './types' } from './types'
/** /**
...@@ -34,14 +35,14 @@ export interface ICrossChainProvider { ...@@ -34,14 +35,14 @@ export interface ICrossChainProvider {
l1ChainId: number l1ChainId: number
/** /**
* Chain ID for the L2 network. * Contract objects attached to their respective providers and addresses.
*/ */
l2ChainId: number contracts: OEContracts
/** /**
* Contract objects attached to their respective providers and addresses. * List of custom bridges for the given network.
*/ */
contracts: OEContracts bridges: CustomBridges
/** /**
* Retrieves all cross chain messages sent within a given transaction. * Retrieves all cross chain messages sent within a given transaction.
...@@ -85,7 +86,7 @@ export interface ICrossChainProvider { ...@@ -85,7 +86,7 @@ export interface ICrossChainProvider {
/** /**
* Finds all cross chain messages that correspond to token deposits or withdrawals sent by a * Finds all cross chain messages that correspond to token deposits or withdrawals sent by a
* particular address. Useful for finding deposits/withdrawals because the sender of the message * particular address. Useful for finding deposits/withdrawals because the sender of the message
* will appear to be the StandardBridge contract and not the actual end user. Returns * will appear to be the StandardBridge contract and not the actual end user.
* *
* @param address Address to search for messages from. * @param address Address to search for messages from.
* @param opts Options object. * @param opts Options object.
...@@ -106,6 +107,56 @@ export interface ICrossChainProvider { ...@@ -106,6 +107,56 @@ export interface ICrossChainProvider {
} }
): Promise<TokenBridgeMessage[]> ): Promise<TokenBridgeMessage[]>
/**
* Alias for getTokenBridgeMessagesByAddress with a drection of L1_TO_L2.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All deposit token bridge messages sent by the given address.
*/
getDepositsByAddress(
address: AddressLike,
opts?: {
fromBlock?: BlockTag
toBlock?: BlockTag
}
): Promise<TokenBridgeMessage[]>
/**
* Alias for getTokenBridgeMessagesByAddress with a drection of L2_TO_L1.
*
* @param address Address to search for messages from.
* @param opts Options object.
* @param opts.fromBlock Block to start searching for messages from. If not provided, will start
* from the first block (block #0).
* @param opts.toBlock Block to stop searching for messages at. If not provided, will stop at the
* latest known block ("latest").
* @returns All withdrawal token bridge messages sent by the given address.
*/
getWithdrawalsByAddress(
address: AddressLike,
opts?: {
fromBlock?: BlockTag
toBlock?: BlockTag
}
): Promise<TokenBridgeMessage[]>
/**
* Resolves a MessageLike into a CrossChainMessage object.
* Unlike other coercion functions, this function is stateful and requires making additional
* requests. For now I'm going to keep this function here, but we could consider putting a
* similar function inside of utils/coercion.ts if people want to use this without having to
* create an entire CrossChainProvider object.
*
* @param message MessageLike to resolve into a CrossChainMessage.
* @returns Message coerced into a CrossChainMessage.
*/
toCrossChainMessage(message: MessageLike): Promise<CrossChainMessage>
/** /**
* Retrieves the status of a particular message as an enum. * Retrieves the status of a particular message as an enum.
* *
...@@ -129,9 +180,9 @@ export interface ICrossChainProvider { ...@@ -129,9 +180,9 @@ export interface ICrossChainProvider {
* *
* @param message Message to wait for. * @param message Message to wait for.
* @param opts Options to pass to the waiting function. * @param opts Options to pass to the waiting function.
* - `confirmations` (number): Number of transaction confirmations to wait for before returning. * @param opts.confirmations Number of transaction confirmations to wait for before returning.
* - `pollIntervalMs` (number): Number of milliseconds to wait between polling for the receipt. * @param opts.pollIntervalMs Number of milliseconds to wait between polling for the receipt.
* - `loopsBeforeTimeout` (number): Number of times to poll before timing out. * @param opts.timeoutMs Milliseconds to wait before timing out.
* @returns CrossChainMessage receipt including receipt of the transaction that relayed the * @returns CrossChainMessage receipt including receipt of the transaction that relayed the
* given message. * given message.
*/ */
...@@ -140,7 +191,7 @@ export interface ICrossChainProvider { ...@@ -140,7 +191,7 @@ export interface ICrossChainProvider {
opts?: { opts?: {
confirmations?: number confirmations?: number
pollIntervalMs?: number pollIntervalMs?: number
loopsBeforeTimeout?: number timeoutMs?: number
} }
): Promise<MessageReceipt> ): Promise<MessageReceipt>
......
...@@ -7,35 +7,87 @@ import { Signer } from '@ethersproject/abstract-signer' ...@@ -7,35 +7,87 @@ import { Signer } from '@ethersproject/abstract-signer'
import { Contract, BigNumber, Overrides } from 'ethers' import { Contract, BigNumber, Overrides } from 'ethers'
/** /**
* Represents Optimistic Ethereum contracts, assumed to be connected to their appropriate * L1 contract references.
*/
export interface OEL1Contracts {
AddressManager: Contract
L1CrossDomainMessenger: Contract
L1StandardBridge: Contract
StateCommitmentChain: Contract
CanonicalTransactionChain: Contract
BondManager: Contract
}
/**
* L2 contract references.
*/
export interface OEL2Contracts {
L2CrossDomainMessenger: Contract
L2StandardBridge: Contract
OVM_L1BlockNumber: Contract
OVM_L2ToL1MessagePasser: Contract
OVM_DeployerWhitelist: Contract
OVM_ETH: Contract
OVM_GasPriceOracle: Contract
OVM_SequencerFeeVault: Contract
WETH: Contract
}
/**
* Represents Optimism contracts, assumed to be connected to their appropriate
* providers and addresses. * providers and addresses.
*/ */
export interface OEContracts { export interface OEContracts {
/** l1: OEL1Contracts
* L1 contract references. l2: OEL2Contracts
*/ }
/**
* Convenience type for something that looks like the L1 OE contract interface but could be
* addresses instead of actual contract objects.
*/
export type OEL1ContractsLike = {
[K in keyof OEL1Contracts]: AddressLike
}
/**
* Convenience type for something that looks like the L2 OE contract interface but could be
* addresses instead of actual contract objects.
*/
export type OEL2ContractsLike = {
[K in keyof OEL2Contracts]: AddressLike
}
/**
* Convenience type for something that looks like the OE contract interface but could be
* addresses instead of actual contract objects.
*/
export interface OEContractsLike {
l1: OEL1ContractsLike
l2: OEL2ContractsLike
}
/**
* Represents list of custom bridges.
*/
export interface CustomBridges {
l1: { l1: {
AddressManager: Contract [name: string]: Contract
L1CrossDomainMessenger: Contract }
L1StandardBridge: Contract l2: {
StateCommitmentChain: Contract [name: string]: Contract
CanonicalTransactionChain: Contract
BondManager: Contract
} }
}
/** /**
* L2 contract references. * Something that looks like the list of custom bridges.
*/ */
export interface CustomBridgesLike {
l1: {
[K in keyof CustomBridges['l1']]: AddressLike
}
l2: { l2: {
L2CrossDomainMessenger: Contract [K in keyof CustomBridges['l2']]: AddressLike
L2StandardBridge: Contract
OVM_L1BlockNumber: Contract
OVM_L2ToL1MessagePasser: Contract
OVM_DeployerWhitelist: Contract
OVM_ETH: Contract
OVM_GasPriceOracle: Contract
OVM_SequencerFeeVault: Contract
WETH: Contract
} }
} }
...@@ -95,11 +147,9 @@ export interface CrossChainMessageRequest { ...@@ -95,11 +147,9 @@ export interface CrossChainMessageRequest {
} }
/** /**
* Describes a message that is sent between L1 and L2. Direction determines where the message was * Core components of a cross chain message.
* sent from and where it's being sent to.
*/ */
export interface CrossChainMessage { export interface CoreCrossChainMessage {
direction: MessageDirection
sender: string sender: string
target: string target: string
message: string message: string
...@@ -107,12 +157,15 @@ export interface CrossChainMessage { ...@@ -107,12 +157,15 @@ export interface CrossChainMessage {
} }
/** /**
* Convenience type for when you don't care which direction the message is going in. * Describes a message that is sent between L1 and L2. Direction determines where the message was
* sent from and where it's being sent to.
*/ */
export type DirectionlessCrossChainMessage = Omit< export interface CrossChainMessage extends CoreCrossChainMessage {
CrossChainMessage, direction: MessageDirection
'direction' logIndex: number
> blockNumber: number
transactionHash: string
}
/** /**
* Describes a token withdrawal or deposit, along with the underlying raw cross chain message * Describes a token withdrawal or deposit, along with the underlying raw cross chain message
...@@ -125,22 +178,24 @@ export interface TokenBridgeMessage { ...@@ -125,22 +178,24 @@ export interface TokenBridgeMessage {
l1Token: string l1Token: string
l2Token: string l2Token: string
amount: BigNumber amount: BigNumber
raw: CrossChainMessage data: string
logIndex: number
blockNumber: number
transactionHash: string
} }
/** /**
* Enum describing the status of a CrossDomainMessage message receipt. * Enum describing the status of a CrossDomainMessage message receipt.
*/ */
export enum MessageReceiptStatus { export enum MessageReceiptStatus {
RELAYED_SUCCEEDED,
RELAYED_FAILED, RELAYED_FAILED,
RELAYED_SUCCEEDED,
} }
/** /**
* CrossDomainMessage receipt. * CrossDomainMessage receipt.
*/ */
export interface MessageReceipt { export interface MessageReceipt {
messageHash: string
receiptStatus: MessageReceiptStatus receiptStatus: MessageReceiptStatus
transactionReceipt: TransactionReceipt transactionReceipt: TransactionReceipt
} }
...@@ -164,13 +219,6 @@ export interface StateRootBatch { ...@@ -164,13 +219,6 @@ export interface StateRootBatch {
stateRoots: string[] stateRoots: string[]
} }
/**
* Utility type for deep partials.
*/
export type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>
}
/** /**
* Extended Ethers overrides object with an l2GasLimit field. * Extended Ethers overrides object with an l2GasLimit field.
* Only meant to be used for L1 to L2 messages, since L2 to L1 messages don't have a specified gas * Only meant to be used for L1 to L2 messages, since L2 to L1 messages don't have a specified gas
......
...@@ -4,46 +4,13 @@ import { ...@@ -4,46 +4,13 @@ import {
TransactionReceipt, TransactionReceipt,
TransactionResponse, TransactionResponse,
} from '@ethersproject/abstract-provider' } from '@ethersproject/abstract-provider'
import { getContractInterface } from '@eth-optimism/contracts' import { ethers, BigNumber } from 'ethers'
import { ethers } from 'ethers'
import { import {
ProviderLike, ProviderLike,
TransactionLike, TransactionLike,
DirectionlessCrossChainMessage, NumberLike,
} from './interfaces' AddressLike,
} from '../interfaces'
/**
* Returns the canonical encoding of a cross chain message. This encoding is used in various
* locations within the Optimistic Ethereum smart contracts.
*
* @param message Cross chain message to encode.
* @returns Canonical encoding of the message.
*/
export const encodeCrossChainMessage = (
message: DirectionlessCrossChainMessage
): string => {
return getContractInterface('L2CrossDomainMessenger').encodeFunctionData(
'relayMessage',
[message.target, message.sender, message.message, message.messageNonce]
)
}
/**
* Returns the canonical hash of a cross chain message. This hash is used in various locations
* within the Optimistic Ethereum smart contracts and is the keccak256 hash of the result of
* encodeCrossChainMessage.
*
* @param message Cross chain message to hash.
* @returns Canonical hash of the message.
*/
export const hashCrossChainMessage = (
message: DirectionlessCrossChainMessage
): string => {
return ethers.utils.solidityKeccak256(
['bytes'],
[encodeCrossChainMessage(message)]
)
}
/** /**
* Converts a ProviderLike into a provider. Assumes that if the ProviderLike is a string then * Converts a ProviderLike into a provider. Assumes that if the ProviderLike is a string then
...@@ -84,3 +51,29 @@ export const toTransactionHash = (transaction: TransactionLike): string => { ...@@ -84,3 +51,29 @@ export const toTransactionHash = (transaction: TransactionLike): string => {
throw new Error('Invalid transaction') throw new Error('Invalid transaction')
} }
} }
/**
* Converts a number-like into an ethers BigNumber.
*
* @param num Number-like to convert into a BigNumber.
* @returns Number-like as a BigNumber.
*/
export const toBigNumber = (num: NumberLike): BigNumber => {
return ethers.BigNumber.from(num)
}
/**
* Converts an address-like into a 0x-prefixed address string.
*
* @param addr Address-like to convert into an address.
* @returns Address-like as an address.
*/
export const toAddress = (addr: AddressLike): string => {
if (typeof addr === 'string') {
assert(ethers.utils.isAddress(addr), 'Invalid address')
return ethers.utils.getAddress(addr)
} else {
assert(ethers.utils.isAddress(addr.address), 'Invalid address')
return ethers.utils.getAddress(addr.address)
}
}
This diff is collapsed.
export * from './coercion'
export * from './contracts'
export * from './message-encoding'
export * from './type-utils'
export * from './misc-utils'
import { getContractInterface } from '@eth-optimism/contracts'
import { ethers } from 'ethers'
import { CoreCrossChainMessage } from '../interfaces'
/**
* Returns the canonical encoding of a cross chain message. This encoding is used in various
* locations within the Optimism smart contracts.
*
* @param message Cross chain message to encode.
* @returns Canonical encoding of the message.
*/
export const encodeCrossChainMessage = (
message: CoreCrossChainMessage
): string => {
return getContractInterface('L2CrossDomainMessenger').encodeFunctionData(
'relayMessage',
[message.target, message.sender, message.message, message.messageNonce]
)
}
/**
* Returns the canonical hash of a cross chain message. This hash is used in various locations
* within the Optimism smart contracts and is the keccak256 hash of the result of
* encodeCrossChainMessage.
*
* @param message Cross chain message to hash.
* @returns Canonical hash of the message.
*/
export const hashCrossChainMessage = (
message: CoreCrossChainMessage
): string => {
return ethers.utils.solidityKeccak256(
['bytes'],
[encodeCrossChainMessage(message)]
)
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment