Commit b57ad006 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into felipe/configs

parents 22a0ee79 41c4c1c6
...@@ -1275,6 +1275,9 @@ workflows: ...@@ -1275,6 +1275,9 @@ workflows:
- go-lint: - go-lint:
name: op-proposer-lint name: op-proposer-lint
module: op-proposer module: op-proposer
- go-lint:
name: op-challenger-lint
module: op-challenger
- go-lint: - go-lint:
name: op-program-lint name: op-program-lint
module: op-program module: op-program
...@@ -1300,6 +1303,9 @@ workflows: ...@@ -1300,6 +1303,9 @@ workflows:
- go-test: - go-test:
name: op-proposer-tests name: op-proposer-tests
module: op-proposer module: op-proposer
- go-test:
name: op-challenger-tests
module: op-challenger
- go-test: - go-test:
name: op-program-tests name: op-program-tests
module: op-program module: op-program
...@@ -1322,6 +1328,7 @@ workflows: ...@@ -1322,6 +1328,7 @@ workflows:
- op-e2e-lint - op-e2e-lint
- op-node-lint - op-node-lint
- op-proposer-lint - op-proposer-lint
- op-challenger-lint
- op-program-lint - op-program-lint
- op-service-lint - op-service-lint
- op-batcher-tests - op-batcher-tests
...@@ -1329,6 +1336,7 @@ workflows: ...@@ -1329,6 +1336,7 @@ workflows:
- op-chain-ops-tests - op-chain-ops-tests
- op-node-tests - op-node-tests
- op-proposer-tests - op-proposer-tests
- op-challenger-tests
- op-program-tests - op-program-tests
- op-service-tests - op-service-tests
- op-e2e-WS-tests - op-e2e-WS-tests
...@@ -1389,6 +1397,20 @@ workflows: ...@@ -1389,6 +1397,20 @@ workflows:
context: context:
- oplabs-gcr - oplabs-gcr
platforms: "linux/amd64,linux/arm64" platforms: "linux/amd64,linux/arm64"
- docker-build:
name: op-challenger-docker-build
docker_file: op-challenger/Dockerfile
docker_name: op-challenger
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
docker_context: .
- docker-publish:
name: op-challenger-docker-publish
docker_file: op-challenger/Dockerfile
docker_name: op-challenger
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
context:
- oplabs-gcr
platforms: "linux/amd64,linux/arm64"
- docker-build: - docker-build:
name: op-heartbeat-docker-build name: op-heartbeat-docker-build
docker_file: op-heartbeat/Dockerfile docker_file: op-heartbeat/Dockerfile
...@@ -1431,6 +1453,7 @@ workflows: ...@@ -1431,6 +1453,7 @@ workflows:
- op-node-docker-build - op-node-docker-build
- op-batcher-docker-build - op-batcher-docker-build
- op-proposer-docker-build - op-proposer-docker-build
- op-challenger-docker-build
- hive-test: - hive-test:
name: hive-test-p2p name: hive-test-p2p
version: <<pipeline.git.revision>> version: <<pipeline.git.revision>>
...@@ -1439,6 +1462,7 @@ workflows: ...@@ -1439,6 +1462,7 @@ workflows:
- op-node-docker-build - op-node-docker-build
- op-batcher-docker-build - op-batcher-docker-build
- op-proposer-docker-build - op-proposer-docker-build
- op-challenger-docker-build
- hive-test: - hive-test:
name: hive-test-l1ops name: hive-test-l1ops
version: <<pipeline.git.revision>> version: <<pipeline.git.revision>>
...@@ -1447,6 +1471,7 @@ workflows: ...@@ -1447,6 +1471,7 @@ workflows:
- op-node-docker-build - op-node-docker-build
- op-batcher-docker-build - op-batcher-docker-build
- op-proposer-docker-build - op-proposer-docker-build
- op-challenger-docker-build
release: release:
jobs: jobs:
- hold: - hold:
...@@ -1504,6 +1529,22 @@ workflows: ...@@ -1504,6 +1529,22 @@ workflows:
- oplabs-gcr-release - oplabs-gcr-release
requires: requires:
- hold - hold
- docker-release:
name: op-challenger-docker-release
filters:
tags:
only: /^op-challenger\/v.*/
branches:
ignore: /.*/
docker_file: op-challenger/Dockerfile
docker_name: op-challenger
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
docker_context: .
platforms: "linux/amd64,linux/arm64"
context:
- oplabs-gcr-release
requires:
- hold
- docker-build: - docker-build:
name: op-migrate-docker-release name: op-migrate-docker-release
filters: filters:
......
...@@ -40,6 +40,10 @@ op-proposer: ...@@ -40,6 +40,10 @@ op-proposer:
make -C ./op-proposer op-proposer make -C ./op-proposer op-proposer
.PHONY: op-proposer .PHONY: op-proposer
op-challenger:
make -C ./op-challenger op-challenger
.PHONY: op-challenger
op-program: op-program:
make -C ./op-program op-program make -C ./op-program op-program
.PHONY: op-program .PHONY: op-program
......
FROM --platform=$BUILDPLATFORM golang:1.19.0-alpine3.15 as builder
ARG VERSION=v0.0.0
RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash
# build op-challenger with the shared go.mod & go.sum files
COPY ./op-challenger /app/op-challenger
COPY ./op-bindings /app/op-bindings
COPY ./op-node /app/op-node
COPY ./op-service /app/op-service
COPY ./op-signer /app/op-signer
COPY ./go.mod /app/go.mod
COPY ./go.sum /app/go.sum
COPY ./.git /app/.git
WORKDIR /app/op-challenger
RUN go mod download
ARG TARGETOS TARGETARCH
RUN make op-challenger VERSION="$VERSION" GOOS=$TARGETOS GOARCH=$TARGETARCH
FROM alpine:3.15
COPY --from=builder /app/op-challenger/bin/op-challenger /usr/local/bin
CMD ["op-challenger"]
GITCOMMIT := $(shell git rev-parse HEAD)
GITDATE := $(shell git show -s --format='%ct')
VERSION := v0.0.0
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
LDFLAGSSTRING +=-X main.Version=$(VERSION)
LDFLAGS := -ldflags "$(LDFLAGSSTRING)"
op-challenger:
env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/op-challenger ./cmd
clean:
rm bin/op-challenger
test:
go test -v ./...
lint:
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint -e "errors.As" -e "errors.Is"
.PHONY: \
clean \
op-challenger \
test \
lint
# op-challenger
The `op-challenger` is a modular **op-stack** challenge agent
written in golang for dispute games including, but not limited to, attestation games, fault
games, and validity games. To learn more about dispute games, visit the
[dispute game specs](../specs/dispute-game.md).
## Quickstart
First, clone this repo. Then, run `make`, which will build all required targets.
Alternatively, run `make devnet` to bring up the [devnet](../ops-bedrock/devnet-up.sh)
which deploys the [mock dispute game contracts](./contracts) as well as an
`op-challenger` instance.
Alternatively, you can build the `op-challenger` binary locally using the pre-configured
[Makefile](./Makefile) target by running `make build`, and then running `./op-challenger --help`
to see a list of available options.
## Usage
`op-challenger` is configurable via command line flags and environment variables. The help menu
shows the available config options and can be accessed by running `./op-challenger --help`.
Note that there are many global options, but the most important ones are:
- `OP_CHALLENGER_L1_ETH_RPC`: An L1 Ethereum RPC URL
- `OP_CHALLENGER_ROLLUP_RPC`: A Rollup Node RPC URL
- `OP_CHALLENGER_L2OO_ADDRESS`: The L2OutputOracle Contract Address
- `OP_CHALLENGER_DGF_ADDRESS`: Dispute Game Factory Contract Address
Here is a reduced output from running `./op-challenger --help`:
```bash
NAME:
op-challenger - Modular Challenger Agent
USAGE:
main [global options] command [command options] [arguments...]
VERSION:
1.0.0
DESCRIPTION:
A modular op-stack challenge agent for output dispute games written in golang.
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--l1-eth-rpc value HTTP provider URL for L1. [$OP_CHALLENGER_L1_ETH_RPC]
--rollup-rpc value HTTP provider URL for the rollup node. [$OP_CHALLENGER_ROLLUP_RPC]
--l2oo-address value Address of the L2OutputOracle contract. [$OP_CHALLENGER_L2OO_ADDRESS]
--dgf-address value Address of the DisputeGameFactory contract. [$OP_CHALLENGER_DGF_ADDRESS]
...
--help, -h show help
--version, -v print the version
```
package main
import (
"os"
flags "github.com/ethereum-optimism/optimism/op-challenger/flags"
log "github.com/ethereum/go-ethereum/log"
cli "github.com/urfave/cli"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
)
const Version = "0.1.0"
func main() {
oplog.SetupDefaults()
app := cli.NewApp()
app.Flags = flags.Flags
app.Version = Version
app.Name = "op-challenger"
app.Usage = "Challenge invalid L2OutputOracle outputs"
app.Description = "A modular op-stack challenge agent for dispute games written in golang."
app.Action = func(ctx *cli.Context) error {
log.Debug("Challenger not implemented...")
return nil
}
err := app.Run(os.Args)
if err != nil {
log.Crit("Application failed", "message", err)
}
}
package flags
import (
"fmt"
"github.com/urfave/cli"
opservice "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc "github.com/ethereum-optimism/optimism/op-service/rpc"
txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
)
const envVarPrefix = "OP_CHALLENGER"
var (
// Required Flags
L1EthRpcFlag = cli.StringFlag{
Name: "l1-eth-rpc",
Usage: "HTTP provider URL for L1.",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "L1_ETH_RPC"),
}
RollupRpcFlag = cli.StringFlag{
Name: "rollup-rpc",
Usage: "HTTP provider URL for the rollup node.",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "ROLLUP_RPC"),
}
L2OOAddressFlag = cli.StringFlag{
Name: "l2oo-address",
Usage: "Address of the L2OutputOracle contract.",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "L2OO_ADDRESS"),
}
DGFAddressFlag = cli.StringFlag{
Name: "dgf-address",
Usage: "Address of the DisputeGameFactory contract.",
EnvVar: opservice.PrefixEnvVar(envVarPrefix, "DGF_ADDRESS"),
}
)
// requiredFlags are checked by [CheckRequired]
var requiredFlags = []cli.Flag{
L1EthRpcFlag,
RollupRpcFlag,
L2OOAddressFlag,
DGFAddressFlag,
}
// optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{}
func init() {
optionalFlags = append(optionalFlags, oprpc.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, oplog.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, opmetrics.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, oppprof.CLIFlags(envVarPrefix)...)
optionalFlags = append(optionalFlags, txmgr.CLIFlags(envVarPrefix)...)
Flags = append(requiredFlags, optionalFlags...)
}
// Flags contains the list of configuration options available to the binary.
var Flags []cli.Flag
func CheckRequired(ctx *cli.Context) error {
for _, f := range requiredFlags {
if !ctx.GlobalIsSet(f.GetName()) {
return fmt.Errorf("flag %s is required", f.GetName())
}
}
return nil
}
...@@ -78,6 +78,11 @@ func TestNetwork(t *testing.T) { ...@@ -78,6 +78,11 @@ func TestNetwork(t *testing.T) {
name := name name := name
expected := cfg expected := cfg
t.Run("Network_"+name, func(t *testing.T) { t.Run("Network_"+name, func(t *testing.T) {
// TODO(CLI-3936) Re-enable test for other networks once bedrock migration is complete
if name != "goerli" {
t.Skipf("Not requiring chain config for network %s", name)
return
}
args := replaceRequiredArg("--network", name) args := replaceRequiredArg("--network", name)
cfg := configForArgs(t, args) cfg := configForArgs(t, args)
require.Equal(t, expected, *cfg.Rollup) require.Equal(t, expected, *cfg.Rollup)
......
...@@ -34,14 +34,10 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants { ...@@ -34,14 +34,10 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants {
address[] internal approvals; address[] internal approvals;
/** /**
* @notice The entrypoint to this script. * -----------------------------------------------------------
* Virtual Functions
* -----------------------------------------------------------
*/ */
function run(address _safe, address _proxyAdmin) public returns (bool) {
vm.startBroadcast();
bool success = _run(_safe, _proxyAdmin);
if (success) _postCheck();
return success;
}
/** /**
* @notice Follow up assertions to ensure that the script ran to completion. * @notice Follow up assertions to ensure that the script ran to completion.
...@@ -56,7 +52,30 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants { ...@@ -56,7 +52,30 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants {
/** /**
* @notice Internal helper function to compute the safe transaction hash. * @notice Internal helper function to compute the safe transaction hash.
*/ */
function _getTransactionHash(address _safe, address _proxyAdmin) internal returns (bytes32) { function computeSafeTransactionHash(address _safe, address _proxyAdmin) public virtual returns (bytes32) {
return _getTransactionHash(_safe, _proxyAdmin);
}
/**
* -----------------------------------------------------------
* Implemented Functions
* -----------------------------------------------------------
*/
/**
* @notice The entrypoint to this script.
*/
function run(address _safe, address _proxyAdmin) public returns (bool) {
vm.startBroadcast();
bool success = _run(_safe, _proxyAdmin);
if (success) _postCheck();
return success;
}
/**
* @notice Computes the safe transaction hash for the provided safe and proxy admin.
*/
function _getTransactionHash(address _safe, address _proxyAdmin) internal view returns (bytes32) {
// Ensure that the required contracts exist // Ensure that the required contracts exist
require(address(multicall).code.length > 0, "multicall3 not deployed"); require(address(multicall).code.length > 0, "multicall3 not deployed");
require(_safe.code.length > 0, "no code at safe address"); require(_safe.code.length > 0, "no code at safe address");
...@@ -84,7 +103,6 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants { ...@@ -84,7 +103,6 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants {
return hash; return hash;
} }
/** /**
* @notice The implementation of the upgrade. Split into its own function * @notice The implementation of the upgrade. Split into its own function
* to allow for testability. This is subject to a race condition if * to allow for testability. This is subject to a race condition if
...@@ -189,6 +207,5 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants { ...@@ -189,6 +207,5 @@ abstract contract SafeBuilder is EnhancedScript, GlobalConstants {
} }
return signatures; return signatures;
} }
} }
...@@ -115,24 +115,24 @@ contract PostSherlockL1 is SafeBuilder { ...@@ -115,24 +115,24 @@ contract PostSherlockL1 is SafeBuilder {
* could be added. * could be added.
*/ */
function test_script_succeeds() skipWhenNotForking external { function test_script_succeeds() skipWhenNotForking external {
address safe; address _safe;
address proxyAdmin; address _proxyAdmin;
if (block.chainid == GOERLI) { if (block.chainid == GOERLI) {
safe = 0xBc1233d0C3e6B5d53Ab455cF65A6623F6dCd7e4f; _safe = 0xBc1233d0C3e6B5d53Ab455cF65A6623F6dCd7e4f;
proxyAdmin = 0x01d3670863c3F4b24D7b107900f0b75d4BbC6e0d; _proxyAdmin = 0x01d3670863c3F4b24D7b107900f0b75d4BbC6e0d;
// Set the proxy admin for the `_postCheck` function // Set the proxy admin for the `_postCheck` function
PROXY_ADMIN = ProxyAdmin(proxyAdmin); PROXY_ADMIN = ProxyAdmin(_proxyAdmin);
} }
require(safe != address(0) && proxyAdmin != address(0)); require(_safe != address(0) && _proxyAdmin != address(0));
address[] memory owners = IGnosisSafe(payable(safe)).getOwners(); address[] memory owners = IGnosisSafe(payable(_safe)).getOwners();
for (uint256 i; i < owners.length; i++) { for (uint256 i; i < owners.length; i++) {
address owner = owners[i]; address owner = owners[i];
vm.startBroadcast(owner); vm.startBroadcast(owner);
bool success = _run(safe, proxyAdmin); bool success = _run(_safe, _proxyAdmin);
vm.stopBroadcast(); vm.stopBroadcast();
if (success) { if (success) {
......
...@@ -3,7 +3,7 @@ pragma solidity 0.8.15; ...@@ -3,7 +3,7 @@ pragma solidity 0.8.15;
import { console } from "forge-std/console.sol"; import { console } from "forge-std/console.sol";
import { SafeBuilder } from "../universal/SafeBuilder.sol"; import { SafeBuilder } from "../universal/SafeBuilder.sol";
import { IGnosisSafe, Enum } from "../libraries/IGnosisSafe.sol"; import { IGnosisSafe, Enum } from "../interfaces/IGnosisSafe.sol";
import { IMulticall3 } from "forge-std/interfaces/IMulticall3.sol"; import { IMulticall3 } from "forge-std/interfaces/IMulticall3.sol";
import { Predeploys } from "../../contracts/libraries/Predeploys.sol"; import { Predeploys } from "../../contracts/libraries/Predeploys.sol";
import { ProxyAdmin } from "../../contracts/universal/ProxyAdmin.sol"; import { ProxyAdmin } from "../../contracts/universal/ProxyAdmin.sol";
...@@ -131,22 +131,22 @@ contract PostSherlockL2 is SafeBuilder { ...@@ -131,22 +131,22 @@ contract PostSherlockL2 is SafeBuilder {
* could be added. * could be added.
*/ */
function test_script_succeeds() skipWhenNotForking external { function test_script_succeeds() skipWhenNotForking external {
address safe; address _safe;
address proxyAdmin; address _proxyAdmin;
if (block.chainid == OP_GOERLI) { if (block.chainid == OP_GOERLI) {
safe = 0xE534ccA2753aCFbcDBCeB2291F596fc60495257e; _safe = 0xE534ccA2753aCFbcDBCeB2291F596fc60495257e;
proxyAdmin = 0x4200000000000000000000000000000000000018; _proxyAdmin = 0x4200000000000000000000000000000000000018;
} }
require(safe != address(0) && proxyAdmin != address(0)); require(_safe != address(0) && _proxyAdmin != address(0));
address[] memory owners = IGnosisSafe(payable(safe)).getOwners(); address[] memory owners = IGnosisSafe(payable(_safe)).getOwners();
for (uint256 i; i < owners.length; i++) { for (uint256 i; i < owners.length; i++) {
address owner = owners[i]; address owner = owners[i];
vm.startBroadcast(owner); vm.startBroadcast(owner);
bool success = _run(safe, proxyAdmin); bool success = _run(_safe, _proxyAdmin);
vm.stopBroadcast(); vm.stopBroadcast();
if (success) { if (success) {
......
...@@ -27,12 +27,6 @@ task('deposit-eth', 'Deposits ether to L2.') ...@@ -27,12 +27,6 @@ task('deposit-eth', 'Deposits ether to L2.')
'http://localhost:9545', 'http://localhost:9545',
types.string types.string
) )
.addParam(
'opNodeProviderUrl',
'op-node provider URL',
'http://localhost:7545',
types.string
)
.addOptionalParam('to', 'Recipient of the ether', '', types.string) .addOptionalParam('to', 'Recipient of the ether', '', types.string)
.addOptionalParam( .addOptionalParam(
'amount', 'amount',
......
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