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

Merge branch 'develop' into dependabot/npm_and_yarn/eslint-plugin-import-2.28.1

parents 0892c3e2 5c5e4e2f
...@@ -880,7 +880,7 @@ jobs: ...@@ -880,7 +880,7 @@ jobs:
patterns: indexer patterns: indexer
- run: - run:
name: Lint name: Lint
command: golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 2m -e "errors.As" -e "errors.Is" ./... command: golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 4m -e "errors.As" -e "errors.Is" ./...
working_directory: indexer working_directory: indexer
- run: - run:
name: install geth name: install geth
...@@ -1053,59 +1053,6 @@ jobs: ...@@ -1053,59 +1053,6 @@ jobs:
name: "Go mod tidy" name: "Go mod tidy"
command: make mod-tidy && git diff --exit-code command: make mod-tidy && git diff --exit-code
hive-test:
parameters:
version:
type: string
default: develop
sim:
type: string
machine:
image: ubuntu-2204:2022.10.2
docker_layer_caching: true
resource_class: large
steps:
- attach_workspace:
at: /tmp/docker_images
- run:
name: Docker Load
command: |
docker load -i /tmp/docker_images/op-batcher_<<parameters.version>>.tar
docker load -i /tmp/docker_images/op-proposer_<<parameters.version>>.tar
docker load -i /tmp/docker_images/op-node_<<parameters.version>>.tar
- run:
command: git clone https://github.com/ethereum-optimism/hive.git .
- go/load-cache
- go/mod-download
- go/save-cache
- run: { command: "go build ." }
- run: { command: "go build junit/junitformatter.go" }
- run:
command: |
./hive \
-sim=<<parameters.sim>> \
-sim.loglevel=5 \
-client=go-ethereum_v1.11.6,op-geth_optimism,op-proposer_<<parameters.version>>,op-batcher_<<parameters.version>>,op-node_<<parameters.version>> |& tee /tmp/hive.log
- run:
command: |
tar -cvf /tmp/workspace.tgz -C /home/circleci/project /home/circleci/project/workspace
name: "Archive workspace"
when: always
- run:
command: |
./junitformatter /home/circleci/project/workspace/logs/*.json > /home/circleci/project/workspace/logs/junit.xml
when: always
- store_artifacts:
path: /tmp/workspace.tgz
destination: hive-workspace.tgz
when: always
- store_test_results:
path: /home/circleci/project/workspace/logs/junit.xml
when: always
- store_artifacts:
path: /home/circleci/project/workspace/logs/junit.xml
when: always
bedrock-go-tests: bedrock-go-tests:
docker: docker:
- image: cimg/go:1.20 - image: cimg/go:1.20
...@@ -1423,33 +1370,6 @@ workflows: ...@@ -1423,33 +1370,6 @@ workflows:
docker_target: wd-mon docker_target: wd-mon
context: context:
- oplabs-gcr - oplabs-gcr
- hive-test:
name: hive-test-rpc
version: <<pipeline.git.revision>>
sim: optimism/rpc
requires:
- op-node-docker-build
- op-batcher-docker-build
- op-proposer-docker-build
- op-challenger-docker-build
- hive-test:
name: hive-test-p2p
version: <<pipeline.git.revision>>
sim: optimism/p2p
requires:
- op-node-docker-build
- op-batcher-docker-build
- op-proposer-docker-build
- op-challenger-docker-build
- hive-test:
name: hive-test-l1ops
version: <<pipeline.git.revision>>
sim: optimism/l1ops
requires:
- op-node-docker-build
- op-batcher-docker-build
- op-proposer-docker-build
- op-challenger-docker-build
- check-generated-mocks-op-node - check-generated-mocks-op-node
- check-generated-mocks-op-service - check-generated-mocks-op-service
- cannon-go-lint-and-test - cannon-go-lint-and-test
......
...@@ -395,87 +395,110 @@ func (m *InstrumentedState) mipsStep() error { ...@@ -395,87 +395,110 @@ func (m *InstrumentedState) mipsStep() error {
func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
opcode := insn >> 26 // 6-bits opcode := insn >> 26 // 6-bits
fun := insn & 0x3f // 6-bits
if opcode == 0 || (opcode >= 8 && opcode < 0xF) {
if opcode < 0x20 { fun := insn & 0x3f // 6-bits
// transform ArithLogI // transform ArithLogI to SPECIAL
// TODO(CLI-4136): replace with table switch opcode {
if opcode >= 8 && opcode < 0xF { case 8:
switch opcode { fun = 0x20 // addi
case 8: case 9:
fun = 0x20 // addi fun = 0x21 // addiu
case 9: case 0xA:
fun = 0x21 // addiu fun = 0x2A // slti
case 0xA: case 0xB:
fun = 0x2A // slti fun = 0x2B // sltiu
case 0xB: case 0xC:
fun = 0x2B // sltiu fun = 0x24 // andi
case 0xC: case 0xD:
fun = 0x24 // andi fun = 0x25 // ori
case 0xD: case 0xE:
fun = 0x25 // ori fun = 0x26 // xori
case 0xE:
fun = 0x26 // xori
}
opcode = 0
} }
// 0 is opcode SPECIAL switch fun {
if opcode == 0 { case 0x00: // sll
return rt << ((insn >> 6) & 0x1F)
case 0x02: // srl
return rt >> ((insn >> 6) & 0x1F)
case 0x03: // sra
shamt := (insn >> 6) & 0x1F shamt := (insn >> 6) & 0x1F
if fun < 0x20 { return SE(rt>>shamt, 32-shamt)
switch { case 0x04: // sllv
case fun >= 0x08: return rt << (rs & 0x1F)
return rs // jr/jalr/div + others case 0x06: // srlv
case fun == 0x00: return rt >> (rs & 0x1F)
return rt << shamt // sll case 0x07: // srav
case fun == 0x02: return SE(rt>>rs, 32-rs)
return rt >> shamt // srl // functs in range [0x8, 0x1b] are handled specially by other functions
case fun == 0x03: case 0x08: // jr
return SE(rt>>shamt, 32-shamt) // sra return rs
case fun == 0x04: case 0x09: // jalr
return rt << (rs & 0x1F) // sllv return rs
case fun == 0x06: case 0x0a: // movz
return rt >> (rs & 0x1F) // srlv return rs
case fun == 0x07: case 0x0b: // movn
return SE(rt>>rs, 32-rs) // srav return rs
} case 0x0c: // syscall
return rs
// 0x0d - break not supported
case 0x0f: // sync
return rs
case 0x10: // mfhi
return rs
case 0x11: // mthi
return rs
case 0x12: // mflo
return rs
case 0x13: // mtlo
return rs
case 0x18: // mult
return rs
case 0x19: // multu
return rs
case 0x1a: // div
return rs
case 0x1b: // divu
return rs
// The rest includes transformed R-type arith imm instructions
case 0x20: // add
return rs + rt
case 0x21: // addu
return rs + rt
case 0x22: // sub
return rs - rt
case 0x23: // subu
return rs - rt
case 0x24: // and
return rs & rt
case 0x25: // or
return rs | rt
case 0x26: // xor
return rs ^ rt
case 0x27: // nor
return ^(rs | rt)
case 0x2a: // slti
if int32(rs) < int32(rt) {
return 1
} }
// 0x10-0x13 = mfhi, mthi, mflo, mtlo return 0
// R-type (ArithLog) case 0x2b: // sltiu
switch fun { if rs < rt {
case 0x20, 0x21: return 1
return rs + rt // add or addu
case 0x22, 0x23:
return rs - rt // sub or subu
case 0x24:
return rs & rt // and
case 0x25:
return rs | rt // or
case 0x26:
return rs ^ rt // xor
case 0x27:
return ^(rs | rt) // nor
case 0x2A:
if int32(rs) < int32(rt) {
return 1 // slt
} else {
return 0
}
case 0x2B:
if rs < rt {
return 1 // sltu
} else {
return 0
}
} }
} else if opcode == 0xF { return 0
return rt << 16 // lui default:
} else if opcode == 0x1C { // SPECIAL2 panic("invalid instruction")
if fun == 2 { // mul }
} else {
switch opcode {
// SPECIAL2
case 0x1C:
fun := insn & 0x3f // 6-bits
switch fun {
case 0x2: // mul
return uint32(int32(rs) * int32(rt)) return uint32(int32(rs) * int32(rt))
} case 0x20, 0x21: // clo
if fun == 0x20 || fun == 0x21 { // clo
if fun == 0x20 { if fun == 0x20 {
rs = ^rs rs = ^rs
} }
...@@ -485,9 +508,8 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { ...@@ -485,9 +508,8 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
} }
return i return i
} }
} case 0x0F: // lui
} else if opcode < 0x28 { return rt << 16
switch opcode {
case 0x20: // lb case 0x20: // lb
return SE((mem>>(24-(rs&3)*8))&0xFF, 8) return SE((mem>>(24-(rs&3)*8))&0xFF, 8)
case 0x21: // lh case 0x21: // lh
...@@ -500,37 +522,38 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 { ...@@ -500,37 +522,38 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
return mem return mem
case 0x24: // lbu case 0x24: // lbu
return (mem >> (24 - (rs&3)*8)) & 0xFF return (mem >> (24 - (rs&3)*8)) & 0xFF
case 0x25: // lhu case 0x25: // lhu
return (mem >> (16 - (rs&2)*8)) & 0xFFFF return (mem >> (16 - (rs&2)*8)) & 0xFFFF
case 0x26: // lwr case 0x26: // lwr
val := mem >> (24 - (rs&3)*8) val := mem >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8) mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
return (rt & ^mask) | val return (rt & ^mask) | val
case 0x28: // sb
val := (rt & 0xFF) << (24 - (rs&3)*8)
mask := 0xFFFFFFFF ^ uint32(0xFF<<(24-(rs&3)*8))
return (mem & mask) | val
case 0x29: // sh
val := (rt & 0xFFFF) << (16 - (rs&2)*8)
mask := 0xFFFFFFFF ^ uint32(0xFFFF<<(16-(rs&2)*8))
return (mem & mask) | val
case 0x2a: // swl
val := rt >> ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8)
return (mem & ^mask) | val
case 0x2b: // sw
return rt
case 0x2e: // swr
val := rt << (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8)
return (mem & ^mask) | val
case 0x30: // ll
return mem
case 0x38: // sc
return rt
default:
panic("invalid instruction")
} }
} else if opcode == 0x28 { // sb
val := (rt & 0xFF) << (24 - (rs&3)*8)
mask := 0xFFFFFFFF ^ uint32(0xFF<<(24-(rs&3)*8))
return (mem & mask) | val
} else if opcode == 0x29 { // sh
val := (rt & 0xFFFF) << (16 - (rs&2)*8)
mask := 0xFFFFFFFF ^ uint32(0xFFFF<<(16-(rs&2)*8))
return (mem & mask) | val
} else if opcode == 0x2a { // swl
val := rt >> ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8)
return (mem & ^mask) | val
} else if opcode == 0x2b { // sw
return rt
} else if opcode == 0x2e { // swr
val := rt << (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8)
return (mem & ^mask) | val
} else if opcode == 0x30 {
return mem // ll
} else if opcode == 0x38 {
return rt // sc
} }
panic("invalid instruction") panic("invalid instruction")
} }
......
## Optimism Monorepo Documentation
The `docs/` directory contains Optimism documentation closely tied to the implementation details of the monorepo (https://github.com/ethereum-optimism/optimism).
The directory layout is divided into the following sub-directories.
- [`postmortems/`](./postmortems/): Timestamped post-mortem documents.
- [`security-reviews`](./security-reviews/): Audit summaries and other security review documents.
...@@ -8,6 +8,7 @@ require ( ...@@ -8,6 +8,7 @@ require (
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20230817174831-5d3ca1966435
github.com/ethereum/go-ethereum v1.12.0 github.com/ethereum/go-ethereum v1.12.0
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/chi/v5 v5.0.10
...@@ -15,7 +16,7 @@ require ( ...@@ -15,7 +16,7 @@ require (
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.1
github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/golang-lru/v2 v2.0.2 github.com/hashicorp/golang-lru/v2 v2.0.2
github.com/holiman/uint256 v1.2.3 github.com/holiman/uint256 v1.2.3
...@@ -31,7 +32,7 @@ require ( ...@@ -31,7 +32,7 @@ require (
github.com/multiformats/go-multiaddr v0.10.1 github.com/multiformats/go-multiaddr v0.10.1
github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/gomega v1.27.4 github.com/onsi/gomega v1.27.10
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.7.0 github.com/pkg/profile v1.7.0
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
...@@ -157,7 +158,7 @@ require ( ...@@ -157,7 +158,7 @@ require (
github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiformats/go-varint v0.0.7 // indirect
github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 // indirect
github.com/onsi/ginkgo/v2 v2.9.2 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
...@@ -193,10 +194,10 @@ require ( ...@@ -193,10 +194,10 @@ require (
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.24.0 // indirect
golang.org/x/mod v0.11.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.10.0 // indirect golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.7.0 // indirect golang.org/x/tools v0.9.3 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
...@@ -207,6 +208,6 @@ require ( ...@@ -207,6 +208,6 @@ require (
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )
replace github.com/ethereum/go-ethereum v1.12.0 => github.com/ethereum-optimism/op-geth v1.101106.1-0.20230724181546-b9c6d36ae9b8 replace github.com/ethereum/go-ethereum v1.12.0 => github.com/ethereum-optimism/op-geth v1.101200.0-rc.1.0.20230818191139-f7376a28049b
//replace github.com/ethereum/go-ethereum v1.12.0 => ../go-ethereum //replace github.com/ethereum/go-ethereum v1.12.0 => ../go-ethereum
...@@ -162,8 +162,10 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 ...@@ -162,8 +162,10 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.101106.1-0.20230724181546-b9c6d36ae9b8 h1:Kr4nvrI5WHLtjLiuuVGXMBfPX2Yeo3HdUWW8iXRH6oA= github.com/ethereum-optimism/op-geth v1.101200.0-rc.1.0.20230818191139-f7376a28049b h1:YF2FE/QnbhvrHwDYJHnbTKgJvw2aKwB/dd7PO1zKNqY=
github.com/ethereum-optimism/op-geth v1.101106.1-0.20230724181546-b9c6d36ae9b8/go.mod h1:G224y5tCMfjaCqIrTu2Svcz13CbVjHIVZjuoacCvJ1w= github.com/ethereum-optimism/op-geth v1.101200.0-rc.1.0.20230818191139-f7376a28049b/go.mod h1:gRnPb21PoKcHm3kHqj9BQlQkwmhOGUvQoGEbC7z852Q=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20230817174831-5d3ca1966435 h1:2CzkJkkTLuVyoVFkoW5w6vDB2Q7eJzxXw/ybA17xjqM=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20230817174831-5d3ca1966435/go.mod h1:v2YpePbdGBF0Gr6VWq49MFFmcTW0kRYZ2ingBJYWEwg=
github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q= github.com/ethereum/c-kzg-4844 v0.2.0 h1:+cUvymlnoDDQgMInp25Bo3OmLajmmY8mLJ/tLjqd77Q=
github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8= github.com/ethereum/c-kzg-4844 v0.2.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
...@@ -214,7 +216,7 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm ...@@ -214,7 +216,7 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
...@@ -316,8 +318,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4 ...@@ -316,8 +318,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
...@@ -647,16 +649,16 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv ...@@ -647,16 +649,16 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
...@@ -934,8 +936,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT ...@@ -934,8 +936,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
...@@ -1056,8 +1058,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f ...@@ -1056,8 +1058,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......
...@@ -105,7 +105,7 @@ func NewCli(GitVersion string, GitCommit string, GitDate string) *Cli { ...@@ -105,7 +105,7 @@ func NewCli(GitVersion string, GitCommit string, GitDate string) *Cli {
Action: runApi, Action: runApi,
}, },
{ {
Name: "indexer", Name: "index",
Flags: flags, Flags: flags,
Description: "Runs the indexing service", Description: "Runs the indexing service",
Action: runIndexer, Action: runIndexer,
......
...@@ -18,8 +18,8 @@ import ( ...@@ -18,8 +18,8 @@ import (
*/ */
type BlockHeader struct { type BlockHeader struct {
Hash common.Hash `gorm:"primaryKey;serializer:json"` Hash common.Hash `gorm:"primaryKey;serializer:bytes"`
ParentHash common.Hash `gorm:"serializer:json"` ParentHash common.Hash `gorm:"serializer:bytes"`
Number U256 Number U256
Timestamp uint64 Timestamp uint64
...@@ -50,14 +50,14 @@ type LegacyStateBatch struct { ...@@ -50,14 +50,14 @@ type LegacyStateBatch struct {
// violating the primary key constraint. // violating the primary key constraint.
Index uint64 `gorm:"primaryKey;default:0"` Index uint64 `gorm:"primaryKey;default:0"`
Root common.Hash `gorm:"serializer:json"` Root common.Hash `gorm:"serializer:bytes"`
Size uint64 Size uint64
PrevTotal uint64 PrevTotal uint64
L1ContractEventGUID uuid.UUID L1ContractEventGUID uuid.UUID
} }
type OutputProposal struct { type OutputProposal struct {
OutputRoot common.Hash `gorm:"primaryKey;serializer:json"` OutputRoot common.Hash `gorm:"primaryKey;serializer:bytes"`
L2OutputIndex U256 L2OutputIndex U256
L2BlockNumber U256 L2BlockNumber U256
......
...@@ -16,7 +16,7 @@ import ( ...@@ -16,7 +16,7 @@ import (
*/ */
type BridgeMessage struct { type BridgeMessage struct {
MessageHash common.Hash `gorm:"primaryKey;serializer:json"` MessageHash common.Hash `gorm:"primaryKey;serializer:bytes"`
Nonce U256 Nonce U256
SentMessageEventGUID uuid.UUID SentMessageEventGUID uuid.UUID
...@@ -28,12 +28,12 @@ type BridgeMessage struct { ...@@ -28,12 +28,12 @@ type BridgeMessage struct {
type L1BridgeMessage struct { type L1BridgeMessage struct {
BridgeMessage `gorm:"embedded"` BridgeMessage `gorm:"embedded"`
TransactionSourceHash common.Hash `gorm:"serializer:json"` TransactionSourceHash common.Hash `gorm:"serializer:bytes"`
} }
type L2BridgeMessage struct { type L2BridgeMessage struct {
BridgeMessage `gorm:"embedded"` BridgeMessage `gorm:"embedded"`
TransactionWithdrawalHash common.Hash `gorm:"serializer:json"` TransactionWithdrawalHash common.Hash `gorm:"serializer:bytes"`
} }
type BridgeMessagesView interface { type BridgeMessagesView interface {
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
) )
/** /**
...@@ -16,16 +15,16 @@ import ( ...@@ -16,16 +15,16 @@ import (
*/ */
type Transaction struct { type Transaction struct {
FromAddress common.Address `gorm:"serializer:json"` FromAddress common.Address `gorm:"serializer:bytes"`
ToAddress common.Address `gorm:"serializer:json"` ToAddress common.Address `gorm:"serializer:bytes"`
Amount U256 Amount U256
Data hexutil.Bytes `gorm:"serializer:json"` Data Bytes `gorm:"serializer:bytes"`
Timestamp uint64 Timestamp uint64
} }
type L1TransactionDeposit struct { type L1TransactionDeposit struct {
SourceHash common.Hash `gorm:"serializer:json;primaryKey"` SourceHash common.Hash `gorm:"serializer:bytes;primaryKey"`
L2TransactionHash common.Hash `gorm:"serializer:json"` L2TransactionHash common.Hash `gorm:"serializer:bytes"`
InitiatedL1EventGUID uuid.UUID InitiatedL1EventGUID uuid.UUID
Tx Transaction `gorm:"embedded"` Tx Transaction `gorm:"embedded"`
...@@ -33,7 +32,7 @@ type L1TransactionDeposit struct { ...@@ -33,7 +32,7 @@ type L1TransactionDeposit struct {
} }
type L2TransactionWithdrawal struct { type L2TransactionWithdrawal struct {
WithdrawalHash common.Hash `gorm:"serializer:json;primaryKey"` WithdrawalHash common.Hash `gorm:"serializer:bytes;primaryKey"`
Nonce U256 Nonce U256
InitiatedL2EventGUID uuid.UUID InitiatedL2EventGUID uuid.UUID
......
...@@ -19,12 +19,12 @@ var ( ...@@ -19,12 +19,12 @@ var (
*/ */
type TokenPair struct { type TokenPair struct {
LocalTokenAddress common.Address `gorm:"serializer:json"` LocalTokenAddress common.Address `gorm:"serializer:bytes"`
RemoteTokenAddress common.Address `gorm:"serializer:json"` RemoteTokenAddress common.Address `gorm:"serializer:bytes"`
} }
type BridgeTransfer struct { type BridgeTransfer struct {
CrossDomainMessageHash *common.Hash `gorm:"serializer:json"` CrossDomainMessageHash *common.Hash `gorm:"serializer:bytes"`
Tx Transaction `gorm:"embedded"` Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"` TokenPair TokenPair `gorm:"embedded"`
...@@ -32,27 +32,27 @@ type BridgeTransfer struct { ...@@ -32,27 +32,27 @@ type BridgeTransfer struct {
type L1BridgeDeposit struct { type L1BridgeDeposit struct {
BridgeTransfer `gorm:"embedded"` BridgeTransfer `gorm:"embedded"`
TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:json"` TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:bytes"`
} }
type L1BridgeDepositWithTransactionHashes struct { type L1BridgeDepositWithTransactionHashes struct {
L1BridgeDeposit L1BridgeDeposit `gorm:"embedded"` L1BridgeDeposit L1BridgeDeposit `gorm:"embedded"`
L1TransactionHash common.Hash `gorm:"serializer:json"` L1TransactionHash common.Hash `gorm:"serializer:bytes"`
L2TransactionHash common.Hash `gorm:"serializer:json"` L2TransactionHash common.Hash `gorm:"serializer:bytes"`
} }
type L2BridgeWithdrawal struct { type L2BridgeWithdrawal struct {
BridgeTransfer `gorm:"embedded"` BridgeTransfer `gorm:"embedded"`
TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:json"` TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:bytes"`
} }
type L2BridgeWithdrawalWithTransactionHashes struct { type L2BridgeWithdrawalWithTransactionHashes struct {
L2BridgeWithdrawal L2BridgeWithdrawal `gorm:"embedded"` L2BridgeWithdrawal L2BridgeWithdrawal `gorm:"embedded"`
L2TransactionHash common.Hash `gorm:"serializer:json"` L2TransactionHash common.Hash `gorm:"serializer:bytes"`
ProvenL1TransactionHash common.Hash `gorm:"serializer:json"` ProvenL1TransactionHash common.Hash `gorm:"serializer:bytes"`
FinalizedL1TransactionHash common.Hash `gorm:"serializer:json"` FinalizedL1TransactionHash common.Hash `gorm:"serializer:bytes"`
} }
type BridgeTransfersView interface { type BridgeTransfersView interface {
......
...@@ -21,12 +21,12 @@ type ContractEvent struct { ...@@ -21,12 +21,12 @@ type ContractEvent struct {
GUID uuid.UUID `gorm:"primaryKey"` GUID uuid.UUID `gorm:"primaryKey"`
// Some useful derived fields // Some useful derived fields
BlockHash common.Hash `gorm:"serializer:json"` BlockHash common.Hash `gorm:"serializer:bytes"`
ContractAddress common.Address `gorm:"serializer:json"` ContractAddress common.Address `gorm:"serializer:bytes"`
TransactionHash common.Hash `gorm:"serializer:json"` TransactionHash common.Hash `gorm:"serializer:bytes"`
LogIndex uint64 LogIndex uint64
EventSignature common.Hash `gorm:"serializer:json"` EventSignature common.Hash `gorm:"serializer:bytes"`
Timestamp uint64 Timestamp uint64
// NOTE: NOT ALL THE DERIVED FIELDS ON `types.Log` ARE // NOTE: NOT ALL THE DERIVED FIELDS ON `types.Log` ARE
......
...@@ -5,6 +5,8 @@ import ( ...@@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/indexer/config" "github.com/ethereum-optimism/optimism/indexer/config"
_ "github.com/ethereum-optimism/optimism/indexer/database/serializers"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/logger" "gorm.io/gorm/logger"
......
package serializers
import (
"context"
"fmt"
"reflect"
"github.com/ethereum/go-ethereum/common/hexutil"
"gorm.io/gorm/schema"
)
type BytesSerializer struct{}
type BytesInterface interface{ Bytes() []byte }
type SetBytesInterface interface{ SetBytes([]byte) }
func init() {
schema.RegisterSerializer("bytes", BytesSerializer{})
}
func (BytesSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error {
if dbValue == nil {
return nil
}
hexStr, ok := dbValue.(string)
if !ok {
return fmt.Errorf("expected hex string as the database value: %T", dbValue)
}
b, err := hexutil.Decode(hexStr)
if err != nil {
return fmt.Errorf("failed to decode database value: %w", err)
}
fieldValue := reflect.New(field.FieldType)
fieldInterface := fieldValue.Interface()
// Detect if we're deserializing into a pointer. If so, we'll need to
// also allocate memory to where the allocated pointer should point to
if field.FieldType.Kind() == reflect.Pointer {
nestedField := fieldValue.Elem()
if nestedField.Elem().Kind() == reflect.Pointer {
return fmt.Errorf("double pointers are the max depth supported: %T", fieldValue)
}
// We'll want to call `SetBytes` on the pointer to
// the allocated memory and not the double pointer
nestedField.Set(reflect.New(field.FieldType.Elem()))
fieldInterface = nestedField.Interface()
}
fieldSetBytes, ok := fieldInterface.(SetBytesInterface)
if !ok {
return fmt.Errorf("field does not satisfy the `SetBytes([]byte)` interface: %T", fieldInterface)
}
fieldSetBytes.SetBytes(b)
field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
return nil
}
func (BytesSerializer) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
if fieldValue == nil || (field.FieldType.Kind() == reflect.Pointer && reflect.ValueOf(fieldValue).IsNil()) {
return nil, nil
}
fieldBytes, ok := fieldValue.(BytesInterface)
if !ok {
return nil, fmt.Errorf("field does not satisfy the `Bytes() []byte` interface")
}
hexStr := hexutil.Encode(fieldBytes.Bytes())
return hexStr, nil
}
package database package serializers
import ( import (
"context" "context"
...@@ -13,38 +13,28 @@ import ( ...@@ -13,38 +13,28 @@ import (
type RLPSerializer struct{} type RLPSerializer struct{}
type RLPInterface interface {
rlp.Encoder
rlp.Decoder
}
func init() { func init() {
schema.RegisterSerializer("rlp", RLPSerializer{}) schema.RegisterSerializer("rlp", RLPSerializer{})
} }
func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error { func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error {
fieldValue := reflect.New(field.FieldType) if dbValue == nil {
if dbValue != nil { return nil
var bytes []byte }
switch v := dbValue.(type) {
case []byte: hexStr, ok := dbValue.(string)
bytes = v if !ok {
case string: return fmt.Errorf("expected hex string as the database value: %T", dbValue)
b, err := hexutil.Decode(v) }
if err != nil {
return err
}
bytes = b
default:
return fmt.Errorf("unrecognized RLP bytes: %#v", dbValue)
}
if len(bytes) > 0 { b, err := hexutil.Decode(hexStr)
err := rlp.DecodeBytes(bytes, fieldValue.Interface()) if err != nil {
if err != nil { return fmt.Errorf("failed to decode database value: %w", err)
return err }
}
} fieldValue := reflect.New(field.FieldType)
if err := rlp.DecodeBytes(b, fieldValue.Interface()); err != nil {
return fmt.Errorf("failed to decode rlp bytes: %w", err)
} }
field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem()) field.ReflectValueOf(ctx, dst).Set(fieldValue.Elem())
...@@ -52,18 +42,15 @@ func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect. ...@@ -52,18 +42,15 @@ func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.
} }
func (RLPSerializer) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) { func (RLPSerializer) Value(ctx context.Context, field *schema.Field, dst reflect.Value, fieldValue interface{}) (interface{}, error) {
// Even though rlp.Encode takes an interface and will error out if the passed interface does not if fieldValue == nil || (field.FieldType.Kind() == reflect.Pointer && reflect.ValueOf(fieldValue).IsNil()) {
// satisfy the interface, we check here since we also want to make sure this type satisfies the return nil, nil
// rlp.Decoder interface as well
i := reflect.TypeOf(new(RLPInterface)).Elem()
if !reflect.TypeOf(fieldValue).Implements(i) {
return nil, fmt.Errorf("%T does not satisfy RLP Encoder & Decoder interface", fieldValue)
} }
rlpBytes, err := rlp.EncodeToBytes(fieldValue) rlpBytes, err := rlp.EncodeToBytes(fieldValue)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to encode rlp bytes: %w", err)
} }
return hexutil.Bytes(rlpBytes).MarshalText() hexStr := hexutil.Encode(rlpBytes)
return hexStr, nil
} }
...@@ -93,3 +93,12 @@ func (h *RLPHeader) Header() *types.Header { ...@@ -93,3 +93,12 @@ func (h *RLPHeader) Header() *types.Header {
func (h *RLPHeader) Hash() common.Hash { func (h *RLPHeader) Hash() common.Hash {
return h.Header().Hash() return h.Header().Hash()
} }
type Bytes []byte
func (b Bytes) Bytes() []byte {
return b[:]
}
func (b *Bytes) SetBytes(bytes []byte) {
*b = bytes
}
...@@ -20,22 +20,14 @@ services: ...@@ -20,22 +20,14 @@ services:
indexer: indexer:
build: build:
context: .. context: ..
dockerfile: indexer/Dockerfile.refresh dockerfile: indexer/Dockerfile
command: ["indexer-refresh", "processor"] command: ["indexer", "index"]
# healthcheck:
# Add healthcheck once figure out good way how
# maybe after we add metrics?
ports:
- 8080:8080
environment: environment:
- INDEXER_DB_PORT=5432 - INDEXER_RPC_URL_L1=$INDEXER_RPC_URL_L1
- INDEXER_DB_USER=db_username - INDEXER_RPC_URL_L2=$INDEXER_RPC_URL_L2
- INDEXER_DB_PASSWORD=db_password - INDEXER_CONFIG=/indexer/indexer.toml
- INDEXER_DB_NAME=db_name
- INDEXER_DB_HOST=postgres
- INDEXER_CONFIG=/configs/indexer.toml
volumes: volumes:
- ./indexer.toml:/configs/indexer.toml - ./indexer.toml:/indexer/indexer.toml
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
...@@ -44,27 +36,17 @@ services: ...@@ -44,27 +36,17 @@ services:
build: build:
context: .. context: ..
dockerfile: indexer/Dockerfile dockerfile: indexer/Dockerfile
command: ["indexer", "api"]
healthcheck: healthcheck:
test: wget localhost:8080/healthz -q -O - > /dev/null 2>&1 test: wget localhost:8080/healthz -q -O - > /dev/null 2>&1
environment: environment:
# Note that you must index goerli with INDEXER_BEDROCK=false first, then # Note that you must index goerli with INDEXER_BEDROCK=false first, then
# reindex with INDEXER_BEDROCK=true or seed the database # reindex with INDEXER_BEDROCK=true or seed the database
- INDEXER_BEDROCK=${INDEXER_BEDROCK_GOERLI:-true} - INDEXER_RPC_URL_L1=$INDEXER_RPC_URL_L1
- INDEXER_BUILD_ENV=${INDEXER_BUILD_ENV:-development} - INDEXER_RPC_URL_L2=$INDEXER_RPC_URL_L2
- INDEXER_DB_PORT=${INDEXER_DB_PORT:-5432} - INDEXER_CONFIG=/indexer/indexer.toml
- INDEXER_DB_USER=${INDEXER_DB_USER:-db_username} volumes:
- INDEXER_DB_PASSWORD=${INDEXER_DB_PASSWORD:-db_password} - ./indexer.toml:/indexer/indexer.toml
- INDEXER_DB_NAME=${INDEXER_DB_NAME:-db_name}
- INDEXER_DB_HOST=${INDEXER_DB_HOST:-postgres}
- INDEXER_CHAIN_ID=${INDEXER_CHAIN_ID:-5}
- INDEXER_L1_ETH_RPC=$INDEXER_L1_ETH_RPC
- INDEXER_L2_ETH_RPC=$INDEXER_L2_ETH_RPC
- INDEXER_REST_HOSTNAME=0.0.0.0
- INDEXER_REST_PORT=8080
- INDEXER_BEDROCK_L1_STANDARD_BRIDGE=0
- INDEXER_BEDROCK_L1_STANDARD_BRIDGE=${INDEXER_BEDROCK_L1_STANDARD_BRIDGE:-0x636Af16bf2f682dD3109e60102b8E1A089FedAa8}
- INDEXER_BEDROCK_OPTIMISM_PORTAL=${INDEXER_BEDROCK_OPTIMISM_PORTAL:-0xB7040fd32359688346A3D1395a42114cf8E3b9b2}
- INDEXER_L1_ADDRESS_MANAGER_ADDRESS=${INDEXER_L1_ADDRESS_MANAGER_ADDRESS:-0xdE1FCfB0851916CA5101820A69b13a4E276bd81F}
ports: ports:
- 8080:8080 - 8080:8080
depends_on: depends_on:
...@@ -99,77 +81,6 @@ services: ...@@ -99,77 +81,6 @@ services:
postgres: postgres:
condition: service_healthy condition: service_healthy
gateway-frontend:
command: pnpm nx start @gateway/frontend --host 0.0.0.0 --port 5173
# Change tag to `latest` after https://github.com/ethereum-optimism/gateway/pull/2541 merges
image: ethereumoptimism/gateway-frontend:latest
ports:
- 5173:5173
healthcheck:
test: curl http://0.0.0.0:5173
environment:
- VITE_GROWTHBOOK=${VITE_GROWTHBOOK:-https://cdn.growthbook.io/api/features/dev_iGoAbSwtGOtEJONeHdVTosV0BD3TvTPttAccGyRxqsk}
- VITE_ENABLE_DEVNET=true
- VITE_RPC_URL_ETHEREUM_MAINNET=$VITE_RPC_URL_ETHEREUM_MAINNET
- VITE_RPC_URL_ETHEREUM_OPTIMISM_MAINNET=$VITE_RPC_URL_OPTIMISM_MAINNET
- VITE_RPC_URL_ETHEREUM_GOERLI=$VITE_RPC_URL_ETHEREUM_GOERLI
- VITE_RPC_URL_ETHEREUM_OPTIMISM_GOERLI=$VITE_RPC_URL_OPTIMISM_GOERLI
- VITE_BACKEND_URL_MAINNET=http://localhost:7421
- VITE_BACKEND_URL_GOERLI=http://localhost:7422
- VITE_ENABLE_ALL_FEATURES=true
backend-mainnet:
image: ethereumoptimism/gateway-backend:latest
environment:
# this enables the backend to proxy history requests to the indexer
- BRIDGE_INDEXER_URI=http://api
- HOST=0.0.0.0
- PORT=7300
- MIGRATE_APP_DB_USER=${MIGRATE_APP_DB_USER:-postgres}
- MIGRATE_APP_DB_PASSWORD=${MIGRATE_APP_DB_PASSWORD:-db_password}
- APP_DB_HOST=${APP_DB_HOST:-postgres-app}
- APP_DB_USER=${APP_DB_USER:-gateway-backend-mainnet@oplabs-local-web.iam}
- APP_DB_NAME=${APP_DB_NAME:-gateway}
- APP_DB_PORT=${APP_DB_PORT:-5432}
# THis is for the legacy indexer which won't be used but the env variable is still required
- INDEXER_DB_HOST=postgres-mainnet
# THis is for the legacy indexer which won't be used but the env variable is still required
- INDEXER_DB_USER=db_username
# THis is for the legacy indexer which won't be used but the env variable is still required
- INDEXER_DB_PASS=db_password
# THis is for the legacy indexer which won't be used but the env variable is still required
- INDEXER_DB_NAME=db_name
# THis is for the legacy indexer which won't be used but the env variable is still required
- INDEXER_DB_PORT=5432
# THis is for the legacy indexer which won't be used but the env variable is still required
- DATABASE_URL=postgres://db_username:db_password@postgres-mainnet:5432/db_name
- JSON_RPC_URLS_L1=$JSON_RPC_URLS_L1_MAINNET
- JSON_RPC_URLS_L2=$JSON_RPC_URLS_L2_MAINNET
- JSON_RPC_URLS_L2_GOERLI=$JSON_RPC_URLS_L2_GOERLI
# anvil[0] privater key as placeholder
- FAUCET_AUTH_ADMIN_WALLET_PRIVATE_KEY=${$FAUCET_AUTH_ADMIN_WALLET_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80}
- IRON_SESSION_SECRET=${IRON_SESSION_SECRET:-UNKNOWN_IRON_SESSION_PASSWORD_32}
- CHAIN_ID_L1=1
- CHAIN_ID_L2=10
- FLEEK_BUCKET_ADDRESS=34a609661-6774-441f-9fdb-453fdbb89931-bucket
- FLEEK_API_SECRET=$FLEEK_API_SECRET
- FLEEK_API_KEY=$FLEEK_API_KEY
- MOCK_MERKLE_PROOF=true
- LOOP_INTERVAL_MINUTES=.1
- GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID
- GITHUB_SECRET=$GITHUB_SECRET
- MAINNET_BEDROCK=$MAINNET_BEDROCK
- TRM_API_KEY=$TRM_API_KEY
- GOOGLE_CLOUD_STORAGE_BUCKET_NAME=oplabs-dev-web-content
# Recommened to uncomment for local dev unless you need it
#- BYPASS_EVENT_LOG_POLLER_BOOTSTRAP=true
ports:
- 7421:7300
# overrides command in Dockerfile so we can hot reload the server in docker while developing
#command: ['pnpm', 'nx', 'run', '@gateway/backend:docker:watch']
healthcheck:
test: curl http://0.0.0.0:7300/api/v0/healthz
backend-goerli: backend-goerli:
image: ethereumoptimism/gateway-backend:latest image: ethereumoptimism/gateway-backend:latest
environment: environment:
......
...@@ -9,11 +9,11 @@ l1-rpc = "${INDEXER_RPC_URL_L1}" ...@@ -9,11 +9,11 @@ l1-rpc = "${INDEXER_RPC_URL_L1}"
l2-rpc = "${INDEXER_RPC_URL_L2}" l2-rpc = "${INDEXER_RPC_URL_L2}"
[db] [db]
host = "127.0.0.1" host = "postgres"
port = 5432 port = 5432
user = "postgres" user = "db_username"
password = "postgres" password = "db_password"
name = "indexer" name = "db_name"
[api] [api]
host = "127.0.0.1" host = "127.0.0.1"
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -105,20 +105,20 @@ func TestGameFactoryAddress(t *testing.T) { ...@@ -105,20 +105,20 @@ func TestGameFactoryAddress(t *testing.T) {
}) })
} }
func TestGameAddress(t *testing.T) { func TestGameAllowlist(t *testing.T) {
t.Run("Optional", func(t *testing.T) { t.Run("Optional", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address")) cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist"))
require.NoError(t, cfg.Check()) require.NoError(t, cfg.Check())
}) })
t.Run("Valid", func(t *testing.T) { t.Run("Valid", func(t *testing.T) {
addr := common.Address{0xbb, 0xcc, 0xdd} addr := common.Address{0xbb, 0xcc, 0xdd}
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address", "--game-address="+addr.Hex())) cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist", "--game-allowlist="+addr.Hex()))
require.Equal(t, addr, cfg.GameAddress) require.Contains(t, cfg.GameAllowlist, addr)
}) })
t.Run("Invalid", func(t *testing.T) { t.Run("Invalid", func(t *testing.T) {
verifyArgsInvalid(t, "invalid address: foo", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address", "--game-address=foo")) verifyArgsInvalid(t, "invalid address: foo", addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist", "--game-allowlist=foo"))
}) })
} }
......
...@@ -4,11 +4,12 @@ import ( ...@@ -4,11 +4,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
) )
var ( var (
...@@ -78,10 +79,10 @@ const DefaultCannonSnapshotFreq = uint(1_000_000_000) ...@@ -78,10 +79,10 @@ const DefaultCannonSnapshotFreq = uint(1_000_000_000)
// This also contains config options for auxiliary services. // This also contains config options for auxiliary services.
// It is used to initialize the challenger. // It is used to initialize the challenger.
type Config struct { type Config struct {
L1EthRpc string // L1 RPC Url L1EthRpc string // L1 RPC Url
GameFactoryAddress common.Address // Address of the dispute game factory GameFactoryAddress common.Address // Address of the dispute game factory
GameAddress common.Address // Address of the fault game GameAllowlist []common.Address // Allowlist of fault game addresses
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
TraceType TraceType // Type of trace TraceType TraceType // Type of trace
...@@ -157,7 +158,7 @@ func (c Config) Check() error { ...@@ -157,7 +158,7 @@ func (c Config) Check() error {
if c.CannonL2GenesisPath != "" { if c.CannonL2GenesisPath != "" {
return ErrCannonNetworkAndL2Genesis return ErrCannonNetworkAndL2Genesis
} }
if _, ok := chaincfg.NetworksByName[c.CannonNetwork]; !ok { if ch := chaincfg.ChainByName(c.CannonNetwork); ch == nil {
return fmt.Errorf("%w: %v", ErrCannonNetworkUnknown, c.CannonNetwork) return fmt.Errorf("%w: %v", ErrCannonNetworkUnknown, c.CannonNetwork)
} }
} }
......
...@@ -3,9 +3,10 @@ package config ...@@ -3,9 +3,10 @@ package config
import ( import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
) )
var ( var (
...@@ -68,9 +69,9 @@ func TestGameFactoryAddressRequired(t *testing.T) { ...@@ -68,9 +69,9 @@ func TestGameFactoryAddressRequired(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingGameFactoryAddress) require.ErrorIs(t, config.Check(), ErrMissingGameFactoryAddress)
} }
func TestGameAddressNotRequired(t *testing.T) { func TestGameAllowlistNotRequired(t *testing.T) {
config := validConfig(TraceTypeCannon) config := validConfig(TraceTypeCannon)
config.GameAddress = common.Address{} config.GameAllowlist = []common.Address{}
require.NoError(t, config.Check()) require.NoError(t, config.Check())
} }
......
...@@ -4,13 +4,11 @@ import ( ...@@ -4,13 +4,11 @@ import (
"context" "context"
"math/big" "math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
) )
type FaultDisputeGameCaller interface { type FaultDisputeGameCaller interface {
...@@ -19,62 +17,39 @@ type FaultDisputeGameCaller interface { ...@@ -19,62 +17,39 @@ type FaultDisputeGameCaller interface {
} }
type FaultCaller struct { type FaultCaller struct {
FaultDisputeGameCaller contract FaultDisputeGameCaller
log log.Logger
} }
func NewFaultCaller(caller FaultDisputeGameCaller, log log.Logger) *FaultCaller { func NewFaultCaller(caller FaultDisputeGameCaller) *FaultCaller {
return &FaultCaller{ return &FaultCaller{
caller, caller,
log,
} }
} }
func NewFaultCallerFromBindings(fdgAddr common.Address, client *ethclient.Client, log log.Logger) (*FaultCaller, error) { func NewFaultCallerFromBindings(fdgAddr common.Address, client *ethclient.Client) (*FaultCaller, error) {
caller, err := bindings.NewFaultDisputeGameCaller(fdgAddr, client) caller, err := bindings.NewFaultDisputeGameCaller(fdgAddr, client)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &FaultCaller{ return &FaultCaller{
caller, caller,
log,
}, nil }, nil
} }
// LogGameInfo logs the game info.
func (fc *FaultCaller) LogGameInfo(ctx context.Context) {
status, err := fc.GetGameStatus(ctx)
if err != nil {
fc.log.Error("failed to get game status", "err", err)
return
}
claimLen, err := fc.GetClaimDataLength(ctx)
if err != nil {
fc.log.Error("failed to get claim count", "err", err)
return
}
fc.log.Info("Game info", "claims", claimLen, "status", status)
}
// GetGameStatus returns the current game status. // GetGameStatus returns the current game status.
// 0: In Progress // 0: In Progress
// 1: Challenger Won // 1: Challenger Won
// 2: Defender Won // 2: Defender Won
func (fc *FaultCaller) GetGameStatus(ctx context.Context) (types.GameStatus, error) { func (fc *FaultCaller) GetGameStatus(ctx context.Context) (types.GameStatus, error) {
status, err := fc.Status(&bind.CallOpts{Context: ctx}) status, err := fc.contract.Status(&bind.CallOpts{Context: ctx})
return types.GameStatus(status), err return types.GameStatus(status), err
} }
// GetClaimDataLength returns the number of claims in the game. // GetClaimCount returns the number of claims in the game.
func (fc *FaultCaller) GetClaimDataLength(ctx context.Context) (*big.Int, error) { func (fc *FaultCaller) GetClaimCount(ctx context.Context) (uint64, error) {
return fc.ClaimDataLen(&bind.CallOpts{Context: ctx}) count, err := fc.contract.ClaimDataLen(&bind.CallOpts{Context: ctx})
}
func (fc *FaultCaller) LogClaimDataLength(ctx context.Context) {
claimLen, err := fc.GetClaimDataLength(ctx)
if err != nil { if err != nil {
fc.log.Error("failed to get claim count", "err", err) return 0, err
return
} }
fc.log.Info("Number of claims", "length", claimLen) return count.Uint64(), nil
} }
...@@ -64,7 +64,7 @@ func TestFaultCaller_GetGameStatus(t *testing.T) { ...@@ -64,7 +64,7 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
fc := NewFaultCaller(test.caller, nil) fc := NewFaultCaller(test.caller)
status, err := fc.GetGameStatus(context.Background()) status, err := fc.GetGameStatus(context.Background())
require.Equal(t, test.expectedStatus, status) require.Equal(t, test.expectedStatus, status)
require.Equal(t, test.expectedErr, err) require.Equal(t, test.expectedErr, err)
...@@ -72,11 +72,11 @@ func TestFaultCaller_GetGameStatus(t *testing.T) { ...@@ -72,11 +72,11 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
} }
} }
func TestFaultCaller_GetClaimDataLength(t *testing.T) { func TestFaultCaller_GetClaimCount(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
caller FaultDisputeGameCaller caller FaultDisputeGameCaller
expectedClaimDataLen *big.Int expectedClaimDataLen uint64
expectedErr error expectedErr error
}{ }{
{ {
...@@ -84,7 +84,7 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) { ...@@ -84,7 +84,7 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) {
caller: &mockFaultDisputeGameCaller{ caller: &mockFaultDisputeGameCaller{
claimDataLen: big.NewInt(1), claimDataLen: big.NewInt(1),
}, },
expectedClaimDataLen: big.NewInt(1), expectedClaimDataLen: 1,
expectedErr: nil, expectedErr: nil,
}, },
{ {
...@@ -92,15 +92,15 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) { ...@@ -92,15 +92,15 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) {
caller: &mockFaultDisputeGameCaller{ caller: &mockFaultDisputeGameCaller{
errClaimDataLen: true, errClaimDataLen: true,
}, },
expectedClaimDataLen: nil, expectedClaimDataLen: 0,
expectedErr: errMock, expectedErr: errMock,
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
fc := NewFaultCaller(test.caller, nil) fc := NewFaultCaller(test.caller)
claimDataLen, err := fc.GetClaimDataLength(context.Background()) claimDataLen, err := fc.GetClaimCount(context.Background())
require.Equal(t, test.expectedClaimDataLen, claimDataLen) require.Equal(t, test.expectedClaimDataLen, claimDataLen)
require.Equal(t, test.expectedErr, err) require.Equal(t, test.expectedErr, err)
}) })
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"math/big" "math/big"
"time" "time"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -24,24 +25,38 @@ type gameSource interface { ...@@ -24,24 +25,38 @@ type gameSource interface {
type gameMonitor struct { type gameMonitor struct {
logger log.Logger logger log.Logger
clock clock.Clock
source gameSource source gameSource
createPlayer playerCreator createPlayer playerCreator
fetchBlockNumber blockNumberFetcher fetchBlockNumber blockNumberFetcher
allowedGame common.Address allowedGames []common.Address
players map[common.Address]gamePlayer players map[common.Address]gamePlayer
} }
func newGameMonitor(logger log.Logger, fetchBlockNumber blockNumberFetcher, allowedGame common.Address, source gameSource, createGame playerCreator) *gameMonitor { func newGameMonitor(logger log.Logger, cl clock.Clock, fetchBlockNumber blockNumberFetcher, allowedGames []common.Address, source gameSource, createGame playerCreator) *gameMonitor {
return &gameMonitor{ return &gameMonitor{
logger: logger, logger: logger,
clock: cl,
source: source, source: source,
createPlayer: createGame, createPlayer: createGame,
fetchBlockNumber: fetchBlockNumber, fetchBlockNumber: fetchBlockNumber,
allowedGame: allowedGame, allowedGames: allowedGames,
players: make(map[common.Address]gamePlayer), players: make(map[common.Address]gamePlayer),
} }
} }
func (m *gameMonitor) allowedGame(game common.Address) bool {
if len(m.allowedGames) == 0 {
return true
}
for _, allowed := range m.allowedGames {
if allowed == game {
return true
}
}
return false
}
func (m *gameMonitor) progressGames(ctx context.Context) error { func (m *gameMonitor) progressGames(ctx context.Context) error {
blockNum, err := m.fetchBlockNumber(ctx) blockNum, err := m.fetchBlockNumber(ctx)
if err != nil { if err != nil {
...@@ -52,7 +67,7 @@ func (m *gameMonitor) progressGames(ctx context.Context) error { ...@@ -52,7 +67,7 @@ func (m *gameMonitor) progressGames(ctx context.Context) error {
return fmt.Errorf("failed to load games: %w", err) return fmt.Errorf("failed to load games: %w", err)
} }
for _, game := range games { for _, game := range games {
if m.allowedGame != (common.Address{}) && m.allowedGame != game.Proxy { if !m.allowedGame(game.Proxy) {
m.logger.Debug("Skipping game not on allow list", "game", game.Proxy) m.logger.Debug("Skipping game not on allow list", "game", game.Proxy)
continue continue
} }
...@@ -86,11 +101,8 @@ func (m *gameMonitor) MonitorGames(ctx context.Context) error { ...@@ -86,11 +101,8 @@ func (m *gameMonitor) MonitorGames(ctx context.Context) error {
if err != nil { if err != nil {
m.logger.Error("Failed to progress games", "err", err) m.logger.Error("Failed to progress games", "err", err)
} }
select { if err := m.clock.SleepCtx(ctx, 300*time.Millisecond); err != nil {
case <-time.After(300 * time.Millisecond): return err
// Continue
case <-ctx.Done():
return ctx.Err()
} }
} }
} }
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -13,7 +14,7 @@ import ( ...@@ -13,7 +14,7 @@ import (
) )
func TestMonitorExitsWhenContextDone(t *testing.T) { func TestMonitorExitsWhenContextDone(t *testing.T) {
monitor, _, _ := setupMonitorTest(t, common.Address{}) monitor, _, _ := setupMonitorTest(t, []common.Address{common.Address{}})
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
cancel() cancel()
err := monitor.MonitorGames(ctx) err := monitor.MonitorGames(ctx)
...@@ -21,7 +22,7 @@ func TestMonitorExitsWhenContextDone(t *testing.T) { ...@@ -21,7 +22,7 @@ func TestMonitorExitsWhenContextDone(t *testing.T) {
} }
func TestMonitorCreateAndProgressGameAgents(t *testing.T) { func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
monitor, source, games := setupMonitorTest(t, common.Address{}) monitor, source, games := setupMonitorTest(t, []common.Address{})
addr1 := common.Address{0xaa} addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb} addr2 := common.Address{0xbb}
...@@ -54,7 +55,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) { ...@@ -54,7 +55,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) { func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
addr1 := common.Address{0xaa} addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb} addr2 := common.Address{0xbb}
monitor, source, games := setupMonitorTest(t, addr2) monitor, source, games := setupMonitorTest(t, []common.Address{addr2})
source.games = []FaultDisputeGame{ source.games = []FaultDisputeGame{
{ {
...@@ -76,7 +77,7 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) { ...@@ -76,7 +77,7 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
require.Equal(t, 1, games.created[addr2].progressCount) require.Equal(t, 1, games.created[addr2].progressCount)
} }
func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, *stubGameSource, *createdGames) { func setupMonitorTest(t *testing.T, allowedGames []common.Address) (*gameMonitor, *stubGameSource, *createdGames) {
logger := testlog.Logger(t, log.LvlDebug) logger := testlog.Logger(t, log.LvlDebug)
source := &stubGameSource{} source := &stubGameSource{}
games := &createdGames{ games := &createdGames{
...@@ -86,7 +87,7 @@ func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, * ...@@ -86,7 +87,7 @@ func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, *
fetchBlockNum := func(ctx context.Context) (uint64, error) { fetchBlockNum := func(ctx context.Context) (uint64, error) {
return 1234, nil return 1234, nil
} }
monitor := newGameMonitor(logger, fetchBlockNum, allowedGame, source, games.CreateGame) monitor := newGameMonitor(logger, clock.SystemClock, fetchBlockNum, allowedGames, source, games.CreateGame)
return monitor, source, games return monitor, source, games
} }
......
...@@ -21,7 +21,7 @@ type Actor interface { ...@@ -21,7 +21,7 @@ type Actor interface {
type GameInfo interface { type GameInfo interface {
GetGameStatus(context.Context) (types.GameStatus, error) GetGameStatus(context.Context) (types.GameStatus, error)
LogGameInfo(ctx context.Context) GetClaimCount(context.Context) (uint64, error)
} }
type GamePlayer struct { type GamePlayer struct {
...@@ -80,7 +80,7 @@ func NewGamePlayer( ...@@ -80,7 +80,7 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to create the responder: %w", err) return nil, fmt.Errorf("failed to create the responder: %w", err)
} }
caller, err := NewFaultCallerFromBindings(addr, client, logger) caller, err := NewFaultCallerFromBindings(addr, client)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to bind the fault contract: %w", err) return nil, fmt.Errorf("failed to bind the fault contract: %w", err)
} }
...@@ -100,21 +100,32 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) bool { ...@@ -100,21 +100,32 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) bool {
} }
if status, err := g.caller.GetGameStatus(ctx); err != nil { if status, err := g.caller.GetGameStatus(ctx); err != nil {
g.logger.Warn("Unable to retrieve game status", "err", err) g.logger.Warn("Unable to retrieve game status", "err", err)
} else if status != 0 {
var expectedStatus types.GameStatus
if g.agreeWithProposedOutput {
expectedStatus = types.GameStatusChallengerWon
} else {
expectedStatus = types.GameStatusDefenderWon
}
if expectedStatus == status {
g.logger.Info("Game won", "status", status)
} else {
g.logger.Error("Game lost", "status", status)
}
return true
} else { } else {
g.caller.LogGameInfo(ctx) g.logGameStatus(ctx, status)
return status != types.GameStatusInProgress
} }
return false return false
} }
func (g *GamePlayer) logGameStatus(ctx context.Context, status types.GameStatus) {
if status == types.GameStatusInProgress {
claimCount, err := g.caller.GetClaimCount(ctx)
if err != nil {
g.logger.Error("Failed to get claim count for in progress game", "err", err)
return
}
g.logger.Info("Game info", "claims", claimCount, "status", status)
return
}
var expectedStatus types.GameStatus
if g.agreeWithProposedOutput {
expectedStatus = types.GameStatusChallengerWon
} else {
expectedStatus = types.GameStatusDefenderWon
}
if expectedStatus == status {
g.logger.Info("Game won", "status", status)
} else {
g.logger.Error("Game lost", "status", status)
}
}
...@@ -11,27 +11,23 @@ import ( ...@@ -11,27 +11,23 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestProgressGameAndLogState(t *testing.T) {
_, game, actor, gameInfo := setupProgressGameTest(t, true)
done := game.ProgressGame(context.Background())
require.False(t, done, "should not be done")
require.Equal(t, 1, actor.callCount, "should perform next actions")
require.Equal(t, 1, gameInfo.logCount, "should log latest game state")
}
func TestProgressGame_LogErrorFromAct(t *testing.T) { func TestProgressGame_LogErrorFromAct(t *testing.T) {
handler, game, actor, gameInfo := setupProgressGameTest(t, true) handler, game, actor, _ := setupProgressGameTest(t, true)
actor.err = errors.New("boom") actor.err = errors.New("boom")
done := game.ProgressGame(context.Background()) done := game.ProgressGame(context.Background())
require.False(t, done, "should not be done") require.False(t, done, "should not be done")
require.Equal(t, 1, actor.callCount, "should perform next actions") require.Equal(t, 1, actor.callCount, "should perform next actions")
require.Equal(t, 1, gameInfo.logCount, "should log latest game state")
errLog := handler.FindLog(log.LvlError, "Error when acting on game") errLog := handler.FindLog(log.LvlError, "Error when acting on game")
require.NotNil(t, errLog, "should log error") require.NotNil(t, errLog, "should log error")
require.Equal(t, actor.err, errLog.GetContextValue("err")) require.Equal(t, actor.err, errLog.GetContextValue("err"))
// Should still log game status
msg := handler.FindLog(log.LvlInfo, "Game info")
require.NotNil(t, msg)
require.Equal(t, uint64(1), msg.GetContextValue("claims"))
} }
func TestProgressGame_LogErrorWhenGameLost(t *testing.T) { func TestProgressGame_LogGameStatus(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
status types.GameStatus status types.GameStatus
...@@ -67,16 +63,23 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) { ...@@ -67,16 +63,23 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
logLevel: log.LvlInfo, logLevel: log.LvlInfo,
logMsg: "Game won", logMsg: "Game won",
}, },
{
name: "GameInProgress",
status: types.GameStatusInProgress,
agreeWithOutput: true,
logLevel: log.LvlInfo,
logMsg: "Game info",
},
} }
for _, test := range tests { for _, test := range tests {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
handler, game, _, gameInfo := setupProgressGameTest(t, test.agreeWithOutput) handler, game, actor, gameInfo := setupProgressGameTest(t, test.agreeWithOutput)
gameInfo.status = test.status gameInfo.status = test.status
done := game.ProgressGame(context.Background()) done := game.ProgressGame(context.Background())
require.True(t, done, "should be done") require.Equal(t, 1, actor.callCount, "should perform next actions")
require.Equal(t, 0, gameInfo.logCount, "should not log latest game state") require.Equal(t, test.status != types.GameStatusInProgress, done, "should be done when not in progress")
errLog := handler.FindLog(test.logLevel, test.logMsg) errLog := handler.FindLog(test.logLevel, test.logMsg)
require.NotNil(t, errLog, "should log game result") require.NotNil(t, errLog, "should log game result")
require.Equal(t, test.status, errLog.GetContextValue("status")) require.Equal(t, test.status, errLog.GetContextValue("status"))
...@@ -91,7 +94,7 @@ func setupProgressGameTest(t *testing.T, agreeWithProposedRoot bool) (*testlog.C ...@@ -91,7 +94,7 @@ func setupProgressGameTest(t *testing.T, agreeWithProposedRoot bool) (*testlog.C
} }
logger.SetHandler(handler) logger.SetHandler(handler)
actor := &stubActor{} actor := &stubActor{}
gameInfo := &stubGameInfo{} gameInfo := &stubGameInfo{claimCount: 1}
game := &GamePlayer{ game := &GamePlayer{
agent: actor, agent: actor,
agreeWithProposedOutput: agreeWithProposedRoot, agreeWithProposedOutput: agreeWithProposedRoot,
...@@ -112,15 +115,15 @@ func (a *stubActor) Act(ctx context.Context) error { ...@@ -112,15 +115,15 @@ func (a *stubActor) Act(ctx context.Context) error {
} }
type stubGameInfo struct { type stubGameInfo struct {
status types.GameStatus status types.GameStatus
err error claimCount uint64
logCount int err error
} }
func (s *stubGameInfo) GetGameStatus(ctx context.Context) (types.GameStatus, error) { func (s *stubGameInfo) GetGameStatus(ctx context.Context) (types.GameStatus, error) {
return s.status, s.err return s.status, s.err
} }
func (s *stubGameInfo) LogGameInfo(ctx context.Context) { func (s *stubGameInfo) GetClaimCount(ctx context.Context) (uint64, error) {
s.logCount++ return s.claimCount, s.err
} }
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/version" "github.com/ethereum-optimism/optimism/op-challenger/version"
"github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/clock"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -33,6 +34,7 @@ type service struct { ...@@ -33,6 +34,7 @@ type service struct {
// NewService creates a new Service. // NewService creates a new Service.
func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*service, error) { func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*service, error) {
cl := clock.SystemClock
m := metrics.NewMetrics() m := metrics.NewMetrics()
txMgr, err := txmgr.NewSimpleTxManager("challenger", logger, &m.TxMetrics, cfg.TxMgrConfig) txMgr, err := txmgr.NewSimpleTxManager("challenger", logger, &m.TxMetrics, cfg.TxMgrConfig)
if err != nil { if err != nil {
...@@ -71,7 +73,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se ...@@ -71,7 +73,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
} }
loader := NewGameLoader(factory) loader := NewGameLoader(factory)
monitor := newGameMonitor(logger, client.BlockNumber, cfg.GameAddress, loader, func(addr common.Address) (gamePlayer, error) { monitor := newGameMonitor(logger, cl, client.BlockNumber, cfg.GameAllowlist, loader, func(addr common.Address) (gamePlayer, error) {
return NewGamePlayer(ctx, logger, cfg, addr, txMgr, client) return NewGamePlayer(ctx, logger, cfg, addr, txMgr, client)
}) })
......
...@@ -60,7 +60,7 @@ func NewGameState(agreeWithProposedOutput bool, root Claim, depth uint64) *gameS ...@@ -60,7 +60,7 @@ func NewGameState(agreeWithProposedOutput bool, root Claim, depth uint64) *gameS
} }
} }
// AgreeWithLevel returns if the game state agrees with the provided claim level. // AgreeWithClaimLevel returns if the game state agrees with the provided claim level.
func (g *gameState) AgreeWithClaimLevel(claim Claim) bool { func (g *gameState) AgreeWithClaimLevel(claim Claim) bool {
isOddLevel := claim.Depth()%2 == 1 isOddLevel := claim.Depth()%2 == 1
// If we agree with the proposed output, we agree with odd levels // If we agree with the proposed output, we agree with odd levels
......
...@@ -4,6 +4,9 @@ import ( ...@@ -4,6 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/chaincfg"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
...@@ -12,9 +15,6 @@ import ( ...@@ -12,9 +15,6 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof" oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
) )
const ( const (
...@@ -37,10 +37,11 @@ var ( ...@@ -37,10 +37,11 @@ var (
Usage: "Address of the fault game factory contract.", Usage: "Address of the fault game factory contract.",
EnvVars: prefixEnvVars("GAME_FACTORY_ADDRESS"), EnvVars: prefixEnvVars("GAME_FACTORY_ADDRESS"),
} }
GameAddressFlag = &cli.StringFlag{ GameAllowlistFlag = &cli.StringSliceFlag{
Name: "game-address", Name: "game-allowlist",
Usage: "Address of the Fault Game contract.", Usage: "List of Fault Game contract addresses the challenger is allowed to play. " +
EnvVars: prefixEnvVars("GAME_ADDRESS"), "If empty, the challenger will play all games.",
EnvVars: prefixEnvVars("GAME_ALLOWLIST"),
} }
TraceTypeFlag = &cli.GenericFlag{ TraceTypeFlag = &cli.GenericFlag{
Name: "trace-type", Name: "trace-type",
...@@ -121,7 +122,7 @@ var requiredFlags = []cli.Flag{ ...@@ -121,7 +122,7 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags // optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{ var optionalFlags = []cli.Flag{
AlphabetFlag, AlphabetFlag,
GameAddressFlag, GameAllowlistFlag,
CannonNetworkFlag, CannonNetworkFlag,
CannonRollupConfigFlag, CannonRollupConfigFlag,
CannonL2GenesisFlag, CannonL2GenesisFlag,
...@@ -154,11 +155,13 @@ func CheckRequired(ctx *cli.Context) error { ...@@ -154,11 +155,13 @@ func CheckRequired(ctx *cli.Context) error {
gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name))) gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name)))
switch gameType { switch gameType {
case config.TraceTypeCannon: case config.TraceTypeCannon:
if !ctx.IsSet(CannonNetworkFlag.Name) && !(ctx.IsSet(CannonRollupConfigFlag.Name) && ctx.IsSet(CannonL2GenesisFlag.Name)) { if !ctx.IsSet(CannonNetworkFlag.Name) &&
!(ctx.IsSet(CannonRollupConfigFlag.Name) && ctx.IsSet(CannonL2GenesisFlag.Name)) {
return fmt.Errorf("flag %v or %v and %v is required", return fmt.Errorf("flag %v or %v and %v is required",
CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name) CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name)
} }
if ctx.IsSet(CannonNetworkFlag.Name) && (ctx.IsSet(CannonRollupConfigFlag.Name) || ctx.IsSet(CannonL2GenesisFlag.Name)) { if ctx.IsSet(CannonNetworkFlag.Name) &&
(ctx.IsSet(CannonRollupConfigFlag.Name) || ctx.IsSet(CannonL2GenesisFlag.Name)) {
return fmt.Errorf("flag %v can not be used with %v and %v", return fmt.Errorf("flag %v can not be used with %v and %v",
CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name) CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name)
} }
...@@ -196,11 +199,14 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) { ...@@ -196,11 +199,14 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var gameAddress common.Address var allowedGames []common.Address
if ctx.IsSet(GameAddressFlag.Name) { if ctx.StringSlice(GameAllowlistFlag.Name) != nil {
gameAddress, err = opservice.ParseAddress(ctx.String(GameAddressFlag.Name)) for _, addr := range ctx.StringSlice(GameAllowlistFlag.Name) {
if err != nil { gameAddress, err := opservice.ParseAddress(addr)
return nil, err if err != nil {
return nil, err
}
allowedGames = append(allowedGames, gameAddress)
} }
} }
...@@ -215,7 +221,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) { ...@@ -215,7 +221,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
L1EthRpc: ctx.String(L1EthRpcFlag.Name), L1EthRpc: ctx.String(L1EthRpcFlag.Name),
TraceType: traceTypeFlag, TraceType: traceTypeFlag,
GameFactoryAddress: gameFactoryAddress, GameFactoryAddress: gameFactoryAddress,
GameAddress: gameAddress, GameAllowlist: allowedGames,
AlphabetTrace: ctx.String(AlphabetFlag.Name), AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonNetwork: ctx.String(CannonNetworkFlag.Name), CannonNetwork: ctx.String(CannonNetworkFlag.Name),
CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name), CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name),
......
...@@ -38,7 +38,10 @@ func WithFactoryAddress(addr common.Address) Option { ...@@ -38,7 +38,10 @@ func WithFactoryAddress(addr common.Address) Option {
func WithGameAddress(addr common.Address) Option { func WithGameAddress(addr common.Address) Option {
return func(c *config.Config) { return func(c *config.Config) {
c.GameAddress = addr if c.GameAllowlist == nil {
c.GameAllowlist = make([]common.Address, 0)
}
c.GameAllowlist = append(c.GameAllowlist, addr)
} }
} }
......
...@@ -5,6 +5,8 @@ import ( ...@@ -5,6 +5,8 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum/go-ethereum/common"
) )
type AlphabetGameHelper struct { type AlphabetGameHelper struct {
...@@ -16,7 +18,7 @@ func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint str ...@@ -16,7 +18,7 @@ func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint str
opts := []challenger.Option{ opts := []challenger.Option{
func(c *config.Config) { func(c *config.Config) {
c.GameFactoryAddress = g.factoryAddr c.GameFactoryAddress = g.factoryAddr
c.GameAddress = g.addr c.GameAllowlist = []common.Address{g.addr}
c.TraceType = config.TraceTypeAlphabet c.TraceType = config.TraceTypeAlphabet
// By default the challenger agrees with the root claim (thus disagrees with the proposed output) // By default the challenger agrees with the root claim (thus disagrees with the proposed output)
// This can be overridden by passing in options // This can be overridden by passing in options
......
...@@ -15,12 +15,14 @@ import ( ...@@ -15,12 +15,14 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/alphabet" "github.com/ethereum-optimism/optimism/op-challenger/fault/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/fault/cannon" "github.com/ethereum-optimism/optimism/op-challenger/fault/cannon"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -106,8 +108,11 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s ...@@ -106,8 +108,11 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
extraData := make([]byte, 64) extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber) binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
binary.BigEndian.PutUint64(extraData[56:], l1Head.Uint64()) binary.BigEndian.PutUint64(extraData[56:], l1Head.Uint64())
tx, err := h.factory.Create(h.opts, alphabetGameType, rootClaim, extraData) tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, alphabetGameType, rootClaim, extraData)
})
h.require.NoError(err, "create fault dispute game") h.require.NoError(err, "create fault dispute game")
h.opts.GasLimit = 0
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash()) rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "wait for create fault dispute game receipt to be OK") h.require.NoError(err, "wait for create fault dispute game receipt to be OK")
h.require.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event") h.require.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event")
...@@ -191,7 +196,9 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, l2BlockNumber uint ...@@ -191,7 +196,9 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, l2BlockNumber uint
extraData := make([]byte, 64) extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber) binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
binary.BigEndian.PutUint64(extraData[56:], l1Head.Uint64()) binary.BigEndian.PutUint64(extraData[56:], l1Head.Uint64())
tx, err := h.factory.Create(h.opts, cannonGameType, rootClaim, extraData) tx, err := transactions.PadGasEstimate(h.opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return h.factory.Create(opts, cannonGameType, rootClaim, extraData)
})
h.require.NoError(err, "create fault dispute game") h.require.NoError(err, "create fault dispute game")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash()) rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
h.require.NoError(err, "wait for create fault dispute game receipt to be OK") h.require.NoError(err, "wait for create fault dispute game receipt to be OK")
......
package transactions
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
)
// TxBuilder creates and sends a transaction using the supplied bind.TransactOpts.
// Returns the created transaction and any error reported.
type TxBuilder func(opts *bind.TransactOpts) (*types.Transaction, error)
// PadGasEstimate multiplies the gas estimate for a transaction by the specified paddingFactor before sending the
// actual transaction. Useful for cases where the gas required is variable.
// The builder will be invoked twice, first with NoSend=true to estimate the gas and the second time with
// NoSend=false and GasLimit including the requested padding.
func PadGasEstimate(opts *bind.TransactOpts, paddingFactor float64, builder TxBuilder) (*types.Transaction, error) {
// Take a copy of the opts to avoid mutating the original
o := *opts
o.NoSend = true
tx, err := builder(&o)
if err != nil {
return nil, fmt.Errorf("failed to estimate gas: %w", err)
}
gas := float64(tx.Gas()) * paddingFactor
o.GasLimit = uint64(gas)
o.NoSend = false
return builder(&o)
}
...@@ -56,8 +56,11 @@ func (s *jsonRawString) UnmarshalJSON(input []byte) error { ...@@ -56,8 +56,11 @@ func (s *jsonRawString) UnmarshalJSON(input []byte) error {
// printDebugTrace logs debug_traceTransaction output to aid in debugging unexpected receipt statuses // printDebugTrace logs debug_traceTransaction output to aid in debugging unexpected receipt statuses
func printDebugTrace(ctx context.Context, client *ethclient.Client, txHash common.Hash) { func printDebugTrace(ctx context.Context, client *ethclient.Client, txHash common.Hash) {
var trace jsonRawString var trace jsonRawString
options := map[string]any{} options := map[string]any{
options["enableReturnData"] = true "enableReturnData": true,
"tracer": "callTracer",
"tracerConfig": map[string]any{},
}
err := client.Client().CallContext(ctx, &trace, "debug_traceTransaction", hexutil.Bytes(txHash.Bytes()), options) err := client.Client().CallContext(ctx, &trace, "debug_traceTransaction", hexutil.Bytes(txHash.Bytes()), options)
if err != nil { if err != nil {
fmt.Printf("TxTrace unavailable: %v\n", err) fmt.Printf("TxTrace unavailable: %v\n", err)
......
...@@ -24,6 +24,10 @@ import ( ...@@ -24,6 +24,10 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
// Force-load the tracer engines to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
) )
var ( var (
......
...@@ -586,7 +586,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -586,7 +586,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
} }
} }
c.Rollup.LogDescription(cfg.Loggers[name], chaincfg.L2ChainIDToNetworkName) c.Rollup.LogDescription(cfg.Loggers[name], chaincfg.L2ChainIDToNetworkDisplayName)
node, err := rollupNode.New(context.Background(), &c, cfg.Loggers[name], snapLog, "", metrics.NewMetrics("")) node, err := rollupNode.New(context.Background(), &c, cfg.Loggers[name], snapLog, "", metrics.NewMetrics(""))
if err != nil { if err != nil {
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -29,19 +30,12 @@ func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l ...@@ -29,19 +30,12 @@ func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l
require.Nil(t, err) require.Nil(t, err)
// Finally send TX // Finally send TX
l1Opts.NoSend = true
tx, err := depositContract.DepositTransaction(l1Opts, l2Opts.ToAddr, l2Opts.Value, l2Opts.GasLimit, l2Opts.IsCreation, l2Opts.Data)
require.Nil(t, err, "with deposit tx")
l1Opts.NoSend = false
// Add 10% padding for the L1 gas limit because the estimation process can be affected by the 1559 style cost scale // Add 10% padding for the L1 gas limit because the estimation process can be affected by the 1559 style cost scale
// for buying L2 gas in the portal contracts. // for buying L2 gas in the portal contracts.
l1Opts.GasLimit = tx.Gas() + (tx.Gas() / 10) tx, err := transactions.PadGasEstimate(l1Opts, 1.1, func(opts *bind.TransactOpts) (*types.Transaction, error) {
return depositContract.DepositTransaction(opts, l2Opts.ToAddr, l2Opts.Value, l2Opts.GasLimit, l2Opts.IsCreation, l2Opts.Data)
// Now resend with gas specified })
tx, err = depositContract.DepositTransaction(l1Opts, l2Opts.ToAddr, l2Opts.Value, l2Opts.GasLimit, l2Opts.IsCreation, l2Opts.Data)
require.Nil(t, err, "with deposit tx") require.Nil(t, err, "with deposit tx")
l1Opts.GasLimit = 0
// Wait for transaction on L1 // Wait for transaction on L1
receipt, err := waitForTransaction(tx.Hash(), l1Client, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) receipt, err := waitForTransaction(tx.Hash(), l1Client, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
......
...@@ -2,135 +2,100 @@ package chaincfg ...@@ -2,135 +2,100 @@ package chaincfg
import ( import (
"fmt" "fmt"
"math/big" "strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum-optimism/superchain-registry/superchain"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
) )
var Mainnet = rollup.Config{ var Mainnet, Goerli, Sepolia *rollup.Config
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec04108"),
Number: 17422590,
},
L2: eth.BlockID{
Hash: common.HexToHash("0xdbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3"),
Number: 105235063,
},
L2Time: 1686068903,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x6887246668a3b87f54deb3b94ba47a6f63f32985"),
Overhead: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000000bc")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000a6fe0")),
GasLimit: 30_000_000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(10),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"),
DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"),
L1SystemConfigAddress: common.HexToAddress("0x229047fed2591dbec1eF1118d64F7aF3dB9EB290"),
RegolithTime: u64Ptr(0),
}
var Goerli = rollup.Config{
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x6ffc1bf3754c01f6bb9fe057c1578b87a8571ce2e9be5ca14bace6eccfd336c7"),
Number: 8300214,
},
L2: eth.BlockID{
Hash: common.HexToHash("0x0f783549ea4313b784eadd9b8e8a69913b368b7366363ea814d7707ac505175f"),
Number: 4061224,
},
L2Time: 1673550516,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x7431310e026B69BFC676C0013E12A1A11411EEc9"),
Overhead: eth.Bytes32(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000834")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000f4240")),
GasLimit: 25_000_000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(5),
L2ChainID: big.NewInt(420),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000420"),
DepositContractAddress: common.HexToAddress("0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383"),
L1SystemConfigAddress: common.HexToAddress("0xAe851f927Ee40dE99aaBb7461C00f9622ab91d60"),
RegolithTime: u64Ptr(1679079600),
}
var Sepolia = rollup.Config{
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b"),
Number: 4071408,
},
L2: eth.BlockID{
Hash: common.HexToHash("0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"),
Number: 0,
},
L2Time: 1691802540,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x8F23BB38F531600e5d8FDDaAEC41F13FaB46E98c"),
Overhead: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000000bc")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000a6fe0")),
GasLimit: 30000000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(11155111),
L2ChainID: big.NewInt(11155420),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"),
DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"),
L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"),
RegolithTime: u64Ptr(0),
}
var NetworksByName = map[string]rollup.Config{ func init() {
"goerli": Goerli, mustCfg := func(name string) *rollup.Config {
"mainnet": Mainnet, cfg, err := GetRollupConfig(name)
"sepolia": Sepolia, if err != nil {
panic(fmt.Errorf("failed to load rollup config %q: %w", name, err))
}
return cfg
}
Mainnet = mustCfg("op-mainnet")
Goerli = mustCfg("op-goerli")
Sepolia = mustCfg("op-sepolia")
} }
var L2ChainIDToNetworkName = func() map[string]string { var L2ChainIDToNetworkDisplayName = func() map[string]string {
out := make(map[string]string) out := make(map[string]string)
for name, netCfg := range NetworksByName { for _, netCfg := range superchain.OPChains {
out[netCfg.L2ChainID.String()] = name out[fmt.Sprintf("%d", netCfg.ChainID)] = netCfg.Name
} }
return out return out
}() }()
// AvailableNetworks returns the selection of network configurations that is available by default.
// Other configurations that are part of the superchain-registry can be used with the --beta.network flag.
func AvailableNetworks() []string { func AvailableNetworks() []string {
return []string{"op-mainnet", "op-goerli", "op-sepolia"}
}
// BetaAvailableNetworks returns all available network configurations in the superchain-registry.
// This set of configurations is experimental, and may change at any time.
func BetaAvailableNetworks() []string {
var networks []string var networks []string
for name := range NetworksByName { for _, cfg := range superchain.OPChains {
networks = append(networks, name) networks = append(networks, cfg.Chain+"-"+cfg.Superchain)
} }
return networks return networks
} }
func GetRollupConfig(name string) (rollup.Config, error) { func IsAvailableNetwork(name string, beta bool) bool {
network, ok := NetworksByName[name] name = handleLegacyName(name)
if !ok { available := AvailableNetworks()
return rollup.Config{}, fmt.Errorf("invalid network %s", name) if beta {
available = BetaAvailableNetworks()
} }
for _, v := range available {
if v == name {
return true
}
}
return false
}
func handleLegacyName(name string) string {
switch name {
case "goerli":
return "op-goerli"
case "mainnet":
return "op-mainnet"
case "sepolia":
return "op-sepolia"
default:
return name
}
}
return network, nil // ChainByName returns a chain, from known available configurations, by name.
// ChainByName returns nil when the chain name is unknown.
func ChainByName(name string) *superchain.ChainConfig {
// Handle legacy name aliases
name = handleLegacyName(name)
for _, chainCfg := range superchain.OPChains {
if strings.EqualFold(chainCfg.Chain+"-"+chainCfg.Superchain, name) {
return chainCfg
}
}
return nil
} }
func u64Ptr(v uint64) *uint64 { func GetRollupConfig(name string) (*rollup.Config, error) {
return &v chainCfg := ChainByName(name)
if chainCfg == nil {
return nil, fmt.Errorf("invalid network %s", name)
}
rollupCfg, err := rollup.LoadOPStackRollupConfig(chainCfg.ChainID)
if err != nil {
return nil, fmt.Errorf("failed to load rollup config: %w", err)
}
return rollupCfg, nil
} }
package chaincfg
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
// TestGetRollupConfig tests that the configs sourced from the superchain-registry match
// the configs that were embedded in the op-node manually before the superchain-registry was utilized.
//
// The superchain-registry repository is a work in progress.
// At a later date, it will be proposed to, and must be approved by, Optimism Governance.
// Until that time, the configuration described in the superchain-registry is subject to change.
//
// This test ensures no op-node config-loading behavior changes before
// the superchain-registry is no longer deemed experimental.
func TestGetRollupConfig(t *testing.T) {
var configsByName = map[string]rollup.Config{
"goerli": goerliCfg,
"mainnet": mainnetCfg,
"sepolia": sepoliaCfg,
}
for name, expectedCfg := range configsByName {
require.True(t, IsAvailableNetwork(name, false))
gotCfg, err := GetRollupConfig(name)
require.NoError(t, err)
require.Equal(t, expectedCfg, *gotCfg, "rollup-configs from superchain-registry must match")
}
}
var mainnetCfg = rollup.Config{
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec04108"),
Number: 17422590,
},
L2: eth.BlockID{
Hash: common.HexToHash("0xdbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3"),
Number: 105235063,
},
L2Time: 1686068903,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x6887246668a3b87f54deb3b94ba47a6f63f32985"),
Overhead: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000000bc")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000a6fe0")),
GasLimit: 30_000_000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(10),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"),
DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"),
L1SystemConfigAddress: common.HexToAddress("0x229047fed2591dbec1eF1118d64F7aF3dB9EB290"),
RegolithTime: u64Ptr(0),
}
var goerliCfg = rollup.Config{
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x6ffc1bf3754c01f6bb9fe057c1578b87a8571ce2e9be5ca14bace6eccfd336c7"),
Number: 8300214,
},
L2: eth.BlockID{
Hash: common.HexToHash("0x0f783549ea4313b784eadd9b8e8a69913b368b7366363ea814d7707ac505175f"),
Number: 4061224,
},
L2Time: 1673550516,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x7431310e026B69BFC676C0013E12A1A11411EEc9"),
Overhead: eth.Bytes32(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000834")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000f4240")),
GasLimit: 25_000_000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(5),
L2ChainID: big.NewInt(420),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000420"),
DepositContractAddress: common.HexToAddress("0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383"),
L1SystemConfigAddress: common.HexToAddress("0xAe851f927Ee40dE99aaBb7461C00f9622ab91d60"),
RegolithTime: u64Ptr(1679079600),
}
var sepoliaCfg = rollup.Config{
Genesis: rollup.Genesis{
L1: eth.BlockID{
Hash: common.HexToHash("0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b"),
Number: 4071408,
},
L2: eth.BlockID{
Hash: common.HexToHash("0x102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d"),
Number: 0,
},
L2Time: 1691802540,
SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x8F23BB38F531600e5d8FDDaAEC41F13FaB46E98c"),
Overhead: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000000bc")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000a6fe0")),
GasLimit: 30000000,
},
},
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: big.NewInt(11155111),
L2ChainID: big.NewInt(11155420),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"),
DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"),
L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"),
RegolithTime: u64Ptr(0),
}
func u64Ptr(v uint64) *uint64 {
return &v
}
...@@ -104,9 +104,9 @@ func RollupNodeMain(ctx *cli.Context) error { ...@@ -104,9 +104,9 @@ func RollupNodeMain(ctx *cli.Context) error {
// Only pretty-print the banner if it is a terminal log. Other log it as key-value pairs. // Only pretty-print the banner if it is a terminal log. Other log it as key-value pairs.
if logCfg.Format == "terminal" { if logCfg.Format == "terminal" {
log.Info("rollup config:\n" + cfg.Rollup.Description(chaincfg.L2ChainIDToNetworkName)) log.Info("rollup config:\n" + cfg.Rollup.Description(chaincfg.L2ChainIDToNetworkDisplayName))
} else { } else {
cfg.Rollup.LogDescription(log, chaincfg.L2ChainIDToNetworkName) cfg.Rollup.LogDescription(log, chaincfg.L2ChainIDToNetworkDisplayName)
} }
n, err := node.New(context.Background(), cfg, log, snapshotLog, VersionWithMeta, m) n, err := node.New(context.Background(), cfg, log, snapshotLog, VersionWithMeta, m)
......
...@@ -229,6 +229,14 @@ var ( ...@@ -229,6 +229,14 @@ var (
Required: false, Required: false,
Value: false, Value: false,
} }
BetaExtraNetworks = &cli.BoolFlag{
Name: "beta.extra-networks",
Usage: fmt.Sprintf("Beta feature: enable selection of a predefined-network from the superchain-registry. "+
"The superchain-registry is experimental, and the availability of configurations may change."+
"Available networks: %s", strings.Join(chaincfg.BetaAvailableNetworks(), ", ")),
EnvVars: prefixEnvVars("BETA_EXTRA_NETWORKS"),
Hidden: true,
}
) )
var requiredFlags = []cli.Flag{ var requiredFlags = []cli.Flag{
...@@ -269,6 +277,7 @@ var optionalFlags = []cli.Flag{ ...@@ -269,6 +277,7 @@ var optionalFlags = []cli.Flag{
BackupL2UnsafeSyncRPCTrustRPC, BackupL2UnsafeSyncRPCTrustRPC,
L2EngineSyncEnabled, L2EngineSyncEnabled,
SkipSyncStartCheck, SkipSyncStartCheck,
BetaExtraNetworks,
} }
// Flags contains the list of configuration options available to the binary. // Flags contains the list of configuration options available to the binary.
......
...@@ -50,7 +50,8 @@ var ( ...@@ -50,7 +50,8 @@ var (
// Banning Flag - whether or not we want to act on the scoring // Banning Flag - whether or not we want to act on the scoring
Banning = &cli.BoolFlag{ Banning = &cli.BoolFlag{
Name: "p2p.ban.peers", Name: "p2p.ban.peers",
Usage: "Enables peer banning. This should ONLY be enabled once certain peer scoring is working correctly.", Usage: "Enables peer banning.",
Value: true,
Required: false, Required: false,
EnvVars: p2pEnv("PEER_BANNING"), EnvVars: p2pEnv("PEER_BANNING"),
} }
......
...@@ -43,7 +43,7 @@ func (testSuite *PeerParamsTestSuite) TestNewPeerScoreThresholds() { ...@@ -43,7 +43,7 @@ func (testSuite *PeerParamsTestSuite) TestNewPeerScoreThresholds() {
// TestGetPeerScoreParams validates the peer score parameters. // TestGetPeerScoreParams validates the peer score parameters.
func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_None() { func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_None() {
params, err := GetScoringParams("none", &chaincfg.Goerli) params, err := GetScoringParams("none", chaincfg.Goerli)
testSuite.NoError(err) testSuite.NoError(err)
testSuite.Nil(params) testSuite.Nil(params)
} }
...@@ -62,12 +62,12 @@ func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_Light() { ...@@ -62,12 +62,12 @@ func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_Light() {
testSuite.Equal(0.9261187281287935, decay) testSuite.Equal(0.9261187281287935, decay)
// Test the params // Test the params
scoringParams, err := GetScoringParams("light", &cfg) scoringParams, err := GetScoringParams("light", cfg)
peerParams := scoringParams.PeerScoring peerParams := scoringParams.PeerScoring
testSuite.NoError(err) testSuite.NoError(err)
// Topics should contain options for block topic // Topics should contain options for block topic
testSuite.Len(peerParams.Topics, 1) testSuite.Len(peerParams.Topics, 1)
topicParams, ok := peerParams.Topics[blocksTopicV1(&cfg)] topicParams, ok := peerParams.Topics[blocksTopicV1(cfg)]
testSuite.True(ok, "should have block topic params") testSuite.True(ok, "should have block topic params")
testSuite.NotZero(topicParams.TimeInMeshQuantum) testSuite.NotZero(topicParams.TimeInMeshQuantum)
testSuite.Equal(peerParams.TopicScoreCap, float64(34)) testSuite.Equal(peerParams.TopicScoreCap, float64(34))
...@@ -101,7 +101,7 @@ func (testSuite *PeerParamsTestSuite) TestParamsZeroBlockTime() { ...@@ -101,7 +101,7 @@ func (testSuite *PeerParamsTestSuite) TestParamsZeroBlockTime() {
cfg := chaincfg.Goerli cfg := chaincfg.Goerli
cfg.BlockTime = 0 cfg.BlockTime = 0
slot := 2 * time.Second slot := 2 * time.Second
params, err := GetScoringParams("light", &cfg) params, err := GetScoringParams("light", cfg)
testSuite.NoError(err) testSuite.NoError(err)
testSuite.Equal(params.PeerScoring.DecayInterval, slot) testSuite.Equal(params.PeerScoring.DecayInterval, slot)
testSuite.Equal(params.ApplicationScoring.DecayInterval, slot) testSuite.Equal(params.ApplicationScoring.DecayInterval, slot)
......
package rollup
import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/superchain-registry/superchain"
)
const (
opMainnet = 10
opGoerli = 420
opSepolia = 11155420
baseGoerli = 84531
baseMainnet = 8453
pgnMainnet = 424
pgnSepolia = 58008
zoraGoerli = 999
zoraMainnet = 7777777
)
// LoadOPStackRollupConfig loads the rollup configuration of the requested chain ID from the superchain-registry.
// Some chains may require a SystemConfigProvider to retrieve any values not part of the registry.
func LoadOPStackRollupConfig(chainID uint64) (*Config, error) {
chConfig, ok := superchain.OPChains[chainID]
if !ok {
return nil, fmt.Errorf("unknown chain ID: %d", chainID)
}
superChain, ok := superchain.Superchains[chConfig.Superchain]
if !ok {
return nil, fmt.Errorf("chain %d specifies unknown superchain: %q", chainID, chConfig.Superchain)
}
var genesisSysConfig eth.SystemConfig
if sysCfg, ok := superchain.GenesisSystemConfigs[chainID]; ok {
genesisSysConfig = eth.SystemConfig{
BatcherAddr: common.Address(sysCfg.BatcherAddr),
Overhead: eth.Bytes32(sysCfg.Overhead),
Scalar: eth.Bytes32(sysCfg.Scalar),
GasLimit: sysCfg.GasLimit,
}
} else {
return nil, fmt.Errorf("unable to retrieve genesis SystemConfig of chain %d", chainID)
}
var depositContractAddress common.Address
if addrs, ok := superchain.Addresses[chainID]; ok {
depositContractAddress = common.Address(addrs.OptimismPortalProxy)
} else {
return nil, fmt.Errorf("unable to retrieve deposit contract address")
}
regolithTime := uint64(0)
// two goerli testnets test-ran Bedrock and later upgraded to Regolith.
// All other OP-Stack chains have Regolith enabled from the start.
switch chainID {
case baseGoerli:
regolithTime = 1683219600
case opGoerli:
regolithTime = 1679079600
}
cfg := &Config{
Genesis: Genesis{
L1: eth.BlockID{
Hash: common.Hash(chConfig.Genesis.L1.Hash),
Number: chConfig.Genesis.L1.Number,
},
L2: eth.BlockID{
Hash: common.Hash(chConfig.Genesis.L2.Hash),
Number: chConfig.Genesis.L2.Number,
},
L2Time: chConfig.Genesis.L2Time,
SystemConfig: genesisSysConfig,
},
// The below chain parameters can be different per OP-Stack chain,
// but since none of the superchain chains differ, it's not represented in the superchain-registry yet.
// This restriction on superchain-chains may change in the future.
// Test/Alt configurations can still load custom rollup-configs when necessary.
BlockTime: 2,
MaxSequencerDrift: 600,
SeqWindowSize: 3600,
ChannelTimeout: 300,
L1ChainID: new(big.Int).SetUint64(superChain.Config.L1.ChainID),
L2ChainID: new(big.Int).SetUint64(chConfig.ChainID),
RegolithTime: &regolithTime,
BatchInboxAddress: common.Address(chConfig.BatchInboxAddr),
DepositContractAddress: depositContractAddress,
L1SystemConfigAddress: common.Address(chConfig.SystemConfigAddr),
}
return cfg, nil
}
...@@ -182,12 +182,16 @@ Startup will proceed to use the network-parameter and ignore the rollup config. ...@@ -182,12 +182,16 @@ Startup will proceed to use the network-parameter and ignore the rollup config.
Conflicting configuration is deprecated, and will stop the op-node from starting in the future. Conflicting configuration is deprecated, and will stop the op-node from starting in the future.
`, "network", network, "rollup_config", rollupConfigPath) `, "network", network, "rollup_config", rollupConfigPath)
} }
// check that the network is available
if !chaincfg.IsAvailableNetwork(network, ctx.Bool(flags.BetaExtraNetworks.Name)) {
return nil, fmt.Errorf("unavailable network: %q", network)
}
config, err := chaincfg.GetRollupConfig(network) config, err := chaincfg.GetRollupConfig(network)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &config, nil return config, nil
} }
file, err := os.Open(rollupConfigPath) file, err := os.Open(rollupConfigPath)
......
...@@ -2,123 +2,40 @@ package chainconfig ...@@ -2,123 +2,40 @@ package chainconfig
import ( import (
"fmt" "fmt"
"math/big"
"strconv"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
var enabledFromBedrockBlock = uint64(0) var OPGoerliChainConfig, OPSepoliaChainConfig, OPMainnetChainConfig *params.ChainConfig
var OPGoerliChainConfig = &params.ChainConfig{ func init() {
ChainID: big.NewInt(420), mustLoadConfig := func(chainID uint64) *params.ChainConfig {
HomesteadBlock: big.NewInt(0), cfg, err := params.LoadOPStackChainConfig(chainID)
DAOForkBlock: nil, if err != nil {
DAOForkSupport: false, panic(err)
EIP150Block: big.NewInt(0), }
EIP155Block: big.NewInt(0), return cfg
EIP158Block: big.NewInt(0), }
ByzantiumBlock: big.NewInt(0), OPGoerliChainConfig = mustLoadConfig(420)
ConstantinopleBlock: big.NewInt(0), OPSepoliaChainConfig = mustLoadConfig(11155420)
PetersburgBlock: big.NewInt(0), OPMainnetChainConfig = mustLoadConfig(10)
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(4061224),
ArrowGlacierBlock: big.NewInt(4061224),
GrayGlacierBlock: big.NewInt(4061224),
MergeNetsplitBlock: big.NewInt(4061224),
BedrockBlock: big.NewInt(4061224),
RegolithTime: &params.OptimismGoerliRegolithTime,
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
Optimism: &params.OptimismConfig{
EIP1559Elasticity: 10,
EIP1559Denominator: 50,
},
}
var OPSepoliaChainConfig = &params.ChainConfig{
ChainID: big.NewInt(11155420),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
MergeNetsplitBlock: big.NewInt(0),
BedrockBlock: big.NewInt(0),
RegolithTime: &enabledFromBedrockBlock,
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
Optimism: &params.OptimismConfig{
EIP1559Elasticity: 6,
EIP1559Denominator: 50,
},
}
var OPMainnetChainConfig = &params.ChainConfig{
ChainID: big.NewInt(10),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: false,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(3950000),
LondonBlock: big.NewInt(105235063),
ArrowGlacierBlock: big.NewInt(105235063),
GrayGlacierBlock: big.NewInt(105235063),
MergeNetsplitBlock: big.NewInt(105235063),
BedrockBlock: big.NewInt(105235063),
RegolithTime: &enabledFromBedrockBlock,
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
Optimism: &params.OptimismConfig{
EIP1559Elasticity: 6,
EIP1559Denominator: 50,
},
} }
var L2ChainConfigsByName = map[string]*params.ChainConfig{ var L2ChainConfigsByChainID = map[uint64]*params.ChainConfig{
"goerli": OPGoerliChainConfig, 420: OPGoerliChainConfig,
"sepolia": OPSepoliaChainConfig, 11155420: OPSepoliaChainConfig,
"mainnet": OPMainnetChainConfig, 10: OPMainnetChainConfig,
} }
func RollupConfigByChainID(chainID uint64) (*rollup.Config, error) { func RollupConfigByChainID(chainID uint64) (*rollup.Config, error) {
network := chaincfg.L2ChainIDToNetworkName[strconv.FormatUint(chainID, 10)] config, err := rollup.LoadOPStackRollupConfig(chainID)
if network == "" { if err != nil {
return nil, fmt.Errorf("unknown chain ID: %d", chainID) return nil, fmt.Errorf("failed to get rollup config for chain ID %d: %w", chainID, err)
}
config, ok := chaincfg.NetworksByName[network]
if !ok {
return nil, fmt.Errorf("unknown network %s for chain ID %d", network, chainID)
} }
return &config, nil return config, nil
} }
func ChainConfigByChainID(chainID uint64) (*params.ChainConfig, error) { func ChainConfigByChainID(chainID uint64) (*params.ChainConfig, error) {
network := chaincfg.L2ChainIDToNetworkName[strconv.FormatUint(chainID, 10)] return params.LoadOPStackChainConfig(chainID)
chainConfig, ok := L2ChainConfigsByName[network]
if !ok {
return nil, fmt.Errorf("unknown network %s for chain ID %d", network, chainID)
}
return chainConfig, nil
} }
...@@ -21,7 +21,7 @@ func TestBootstrapClient(t *testing.T) { ...@@ -21,7 +21,7 @@ func TestBootstrapClient(t *testing.T) {
L2ClaimBlockNumber: 1, L2ClaimBlockNumber: 1,
L2ChainID: chaincfg.Goerli.L2ChainID.Uint64(), L2ChainID: chaincfg.Goerli.L2ChainID.Uint64(),
L2ChainConfig: chainconfig.OPGoerliChainConfig, L2ChainConfig: chainconfig.OPGoerliChainConfig,
RollupConfig: &chaincfg.Goerli, RollupConfig: chaincfg.Goerli,
} }
mockOracle := &mockBoostrapOracle{bootInfo, false} mockOracle := &mockBoostrapOracle{bootInfo, false}
readBootInfo := NewBootstrapClient(mockOracle).BootInfo() readBootInfo := NewBootstrapClient(mockOracle).BootInfo()
...@@ -36,7 +36,7 @@ func TestBootstrapClient_CustomChain(t *testing.T) { ...@@ -36,7 +36,7 @@ func TestBootstrapClient_CustomChain(t *testing.T) {
L2ClaimBlockNumber: 1, L2ClaimBlockNumber: 1,
L2ChainID: CustomChainIDIndicator, L2ChainID: CustomChainIDIndicator,
L2ChainConfig: chainconfig.OPGoerliChainConfig, L2ChainConfig: chainconfig.OPGoerliChainConfig,
RollupConfig: &chaincfg.Goerli, RollupConfig: chaincfg.Goerli,
} }
mockOracle := &mockBoostrapOracle{bootInfo, true} mockOracle := &mockBoostrapOracle{bootInfo, true}
readBootInfo := NewBootstrapClient(mockOracle).BootInfo() readBootInfo := NewBootstrapClient(mockOracle).BootInfo()
......
...@@ -161,7 +161,7 @@ func createOracleEngine(t *testing.T) (*OracleEngine, *stubEngineBackend) { ...@@ -161,7 +161,7 @@ func createOracleEngine(t *testing.T) (*OracleEngine, *stubEngineBackend) {
} }
engine := OracleEngine{ engine := OracleEngine{
backend: backend, backend: backend,
rollupCfg: &chaincfg.Goerli, rollupCfg: chaincfg.Goerli,
} }
return &engine, backend return &engine, backend
} }
......
...@@ -45,8 +45,10 @@ func TestLogLevel(t *testing.T) { ...@@ -45,8 +45,10 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs()) cfg := configForArgs(t, addRequiredArgs())
rollupCfg, err := chaincfg.GetRollupConfig("op-goerli")
require.NoError(t, err)
defaultCfg := config.NewConfig( defaultCfg := config.NewConfig(
&chaincfg.Goerli, rollupCfg,
chainconfig.OPGoerliChainConfig, chainconfig.OPGoerliChainConfig,
common.HexToHash(l1HeadValue), common.HexToHash(l1HeadValue),
common.HexToHash(l2HeadValue), common.HexToHash(l2HeadValue),
...@@ -58,7 +60,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { ...@@ -58,7 +60,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
func TestNetwork(t *testing.T) { func TestNetwork(t *testing.T) {
t.Run("Unknown", func(t *testing.T) { t.Run("Unknown", func(t *testing.T) {
verifyArgsInvalid(t, "invalid network bar", replaceRequiredArg("--network", "bar")) verifyArgsInvalid(t, "unavailable network: \"bar\"", replaceRequiredArg("--network", "bar"))
}) })
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
...@@ -74,16 +76,17 @@ func TestNetwork(t *testing.T) { ...@@ -74,16 +76,17 @@ func TestNetwork(t *testing.T) {
genesisFile := writeValidGenesis(t) genesisFile := writeValidGenesis(t)
cfg := configForArgs(t, addRequiredArgsExcept("--network", "--rollup.config", configFile, "--l2.genesis", genesisFile)) cfg := configForArgs(t, addRequiredArgsExcept("--network", "--rollup.config", configFile, "--l2.genesis", genesisFile))
require.Equal(t, chaincfg.Goerli, *cfg.Rollup) require.Equal(t, *chaincfg.Goerli, *cfg.Rollup)
}) })
for name, cfg := range chaincfg.NetworksByName { for _, name := range chaincfg.AvailableNetworks() {
name := name name := name
expected := cfg expected, err := chaincfg.GetRollupConfig(name)
require.NoError(t, err)
t.Run("Network_"+name, func(t *testing.T) { t.Run("Network_"+name, func(t *testing.T) {
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)
}) })
} }
} }
......
...@@ -6,10 +6,11 @@ import ( ...@@ -6,10 +6,11 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/sources" "github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-program/chainconfig"
"github.com/ethereum-optimism/optimism/op-program/host/flags" "github.com/ethereum-optimism/optimism/op-program/host/flags"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
...@@ -157,10 +158,15 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) { ...@@ -157,10 +158,15 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) {
var l2ChainConfig *params.ChainConfig var l2ChainConfig *params.ChainConfig
if l2GenesisPath == "" { if l2GenesisPath == "" {
networkName := ctx.String(flags.Network.Name) networkName := ctx.String(flags.Network.Name)
l2ChainConfig = chainconfig.L2ChainConfigsByName[networkName] ch := chaincfg.ChainByName(networkName)
if l2ChainConfig == nil { if ch == nil {
return nil, fmt.Errorf("flag %s is required for network %s", flags.L2GenesisPath.Name, networkName) return nil, fmt.Errorf("flag %s is required for network %s", flags.L2GenesisPath.Name, networkName)
} }
cfg, err := params.LoadOPStackChainConfig(ch.ChainID)
if err != nil {
return nil, fmt.Errorf("failed to load chain config for chain %d: %w", ch.ChainID, err)
}
l2ChainConfig = cfg
} else { } else {
l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath) l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath)
} }
......
...@@ -11,7 +11,7 @@ import ( ...@@ -11,7 +11,7 @@ import (
) )
var ( var (
validRollupConfig = &chaincfg.Goerli validRollupConfig = chaincfg.Goerli
validL2Genesis = params.GoerliChainConfig validL2Genesis = params.GoerliChainConfig
validL1Head = common.Hash{0xaa} validL1Head = common.Hash{0xaa}
validL2Head = common.Hash{0xbb} validL2Head = common.Hash{0xbb}
......
...@@ -35,7 +35,7 @@ func Main(logger log.Logger, cfg *config.Config) error { ...@@ -35,7 +35,7 @@ func Main(logger log.Logger, cfg *config.Config) error {
return fmt.Errorf("invalid config: %w", err) return fmt.Errorf("invalid config: %w", err)
} }
opservice.ValidateEnvVars(flags.EnvVarPrefix, flags.Flags, logger) opservice.ValidateEnvVars(flags.EnvVarPrefix, flags.Flags, logger)
cfg.Rollup.LogDescription(logger, chaincfg.L2ChainIDToNetworkName) cfg.Rollup.LogDescription(logger, chaincfg.L2ChainIDToNetworkDisplayName)
ctx := context.Background() ctx := context.Background()
if cfg.ServerMode { if cfg.ServerMode {
......
...@@ -25,7 +25,7 @@ func TestServerMode(t *testing.T) { ...@@ -25,7 +25,7 @@ func TestServerMode(t *testing.T) {
l1Head := common.Hash{0x11} l1Head := common.Hash{0x11}
l2OutputRoot := common.Hash{0x33} l2OutputRoot := common.Hash{0x33}
cfg := config.NewConfig(&chaincfg.Goerli, chainconfig.OPGoerliChainConfig, l1Head, common.Hash{0x22}, l2OutputRoot, common.Hash{0x44}, 1000) cfg := config.NewConfig(chaincfg.Goerli, chainconfig.OPGoerliChainConfig, l1Head, common.Hash{0x22}, l2OutputRoot, common.Hash{0x44}, 1000)
cfg.DataDir = dir cfg.DataDir = dir
cfg.ServerMode = true cfg.ServerMode = true
......
...@@ -16,7 +16,7 @@ import ( ...@@ -16,7 +16,7 @@ import (
func TestLocalPreimageSource(t *testing.T) { func TestLocalPreimageSource(t *testing.T) {
cfg := &config.Config{ cfg := &config.Config{
Rollup: &chaincfg.Goerli, Rollup: chaincfg.Goerli,
L1Head: common.HexToHash("0x1111"), L1Head: common.HexToHash("0x1111"),
L2OutputRoot: common.HexToHash("0x2222"), L2OutputRoot: common.HexToHash("0x2222"),
L2Claim: common.HexToHash("0x3333"), L2Claim: common.HexToHash("0x3333"),
......
// Package clock provides an abstraction for time to enable testing of functionality that uses time as an input. // Package clock provides an abstraction for time to enable testing of functionality that uses time as an input.
package clock package clock
import "time" import (
"context"
"time"
)
// Clock represents time in a way that can be provided by varying implementations. // Clock represents time in a way that can be provided by varying implementations.
// Methods are designed to be direct replacements for methods in the time package. // Methods are designed to be direct replacements for methods in the time package,
// with some new additions to make common patterns simple.
type Clock interface { type Clock interface {
// Now provides the current local time. Equivalent to time.Now // Now provides the current local time. Equivalent to time.Now
Now() time.Time Now() time.Time
...@@ -26,6 +30,10 @@ type Clock interface { ...@@ -26,6 +30,10 @@ type Clock interface {
// NewTimer creates a new Timer that will send // NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d. // the current time on its channel after at least duration d.
NewTimer(d time.Duration) Timer NewTimer(d time.Duration) Timer
// SleepCtx sleeps until either ctx is done or the specified duration has elapsed.
// Returns the ctx.Err if it returns because the context is done.
SleepCtx(ctx context.Context, d time.Duration) error
} }
// A Ticker holds a channel that delivers "ticks" of a clock at intervals // A Ticker holds a channel that delivers "ticks" of a clock at intervals
...@@ -104,3 +112,14 @@ func (t *SystemTimer) Ch() <-chan time.Time { ...@@ -104,3 +112,14 @@ func (t *SystemTimer) Ch() <-chan time.Time {
func (s systemClock) AfterFunc(d time.Duration, f func()) Timer { func (s systemClock) AfterFunc(d time.Duration, f func()) Timer {
return &SystemTimer{time.AfterFunc(d, f)} return &SystemTimer{time.AfterFunc(d, f)}
} }
func (s systemClock) SleepCtx(ctx context.Context, d time.Duration) error {
timer := s.NewTimer(d)
defer timer.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-timer.Ch():
return nil
}
}
package clock
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestSystemClock_SleepCtx(t *testing.T) {
t.Run("ReturnWhenContextDone", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
start := time.Now()
err := SystemClock.SleepCtx(ctx, 5*time.Minute)
end := time.Now()
require.ErrorIs(t, err, context.Canceled)
// The call shouldn't block for the 5 minutes, but use a high tolerance as test servers can be slow
// and clocks are inaccurate.
require.Less(t, end.Sub(start), time.Minute)
})
t.Run("ReturnAfterDuration", func(t *testing.T) {
start := time.Now()
err := SystemClock.SleepCtx(context.Background(), 100*time.Millisecond)
end := time.Now()
require.NoError(t, err)
// Require the call to sleep for at least a little. Use a high tolerance since clocks can be quite inaccurate.
require.Greater(t, end.Sub(start), 5*time.Millisecond, "should sleep at least a bit")
})
}
package clock
import (
"context"
"time"
)
func sleepCtx(ctx context.Context, d time.Duration, c Clock) error {
timer := c.NewTimer(d)
defer timer.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-timer.Ch():
return nil
}
}
...@@ -195,6 +195,10 @@ func (s *DeterministicClock) NewTimer(d time.Duration) Timer { ...@@ -195,6 +195,10 @@ func (s *DeterministicClock) NewTimer(d time.Duration) Timer {
return t return t
} }
func (s *DeterministicClock) SleepCtx(ctx context.Context, d time.Duration) error {
return sleepCtx(ctx, d, s)
}
func (s *DeterministicClock) addPending(t action) { func (s *DeterministicClock) addPending(t action) {
s.pending = append(s.pending, t) s.pending = append(s.pending, t)
select { select {
......
...@@ -315,3 +315,38 @@ func TestWaitForPending(t *testing.T) { ...@@ -315,3 +315,38 @@ func TestWaitForPending(t *testing.T) {
require.False(t, clock.WaitForNewPendingTask(ctx), "should have reset new pending task flag") require.False(t, clock.WaitForNewPendingTask(ctx), "should have reset new pending task flag")
}) })
} }
func TestSleepCtx(t *testing.T) {
t.Run("ReturnWhenContextComplete", func(t *testing.T) {
clock := NewDeterministicClock(time.UnixMilli(1000))
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := clock.SleepCtx(ctx, 5*time.Minute)
require.ErrorIs(t, err, context.Canceled)
})
t.Run("ReturnWhenDurationComplete", func(t *testing.T) {
clock := NewDeterministicClock(time.UnixMilli(1000))
var wg sync.WaitGroup
var result atomic.Value
wg.Add(1)
go func() {
err := clock.SleepCtx(context.Background(), 5*time.Minute)
if err != nil {
result.Store(err)
}
wg.Done()
}()
ctx, cancelFunc := context.WithTimeout(context.Background(), 30*time.Second)
defer cancelFunc()
// Wait until the SleepCtx is called and schedules a pending task
clock.WaitForNewPendingTask(ctx)
clock.AdvanceTime(5 * time.Minute)
// Wait for the call to return
wg.Wait()
require.Nil(t, result.Load())
})
}
package enum package enum
import ( import (
"fmt"
"strings" "strings"
) )
// Stringered wraps the string type to implement the fmt.Stringer interface.
type Stringered string
// String returns the string value.
func (s Stringered) String() string {
return string(s)
}
// StringeredList converts a list of strings to a list of Stringered.
func StringeredList(values []string) []Stringered {
var out []Stringered
for _, v := range values {
out = append(out, Stringered(v))
}
return out
}
// EnumString returns a comma-separated string of the enum values. // EnumString returns a comma-separated string of the enum values.
// This is primarily used to generate a cli flag. // This is primarily used to generate a cli flag.
func EnumString[T fmt.Stringer](values []T) string { func EnumString[T ~string](values []T) string {
var out strings.Builder var out strings.Builder
for i, v := range values { for i, v := range values {
out.WriteString(v.String()) out.WriteString(string(v))
if i+1 < len(values) { if i+1 < len(values) {
out.WriteString(", ") out.WriteString(", ")
} }
......
...@@ -8,30 +8,15 @@ import ( ...@@ -8,30 +8,15 @@ import (
// TestEnumString_MultipleInputs tests the EnumString function with multiple inputs. // TestEnumString_MultipleInputs tests the EnumString function with multiple inputs.
func TestEnumString_MultipleInputs(t *testing.T) { func TestEnumString_MultipleInputs(t *testing.T) {
require.Equal(t, "a, b, c", EnumString([]Stringered{"a", "b", "c"})) require.Equal(t, "a, b, c", EnumString([]string{"a", "b", "c"}))
} }
// TestEnumString_SingleString tests the EnumString function with a single input. // TestEnumString_SingleString tests the EnumString function with a single input.
func TestEnumString_SingleString(t *testing.T) { func TestEnumString_SingleString(t *testing.T) {
require.Equal(t, "a", EnumString([]Stringered{"a"})) require.Equal(t, "a", EnumString([]string{"a"}))
} }
// TestEnumString_EmptyString tests the EnumString function with no inputs. // TestEnumString_EmptyString tests the EnumString function with no inputs.
func TestEnumString_EmptyString(t *testing.T) { func TestEnumString_EmptyString(t *testing.T) {
require.Equal(t, "", EnumString([]Stringered{})) require.Equal(t, "", EnumString([]string{}))
}
// TestStringeredList_MultipleInputs tests the StringeredList function with multiple inputs.
func TestStringeredList_MultipleInputs(t *testing.T) {
require.Equal(t, []Stringered{"a", "b", "c"}, StringeredList([]string{"a", "b", "c"}))
}
// TestStringeredList_SingleString tests the StringeredList function with a single input.
func TestStringeredList_SingleString(t *testing.T) {
require.Equal(t, []Stringered{"a"}, StringeredList([]string{"a"}))
}
// TestStringeredList_EmptyString tests the StringeredList function with no inputs.
func TestStringeredList_EmptyString(t *testing.T) {
require.Equal(t, []Stringered(nil), StringeredList([]string{}))
} }
package jsonutil
import (
"encoding/json"
"fmt"
"sort"
)
// LazySortedJsonMap provides sorted encoding order for JSON maps.
// The sorting is lazy: in-memory it's just a map, until it sorts just-in-time when the map is encoded to JSON.
// Warning: the just-in-time sorting requires a full allocation of the map structure and keys slice during encoding.
// Sorting order is not enforced when decoding from JSON.
type LazySortedJsonMap[K comparable, V any] map[K]V
func (m LazySortedJsonMap[K, V]) MarshalJSON() ([]byte, error) {
keys := make([]string, 0, len(m))
values := make(map[string]V)
for k, v := range m {
s := fmt.Sprintf("%q", any(k)) // format as quoted string
keys = append(keys, s)
values[s] = v
}
sort.Strings(keys)
var out []byte
out = append(out, '{')
for i, k := range keys {
out = append(out, k...) // quotes are already included
out = append(out, ':')
v, err := json.Marshal(values[k])
if err != nil {
return nil, fmt.Errorf("failed to encode value of %s: %w", k, err)
}
out = append(out, v...)
if i != len(keys)-1 {
out = append(out, ',')
}
}
out = append(out, '}')
return out, nil
}
func (m *LazySortedJsonMap[K, V]) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, (*map[K]V)(m))
}
package jsonutil
import (
"encoding/json"
"fmt"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
type LazySortedJsonMapTestCase[K comparable, V any] struct {
Object LazySortedJsonMap[K, V]
Json string
}
func (tc *LazySortedJsonMapTestCase[K, V]) Run(t *testing.T) {
t.Run("Marshal", func(t *testing.T) {
got, err := json.Marshal(tc.Object)
require.NoError(t, err)
require.Equal(t, tc.Json, string(got), "json output must match")
})
t.Run("Unmarshal", func(t *testing.T) {
var dest LazySortedJsonMap[K, V]
err := json.Unmarshal([]byte(tc.Json), &dest)
require.NoError(t, err)
require.Equal(t, len(tc.Object), len(dest), "lengths match")
for k, v := range tc.Object {
require.Equal(t, v, dest[k], "values of %q match", k)
}
})
}
func TestLazySortedJsonMap(t *testing.T) {
testCases := []interface{ Run(t *testing.T) }{
&LazySortedJsonMapTestCase[string, int]{Object: LazySortedJsonMap[string, int]{}, Json: `{}`},
&LazySortedJsonMapTestCase[string, int]{Object: LazySortedJsonMap[string, int]{"a": 1, "c": 2, "b": 3}, Json: `{"a":1,"b":3,"c":2}`},
&LazySortedJsonMapTestCase[common.Address, int]{Object: LazySortedJsonMap[common.Address, int]{
common.HexToAddress("0x4100000000000000000000000000000000000000"): 123,
common.HexToAddress("0x4200000000000000000000000000000000000000"): 100,
common.HexToAddress("0x4200000000000000000000000000000000000001"): 100,
},
Json: `{"0x4100000000000000000000000000000000000000":123,` +
`"0x4200000000000000000000000000000000000000":100,` +
`"0x4200000000000000000000000000000000000001":100}`},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("case %d", i), tc.Run)
}
}
...@@ -298,12 +298,13 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957) ...@@ -298,12 +298,13 @@ LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755) LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524) LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689) LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
MIPS_Test:test_add_succeeds() (gas: 121593) MIPS_Test:test_add_succeeds() (gas: 122197)
MIPS_Test:test_addi_succeeds() (gas: 121918) MIPS_Test:test_addiSign_succeeds() (gas: 122188)
MIPS_Test:test_addu_succeeds() (gas: 121601) MIPS_Test:test_addi_succeeds() (gas: 122385)
MIPS_Test:test_addui_succeeds() (gas: 121975) MIPS_Test:test_addu_succeeds() (gas: 122239)
MIPS_Test:test_and_succeeds() (gas: 121650) MIPS_Test:test_addui_succeeds() (gas: 122447)
MIPS_Test:test_andi_succeeds() (gas: 121792) MIPS_Test:test_and_succeeds() (gas: 122258)
MIPS_Test:test_andi_succeeds() (gas: 122191)
MIPS_Test:test_beq_succeeds() (gas: 202355) MIPS_Test:test_beq_succeeds() (gas: 202355)
MIPS_Test:test_bgez_succeeds() (gas: 121484) MIPS_Test:test_bgez_succeeds() (gas: 121484)
MIPS_Test:test_bgtz_succeeds() (gas: 121405) MIPS_Test:test_bgtz_succeeds() (gas: 121405)
...@@ -311,67 +312,67 @@ MIPS_Test:test_blez_succeeds() (gas: 121361) ...@@ -311,67 +312,67 @@ MIPS_Test:test_blez_succeeds() (gas: 121361)
MIPS_Test:test_bltz_succeeds() (gas: 121504) MIPS_Test:test_bltz_succeeds() (gas: 121504)
MIPS_Test:test_bne_succeeds() (gas: 121570) MIPS_Test:test_bne_succeeds() (gas: 121570)
MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85999) MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85999)
MIPS_Test:test_brk_succeeds() (gas: 121531) MIPS_Test:test_brk_succeeds() (gas: 121869)
MIPS_Test:test_clo_succeeds() (gas: 121991) MIPS_Test:test_clo_succeeds() (gas: 121926)
MIPS_Test:test_clone_succeeds() (gas: 121484) MIPS_Test:test_clone_succeeds() (gas: 121822)
MIPS_Test:test_clz_succeeds() (gas: 122462) MIPS_Test:test_clz_succeeds() (gas: 122397)
MIPS_Test:test_div_succeeds() (gas: 121806) MIPS_Test:test_div_succeeds() (gas: 122376)
MIPS_Test:test_divu_succeeds() (gas: 121762) MIPS_Test:test_divu_succeeds() (gas: 122361)
MIPS_Test:test_exit_succeeds() (gas: 121408) MIPS_Test:test_exit_succeeds() (gas: 121746)
MIPS_Test:test_fcntl_succeeds() (gas: 203129) MIPS_Test:test_fcntl_succeeds() (gas: 203827)
MIPS_Test:test_illegal_instruction_fails() (gas: 91175) MIPS_Test:test_illegal_instruction_fails() (gas: 91462)
MIPS_Test:test_invalid_root_fails() (gas: 435678) MIPS_Test:test_invalid_root_fails() (gas: 435636)
MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120492) MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120514)
MIPS_Test:test_jal_succeeds() (gas: 120481) MIPS_Test:test_jal_succeeds() (gas: 120503)
MIPS_Test:test_jalr_succeeds() (gas: 121349) MIPS_Test:test_jalr_succeeds() (gas: 121622)
MIPS_Test:test_jr_succeeds() (gas: 121094) MIPS_Test:test_jr_succeeds() (gas: 121316)
MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85345) MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85367)
MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120236) MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120258)
MIPS_Test:test_jump_succeeds() (gas: 120188) MIPS_Test:test_jump_succeeds() (gas: 120188)
MIPS_Test:test_lb_succeeds() (gas: 127346) MIPS_Test:test_lb_succeeds() (gas: 127429)
MIPS_Test:test_lbu_succeeds() (gas: 127222) MIPS_Test:test_lbu_succeeds() (gas: 127327)
MIPS_Test:test_lh_succeeds() (gas: 127367) MIPS_Test:test_lh_succeeds() (gas: 127450)
MIPS_Test:test_lhu_succeeds() (gas: 127284) MIPS_Test:test_lhu_succeeds() (gas: 127367)
MIPS_Test:test_ll_succeeds() (gas: 127304) MIPS_Test:test_ll_succeeds() (gas: 127589)
MIPS_Test:test_lui_succeeds() (gas: 121488) MIPS_Test:test_lui_succeeds() (gas: 121470)
MIPS_Test:test_lw_succeeds() (gas: 127158) MIPS_Test:test_lw_succeeds() (gas: 127218)
MIPS_Test:test_lwl_succeeds() (gas: 241434) MIPS_Test:test_lwl_succeeds() (gas: 241600)
MIPS_Test:test_lwr_succeeds() (gas: 241722) MIPS_Test:test_lwr_succeeds() (gas: 241888)
MIPS_Test:test_mfhi_succeeds() (gas: 121458) MIPS_Test:test_mfhi_succeeds() (gas: 121831)
MIPS_Test:test_mflo_succeeds() (gas: 121484) MIPS_Test:test_mflo_succeeds() (gas: 121960)
MIPS_Test:test_mmap_succeeds() (gas: 118451) MIPS_Test:test_mmap_succeeds() (gas: 118789)
MIPS_Test:test_movn_succeeds() (gas: 202409) MIPS_Test:test_movn_succeeds() (gas: 203027)
MIPS_Test:test_movz_succeeds() (gas: 202313) MIPS_Test:test_movz_succeeds() (gas: 202895)
MIPS_Test:test_mthi_succeeds() (gas: 121450) MIPS_Test:test_mthi_succeeds() (gas: 121875)
MIPS_Test:test_mtlo_succeeds() (gas: 121478) MIPS_Test:test_mtlo_succeeds() (gas: 121983)
MIPS_Test:test_mul_succeeds() (gas: 121563) MIPS_Test:test_mul_succeeds() (gas: 121475)
MIPS_Test:test_mult_succeeds() (gas: 121667) MIPS_Test:test_mult_succeeds() (gas: 122179)
MIPS_Test:test_multu_succeeds() (gas: 121675) MIPS_Test:test_multu_succeeds() (gas: 122216)
MIPS_Test:test_nor_succeeds() (gas: 121697) MIPS_Test:test_nor_succeeds() (gas: 122308)
MIPS_Test:test_or_succeeds() (gas: 121657) MIPS_Test:test_or_succeeds() (gas: 122265)
MIPS_Test:test_ori_succeeds() (gas: 121865) MIPS_Test:test_ori_succeeds() (gas: 122268)
MIPS_Test:test_preimage_read_succeeds() (gas: 233847) MIPS_Test:test_preimage_read_succeeds() (gas: 234185)
MIPS_Test:test_preimage_write_succeeds() (gas: 126473) MIPS_Test:test_preimage_write_succeeds() (gas: 126811)
MIPS_Test:test_prestate_exited_succeeds() (gas: 112992) MIPS_Test:test_prestate_exited_succeeds() (gas: 112992)
MIPS_Test:test_sb_succeeds() (gas: 159993) MIPS_Test:test_sb_succeeds() (gas: 160300)
MIPS_Test:test_sc_succeeds() (gas: 160187) MIPS_Test:test_sc_succeeds() (gas: 160494)
MIPS_Test:test_sh_succeeds() (gas: 160052) MIPS_Test:test_sh_succeeds() (gas: 160337)
MIPS_Test:test_sll_succeeds() (gas: 121456) MIPS_Test:test_sll_succeeds() (gas: 121436)
MIPS_Test:test_sllv_succeeds() (gas: 121646) MIPS_Test:test_sllv_succeeds() (gas: 121665)
MIPS_Test:test_slt_succeeds() (gas: 203266) MIPS_Test:test_slt_succeeds() (gas: 204222)
MIPS_Test:test_sltu_succeeds() (gas: 121871) MIPS_Test:test_sltu_succeeds() (gas: 122482)
MIPS_Test:test_sra_succeeds() (gas: 121763) MIPS_Test:test_sra_succeeds() (gas: 121687)
MIPS_Test:test_srav_succeeds() (gas: 121959) MIPS_Test:test_srav_succeeds() (gas: 121955)
MIPS_Test:test_srl_succeeds() (gas: 121514) MIPS_Test:test_srl_succeeds() (gas: 121518)
MIPS_Test:test_srlv_succeeds() (gas: 121707) MIPS_Test:test_srlv_succeeds() (gas: 121683)
MIPS_Test:test_step_abi_succeeds() (gas: 57876) MIPS_Test:test_step_abi_succeeds() (gas: 58312)
MIPS_Test:test_sub_succeeds() (gas: 121696) MIPS_Test:test_sub_succeeds() (gas: 122292)
MIPS_Test:test_subu_succeeds() (gas: 121659) MIPS_Test:test_subu_succeeds() (gas: 122289)
MIPS_Test:test_sw_succeeds() (gas: 160027) MIPS_Test:test_sw_succeeds() (gas: 160312)
MIPS_Test:test_swl_succeeds() (gas: 160088) MIPS_Test:test_swl_succeeds() (gas: 160373)
MIPS_Test:test_swr_succeeds() (gas: 160163) MIPS_Test:test_swr_succeeds() (gas: 160448)
MIPS_Test:test_xor_succeeds() (gas: 121685) MIPS_Test:test_xor_succeeds() (gas: 122293)
MIPS_Test:test_xori_succeeds() (gas: 121916) MIPS_Test:test_xori_succeeds() (gas: 122345)
MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733) MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733)
MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889) MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889)
MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845) MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845)
......
...@@ -102,6 +102,26 @@ contract MIPS_Test is CommonTest { ...@@ -102,6 +102,26 @@ contract MIPS_Test is CommonTest {
assertEq(postState, outputState(expect), "unexpected post state"); assertEq(postState, outputState(expect), "unexpected post state");
} }
function test_addiSign_succeeds() external {
uint16 imm = 0xfffe; // -2
uint32 insn = encodeitype(0x8, 17, 8, imm); // addi t0, s1, 40
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[8] = 1; // t0
state.registers[17] = 2; // s1
bytes memory encodedState = encodeState(state);
MIPS.State memory expect;
expect.memRoot = state.memRoot;
expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1;
expect.registers[8] = 0;
expect.registers[17] = state.registers[17];
bytes32 postState = mips.step(encodedState, proof);
assertEq(postState, outputState(expect), "unexpected post state");
}
function test_addui_succeeds() external { function test_addui_succeeds() external {
uint16 imm = 40; uint16 imm = 40;
uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40 uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40
...@@ -305,15 +325,15 @@ contract MIPS_Test is CommonTest { ...@@ -305,15 +325,15 @@ contract MIPS_Test is CommonTest {
function test_slt_succeeds() external { function test_slt_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2 uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0); (MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200; state.registers[17] = 0xFF_FF_FF_FE; // -2
state.registers[18] = 490; state.registers[18] = 5;
MIPS.State memory expect; MIPS.State memory expect;
expect.memRoot = state.memRoot; expect.memRoot = state.memRoot;
expect.pc = state.nextPC; expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4; expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1; expect.step = state.step + 1;
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0 expect.registers[8] = 1; // t0
expect.registers[17] = state.registers[17]; expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18]; expect.registers[18] = state.registers[18];
...@@ -326,7 +346,7 @@ contract MIPS_Test is CommonTest { ...@@ -326,7 +346,7 @@ contract MIPS_Test is CommonTest {
state.registers[18] = tmp; state.registers[18] = tmp;
expect.registers[17] = state.registers[17]; expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18]; expect.registers[18] = state.registers[18];
expect.registers[8] = state.registers[17] < state.registers[18] ? 1 : 0; // t0 expect.registers[8] = 0; // t0
postState = mips.step(encodeState(state), proof); postState = mips.step(encodeState(state), proof);
assertEq(postState, outputState(expect), "unexpected post state"); assertEq(postState, outputState(expect), "unexpected post state");
} }
...@@ -1127,14 +1147,14 @@ contract MIPS_Test is CommonTest { ...@@ -1127,14 +1147,14 @@ contract MIPS_Test is CommonTest {
uint8 shiftamt = 4; uint8 shiftamt = 4;
uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3 uint32 insn = encodespec(0x0, 0x9, 0x8, uint16(shiftamt) << 6 | 3); // sra t0, t1, 3
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0); (MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[9] = 0x20; // t1 state.registers[9] = 0x80_00_00_20; // t1
MIPS.State memory expect; MIPS.State memory expect;
expect.memRoot = state.memRoot; expect.memRoot = state.memRoot;
expect.pc = state.nextPC; expect.pc = state.nextPC;
expect.nextPC = state.nextPC + 4; expect.nextPC = state.nextPC + 4;
expect.step = state.step + 1; expect.step = state.step + 1;
expect.registers[8] = state.registers[9] >> shiftamt; expect.registers[8] = 0xF8_00_00_02; // 4 shifts while preserving sign bit
expect.registers[9] = state.registers[9]; expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state); bytes memory enc = encodeState(state);
......
This diff is collapsed.
...@@ -17,14 +17,14 @@ import ( ...@@ -17,14 +17,14 @@ import (
"sync" "sync"
"time" "time"
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/semaphore" "golang.org/x/sync/semaphore"
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
) )
const ( const (
...@@ -138,6 +138,7 @@ type Backend struct { ...@@ -138,6 +138,7 @@ type Backend struct {
proxydIP string proxydIP string
skipPeerCountCheck bool skipPeerCountCheck bool
forcedCandidate bool
maxDegradedLatencyThreshold time.Duration maxDegradedLatencyThreshold time.Duration
maxLatencyThreshold time.Duration maxLatencyThreshold time.Duration
...@@ -220,6 +221,12 @@ func WithConsensusSkipPeerCountCheck(skipPeerCountCheck bool) BackendOpt { ...@@ -220,6 +221,12 @@ func WithConsensusSkipPeerCountCheck(skipPeerCountCheck bool) BackendOpt {
} }
} }
func WithConsensusForcedCandidate(forcedCandidate bool) BackendOpt {
return func(b *Backend) {
b.forcedCandidate = forcedCandidate
}
}
func WithMaxDegradedLatencyThreshold(maxDegradedLatencyThreshold time.Duration) BackendOpt { func WithMaxDegradedLatencyThreshold(maxDegradedLatencyThreshold time.Duration) BackendOpt {
return func(b *Backend) { return func(b *Backend) {
b.maxDegradedLatencyThreshold = maxDegradedLatencyThreshold b.maxDegradedLatencyThreshold = maxDegradedLatencyThreshold
...@@ -675,9 +682,10 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch ...@@ -675,9 +682,10 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch
// We also rewrite block tags to enforce compliance with consensus // We also rewrite block tags to enforce compliance with consensus
rctx := RewriteContext{ rctx := RewriteContext{
latest: bg.Consensus.GetLatestBlockNumber(), latest: bg.Consensus.GetLatestBlockNumber(),
safe: bg.Consensus.GetSafeBlockNumber(), safe: bg.Consensus.GetSafeBlockNumber(),
finalized: bg.Consensus.GetFinalizedBlockNumber(), finalized: bg.Consensus.GetFinalizedBlockNumber(),
maxBlockRange: bg.Consensus.maxBlockRange,
} }
for i, req := range rpcReqs { for i, req := range rpcReqs {
...@@ -692,6 +700,10 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch ...@@ -692,6 +700,10 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch
}) })
if errors.Is(err, ErrRewriteBlockOutOfRange) { if errors.Is(err, ErrRewriteBlockOutOfRange) {
res.Error = ErrBlockOutOfRange res.Error = ErrBlockOutOfRange
} else if errors.Is(err, ErrRewriteRangeTooLarge) {
res.Error = ErrInvalidParams(
fmt.Sprintf("block range greater than %d max", rctx.maxBlockRange),
)
} else { } else {
res.Error = ErrParseErr res.Error = ErrParseErr
} }
......
...@@ -93,6 +93,7 @@ type BackendConfig struct { ...@@ -93,6 +93,7 @@ type BackendConfig struct {
StripTrailingXFF bool `toml:"strip_trailing_xff"` StripTrailingXFF bool `toml:"strip_trailing_xff"`
ConsensusSkipPeerCountCheck bool `toml:"consensus_skip_peer_count"` ConsensusSkipPeerCountCheck bool `toml:"consensus_skip_peer_count"`
ConsensusForcedCandidate bool `toml:"consensus_forced_candidate"`
ConsensusReceiptsTarget string `toml:"consensus_receipts_target"` ConsensusReceiptsTarget string `toml:"consensus_receipts_target"`
} }
...@@ -107,6 +108,7 @@ type BackendGroupConfig struct { ...@@ -107,6 +108,7 @@ type BackendGroupConfig struct {
ConsensusBanPeriod TOMLDuration `toml:"consensus_ban_period"` ConsensusBanPeriod TOMLDuration `toml:"consensus_ban_period"`
ConsensusMaxUpdateThreshold TOMLDuration `toml:"consensus_max_update_threshold"` ConsensusMaxUpdateThreshold TOMLDuration `toml:"consensus_max_update_threshold"`
ConsensusMaxBlockLag uint64 `toml:"consensus_max_block_lag"` ConsensusMaxBlockLag uint64 `toml:"consensus_max_block_lag"`
ConsensusMaxBlockRange uint64 `toml:"consensus_max_block_range"`
ConsensusMinPeerCount int `toml:"consensus_min_peer_count"` ConsensusMinPeerCount int `toml:"consensus_min_peer_count"`
} }
......
...@@ -38,6 +38,7 @@ type ConsensusPoller struct { ...@@ -38,6 +38,7 @@ type ConsensusPoller struct {
banPeriod time.Duration banPeriod time.Duration
maxUpdateThreshold time.Duration maxUpdateThreshold time.Duration
maxBlockLag uint64 maxBlockLag uint64
maxBlockRange uint64
} }
type backendState struct { type backendState struct {
...@@ -201,6 +202,12 @@ func WithMaxBlockLag(maxBlockLag uint64) ConsensusOpt { ...@@ -201,6 +202,12 @@ func WithMaxBlockLag(maxBlockLag uint64) ConsensusOpt {
} }
} }
func WithMaxBlockRange(maxBlockRange uint64) ConsensusOpt {
return func(cp *ConsensusPoller) {
cp.maxBlockRange = maxBlockRange
}
}
func WithMinPeerCount(minPeerCount uint64) ConsensusOpt { func WithMinPeerCount(minPeerCount uint64) ConsensusOpt {
return func(cp *ConsensusPoller) { return func(cp *ConsensusPoller) {
cp.minPeerCount = minPeerCount cp.minPeerCount = minPeerCount
...@@ -621,6 +628,10 @@ func (cp *ConsensusPoller) getConsensusCandidates() map[*Backend]*backendState { ...@@ -621,6 +628,10 @@ func (cp *ConsensusPoller) getConsensusCandidates() map[*Backend]*backendState {
for _, be := range cp.backendGroup.Backends { for _, be := range cp.backendGroup.Backends {
bs := cp.getBackendState(be) bs := cp.getBackendState(be)
if be.forcedCandidate {
candidates[be] = bs
continue
}
if bs.IsBanned() { if bs.IsBanned() {
continue continue
} }
......
...@@ -9,7 +9,6 @@ require ( ...@@ -9,7 +9,6 @@ require (
github.com/ethereum/go-ethereum v1.12.0 github.com/ethereum/go-ethereum v1.12.0
github.com/go-redis/redis/v8 v8.11.4 github.com/go-redis/redis/v8 v8.11.4
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/uuid v1.3.0
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0 github.com/gorilla/websocket v1.5.0
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
...@@ -17,6 +16,7 @@ require ( ...@@ -17,6 +16,7 @@ require (
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/rs/cors v1.8.2 github.com/rs/cors v1.8.2
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
...@@ -37,6 +37,8 @@ require ( ...@@ -37,6 +37,8 @@ require (
github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
...@@ -44,8 +46,11 @@ require ( ...@@ -44,8 +46,11 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/gomodule/redigo v1.8.8 // indirect github.com/gomodule/redigo v1.8.8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/huin/goupnp v1.0.3 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/compress v1.15.15 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
...@@ -59,9 +64,10 @@ require ( ...@@ -59,9 +64,10 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/status-im/keycard-go v0.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect github.com/tklauser/numcpus v0.4.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect github.com/yuin/gopher-lua v0.0.0-20210529063254-f4c35e4016d9 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.1.0 // indirect golang.org/x/crypto v0.1.0 // indirect
......
This diff is collapsed.
...@@ -142,6 +142,7 @@ func Start(config *Config) (*Server, func(), error) { ...@@ -142,6 +142,7 @@ func Start(config *Config) (*Server, func(), error) {
} }
opts = append(opts, WithProxydIP(os.Getenv("PROXYD_IP"))) opts = append(opts, WithProxydIP(os.Getenv("PROXYD_IP")))
opts = append(opts, WithConsensusSkipPeerCountCheck(cfg.ConsensusSkipPeerCountCheck)) opts = append(opts, WithConsensusSkipPeerCountCheck(cfg.ConsensusSkipPeerCountCheck))
opts = append(opts, WithConsensusForcedCandidate(cfg.ConsensusForcedCandidate))
receiptsTarget, err := ReadFromEnvOrConfig(cfg.ConsensusReceiptsTarget) receiptsTarget, err := ReadFromEnvOrConfig(cfg.ConsensusReceiptsTarget)
if err != nil { if err != nil {
...@@ -308,6 +309,9 @@ func Start(config *Config) (*Server, func(), error) { ...@@ -308,6 +309,9 @@ func Start(config *Config) (*Server, func(), error) {
if bgcfg.ConsensusMinPeerCount > 0 { if bgcfg.ConsensusMinPeerCount > 0 {
copts = append(copts, WithMinPeerCount(uint64(bgcfg.ConsensusMinPeerCount))) copts = append(copts, WithMinPeerCount(uint64(bgcfg.ConsensusMinPeerCount)))
} }
if bgcfg.ConsensusMaxBlockRange > 0 {
copts = append(copts, WithMaxBlockRange(bgcfg.ConsensusMaxBlockRange))
}
cp := NewConsensusPoller(bg, copts...) cp := NewConsensusPoller(bg, copts...)
bg.Consensus = cp bg.Consensus = cp
......
...@@ -9,9 +9,10 @@ import ( ...@@ -9,9 +9,10 @@ import (
) )
type RewriteContext struct { type RewriteContext struct {
latest hexutil.Uint64 latest hexutil.Uint64
safe hexutil.Uint64 safe hexutil.Uint64
finalized hexutil.Uint64 finalized hexutil.Uint64
maxBlockRange uint64
} }
type RewriteResult uint8 type RewriteResult uint8
...@@ -32,6 +33,7 @@ const ( ...@@ -32,6 +33,7 @@ const (
var ( var (
ErrRewriteBlockOutOfRange = errors.New("block is out of range") ErrRewriteBlockOutOfRange = errors.New("block is out of range")
ErrRewriteRangeTooLarge = errors.New("block range is too large")
) )
// RewriteTags modifies the request and the response based on block tags // RewriteTags modifies the request and the response based on block tags
...@@ -121,6 +123,15 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri ...@@ -121,6 +123,15 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
return RewriteOverrideError, err return RewriteOverrideError, err
} }
// if either fromBlock or toBlock is defined, default the other to "latest" if unset
_, hasFrom := p[pos]["fromBlock"]
_, hasTo := p[pos]["toBlock"]
if hasFrom && !hasTo {
p[pos]["toBlock"] = "latest"
} else if hasTo && !hasFrom {
p[pos]["fromBlock"] = "latest"
}
modifiedFrom, err := rewriteTagMap(rctx, p[pos], "fromBlock") modifiedFrom, err := rewriteTagMap(rctx, p[pos], "fromBlock")
if err != nil { if err != nil {
return RewriteOverrideError, err return RewriteOverrideError, err
...@@ -131,6 +142,20 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri ...@@ -131,6 +142,20 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
return RewriteOverrideError, err return RewriteOverrideError, err
} }
if rctx.maxBlockRange > 0 && (hasFrom || hasTo) {
from, err := blockNumber(p[pos], "fromBlock", uint64(rctx.latest))
if err != nil {
return RewriteOverrideError, err
}
to, err := blockNumber(p[pos], "toBlock", uint64(rctx.latest))
if err != nil {
return RewriteOverrideError, err
}
if to-from > rctx.maxBlockRange {
return RewriteOverrideError, ErrRewriteRangeTooLarge
}
}
// if any of the fields the request have been changed, re-marshal the params // if any of the fields the request have been changed, re-marshal the params
if modifiedFrom || modifiedTo { if modifiedFrom || modifiedTo {
paramsRaw, err := json.Marshal(p) paramsRaw, err := json.Marshal(p)
...@@ -144,6 +169,21 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri ...@@ -144,6 +169,21 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
return RewriteNone, nil return RewriteNone, nil
} }
func blockNumber(m map[string]interface{}, key string, latest uint64) (uint64, error) {
current, ok := m[key].(string)
if !ok {
return 0, errors.New("expected string")
}
// the latest/safe/finalized tags are already replaced by rewriteTag
if current == "earliest" {
return 0, nil
}
if current == "pending" {
return latest + 1, nil
}
return hexutil.DecodeUint64(current)
}
func rewriteTagMap(rctx RewriteContext, m map[string]interface{}, key string) (bool, error) { func rewriteTagMap(rctx RewriteContext, m map[string]interface{}, key string) (bool, error) {
if m[key] == nil || m[key] == "" { if m[key] == nil || m[key] == "" {
return false, nil return false, nil
......
...@@ -48,7 +48,7 @@ func TestRewriteRequest(t *testing.T) { ...@@ -48,7 +48,7 @@ func TestRewriteRequest(t *testing.T) {
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": hexutil.Uint64(55).String()}})}, req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": hexutil.Uint64(55).String()}})},
res: nil, res: nil,
}, },
expected: RewriteNone, expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) { check: func(t *testing.T, args args) {
var p []map[string]interface{} var p []map[string]interface{}
err := json.Unmarshal(args.req.Params, &p) err := json.Unmarshal(args.req.Params, &p)
...@@ -88,7 +88,7 @@ func TestRewriteRequest(t *testing.T) { ...@@ -88,7 +88,7 @@ func TestRewriteRequest(t *testing.T) {
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"toBlock": hexutil.Uint64(55).String()}})}, req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"toBlock": hexutil.Uint64(55).String()}})},
res: nil, res: nil,
}, },
expected: RewriteNone, expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) { check: func(t *testing.T, args args) {
var p []map[string]interface{} var p []map[string]interface{}
err := json.Unmarshal(args.req.Params, &p) err := json.Unmarshal(args.req.Params, &p)
...@@ -148,6 +148,62 @@ func TestRewriteRequest(t *testing.T) { ...@@ -148,6 +148,62 @@ func TestRewriteRequest(t *testing.T) {
expected: RewriteOverrideError, expected: RewriteOverrideError,
expectedErr: ErrRewriteBlockOutOfRange, expectedErr: ErrRewriteBlockOutOfRange,
}, },
{
name: "eth_getLogs fromBlock -> toBlock above max range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100), maxBlockRange: 30},
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": hexutil.Uint64(20).String(), "toBlock": hexutil.Uint64(80).String()}})},
res: nil,
},
expected: RewriteOverrideError,
expectedErr: ErrRewriteRangeTooLarge,
},
{
name: "eth_getLogs earliest -> latest above max range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100), maxBlockRange: 30},
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": "earliest", "toBlock": "latest"}})},
res: nil,
},
expected: RewriteOverrideError,
expectedErr: ErrRewriteRangeTooLarge,
},
{
name: "eth_getLogs earliest -> pending above max range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100), maxBlockRange: 30},
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": "earliest", "toBlock": "pending"}})},
res: nil,
},
expected: RewriteOverrideError,
expectedErr: ErrRewriteRangeTooLarge,
},
{
name: "eth_getLogs earliest -> default above max range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100), maxBlockRange: 30},
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": "earliest"}})},
res: nil,
},
expected: RewriteOverrideError,
expectedErr: ErrRewriteRangeTooLarge,
},
{
name: "eth_getLogs default -> latest within range",
args: args{
rctx: RewriteContext{latest: hexutil.Uint64(100), maxBlockRange: 30},
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"toBlock": "latest"}})},
res: nil,
},
expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) {
var p []map[string]interface{}
err := json.Unmarshal(args.req.Params, &p)
require.Nil(t, err)
require.Equal(t, hexutil.Uint64(100).String(), p[0]["fromBlock"])
require.Equal(t, hexutil.Uint64(100).String(), p[0]["toBlock"])
},
},
/* required parameter at pos 0 */ /* required parameter at pos 0 */
{ {
name: "debug_getRawReceipts latest", name: "debug_getRawReceipts latest",
......
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