Commit 0394f490 authored by Ethen Pociask's avatar Ethen Pociask

Merge branch 'develop' of https://github.com/epociask/optimism into indexer.l1height-param

parents dd4f5615 53d8a094
......@@ -778,6 +778,9 @@ jobs:
use_http:
description: If the op-e2e package should use HTTP clients
type: string
use_external:
description: The extra-process shim (if any) that should be used
type: string
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
resource_class: xlarge
......@@ -788,6 +791,13 @@ jobs:
- run:
name: prep results dir
command: mkdir -p /tmp/test-results
- when:
condition: <<parameters.use_external>>
steps:
- run:
name: Build Shim
command: make -C <<parameters.use_external>>
working_directory: <<parameters.module>>
- run:
name: install geth
command: make install-geth
......@@ -807,9 +817,11 @@ jobs:
# Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional
# constraint that gotestsum does not currently (nor likely will) accept files from different pacakges when building.
# Note: -parallel must be set to match the number of cores in the resource class
export TEST_SUFFIX="<<parameters.use_external>>"
export EXTERNAL_L2="$(test -z '<<parameters.use_external>>' || echo '<<parameters.use_external>>/shim')"
OP_TESTLOG_DISABLE_COLOR=true OP_E2E_DISABLE_PARALLEL=false OP_E2E_USE_HTTP=<<parameters.use_http>> gotestsum \
--format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>.xml \
-- -timeout=20m -parallel=8 ./...
--format=standard-verbose --junitfile=/tmp/test-results/<<parameters.module>>_http_<<parameters.use_http>>$TEST_SUFFIX.xml \
-- -timeout=20m -parallel=8 --externalL2 "$EXTERNAL_L2" ./...
working_directory: <<parameters.module>>
- store_test_results:
path: /tmp/test-results
......@@ -868,7 +880,7 @@ jobs:
patterns: indexer
- run:
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
- run:
name: install geth
......@@ -1041,59 +1053,6 @@ jobs:
name: "Go mod tidy"
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:
docker:
- image: cimg/go:1.20
......@@ -1274,10 +1233,17 @@ workflows:
name: op-e2e-WS-tests
module: op-e2e
use_http: "false"
use_external: ""
- go-e2e-test:
name: op-e2e-HTTP-tests
module: op-e2e
use_http: "true"
use_external: ""
- go-e2e-test:
name: op-e2e-WS-tests-external-geth
module: op-e2e
use_http: "false"
use_external: "external_geth"
- bedrock-go-tests:
requires:
- op-batcher-lint
......@@ -1404,33 +1370,6 @@ workflows:
docker_target: wd-mon
context:
- 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-service
- cannon-go-lint-and-test
......
......@@ -395,12 +395,10 @@ func (m *InstrumentedState) mipsStep() error {
func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
opcode := insn >> 26 // 6-bits
fun := insn & 0x3f // 6-bits
if opcode < 0x20 {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if opcode >= 8 && opcode < 0xF {
if opcode == 0 || (opcode >= 8 && opcode < 0xF) {
fun := insn & 0x3f // 6-bits
// transform ArithLogI to SPECIAL
switch opcode {
case 8:
fun = 0x20 // addi
......@@ -417,65 +415,90 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
case 0xE:
fun = 0x26 // xori
}
opcode = 0
}
// 0 is opcode SPECIAL
if opcode == 0 {
shamt := (insn >> 6) & 0x1F
if fun < 0x20 {
switch {
case fun >= 0x08:
return rs // jr/jalr/div + others
case fun == 0x00:
return rt << shamt // sll
case fun == 0x02:
return rt >> shamt // srl
case fun == 0x03:
return SE(rt>>shamt, 32-shamt) // sra
case fun == 0x04:
return rt << (rs & 0x1F) // sllv
case fun == 0x06:
return rt >> (rs & 0x1F) // srlv
case fun == 0x07:
return SE(rt>>rs, 32-rs) // srav
}
}
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// R-type (ArithLog)
switch fun {
case 0x20, 0x21:
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:
case 0x00: // sll
return rt << ((insn >> 6) & 0x1F)
case 0x02: // srl
return rt >> ((insn >> 6) & 0x1F)
case 0x03: // sra
shamt := (insn >> 6) & 0x1F
return SE(rt>>shamt, 32-shamt)
case 0x04: // sllv
return rt << (rs & 0x1F)
case 0x06: // srlv
return rt >> (rs & 0x1F)
case 0x07: // srav
return SE(rt>>rs, 32-rs)
// functs in range [0x8, 0x1b] are handled specially by other functions
case 0x08: // jr
return rs
case 0x09: // jalr
return rs
case 0x0a: // movz
return rs
case 0x0b: // movn
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 // slt
} else {
return 0
return 1
}
case 0x2B:
if rs < rt {
return 1 // sltu
} else {
return 0
case 0x2b: // sltiu
if rs < rt {
return 1
}
return 0
default:
panic("invalid instruction")
}
} else if opcode == 0xF {
return rt << 16 // lui
} else if opcode == 0x1C { // SPECIAL2
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))
}
if fun == 0x20 || fun == 0x21 { // clo
case 0x20, 0x21: // clo
if fun == 0x20 {
rs = ^rs
}
......@@ -485,9 +508,8 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
}
return i
}
}
} else if opcode < 0x28 {
switch opcode {
case 0x0F: // lui
return rt << 16
case 0x20: // lb
return SE((mem>>(24-(rs&3)*8))&0xFF, 8)
case 0x21: // lh
......@@ -506,31 +528,32 @@ func execute(insn uint32, rs uint32, rt uint32, mem uint32) uint32 {
val := mem >> (24 - (rs&3)*8)
mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)
return (rt & ^mask) | val
}
} else if opcode == 0x28 { // sb
case 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
case 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
case 0x2a: // swl
val := rt >> ((rs & 3) * 8)
mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8)
return (mem & ^mask) | val
} else if opcode == 0x2b { // sw
case 0x2b: // sw
return rt
} else if opcode == 0x2e { // swr
case 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
case 0x30: // ll
return mem
case 0x38: // sc
return rt
default:
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 (
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0
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/fsnotify/fsnotify v1.6.0
github.com/go-chi/chi/v5 v5.0.10
......@@ -15,9 +16,8 @@ require (
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/go-cmp v0.5.9
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/golang-lru v1.0.2
github.com/hashicorp/golang-lru/v2 v2.0.2
github.com/holiman/uint256 v1.2.3
github.com/ipfs/go-datastore v0.6.0
......@@ -32,6 +32,7 @@ require (
github.com/multiformats/go-multiaddr v0.10.1
github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/gomega v1.27.10
github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.7.0
github.com/prometheus/client_golang v1.14.0
......@@ -43,7 +44,7 @@ require (
golang.org/x/term v0.11.0
golang.org/x/time v0.3.0
gorm.io/driver/postgres v1.5.2
gorm.io/gorm v1.25.3
gorm.io/gorm v1.25.4
)
require (
......@@ -66,23 +67,29 @@ require (
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 // indirect
github.com/crate-crypto/go-kzg-4844 v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/docker/docker v20.10.24+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/ethereum/c-kzg-4844 v0.2.0 // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
github.com/fjl/memsize v0.0.1 // indirect
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
......@@ -110,8 +117,10 @@ require (
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/karalabe/usb v0.0.2 // indirect
github.com/klauspost/compress v1.16.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
......@@ -147,7 +156,9 @@ require (
github.com/multiformats/go-multihash v0.2.1 // indirect
github.com/multiformats/go-multistream v0.4.1 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
......@@ -183,10 +194,10 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.24.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/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
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
......@@ -197,6 +208,6 @@ require (
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
......@@ -107,6 +107,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7 h1:6IrxszG5G+O7zhtkWxq6+unVvnrm1fqV2Pe+T95DUzw=
github.com/crate-crypto/go-ipa v0.0.0-20220523130400-f11357ae11c7/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI=
github.com/crate-crypto/go-kzg-4844 v0.2.0 h1:UVuHOE+5tIWrim4zf/Xaa43+MIsDCPyW76QhUpiMGj4=
github.com/crate-crypto/go-kzg-4844 v0.2.0/go.mod h1:SBP7ikXEgDnUPONgm33HtuDZEDtWa3L4QtN1ocJSEQ4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
......@@ -134,13 +136,19 @@ github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE=
github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7 h1:kgvzE5wLsLa7XKfV85VZl40QXaMCaeFtHpPwJ8fhotY=
github.com/dop251/goja v0.0.0-20230122112309-96b1610dd4f7/go.mod h1:yRkwfj0CBpOGre+TwBsqPV0IH0Pk73e4PXJOeNDboGs=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
......@@ -154,11 +162,15 @@ 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/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/op-geth v1.101106.1-0.20230724181546-b9c6d36ae9b8 h1:Kr4nvrI5WHLtjLiuuVGXMBfPX2Yeo3HdUWW8iXRH6oA=
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 h1:YF2FE/QnbhvrHwDYJHnbTKgJvw2aKwB/dd7PO1zKNqY=
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/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
......@@ -177,6 +189,8 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732 h1:AB7YjNrzlVHsYz06zCULVV2zYCEft82P86dSmtwxKL0=
github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I=
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
......@@ -202,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-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-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-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
......@@ -216,6 +230,7 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
......@@ -303,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/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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
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 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
......@@ -324,8 +339,6 @@ github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.2 h1:Dwmkdr5Nc/oBiXgJS3CDHNhJtIHkuZ3DZF5twqnfBdU=
github.com/hashicorp/golang-lru/v2 v2.0.2/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
......@@ -422,6 +435,8 @@ github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABo
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e h1:UvSe12bq+Uj2hWd8aOlwPmoZ+CITRFrdit+sDGfAg8U=
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
......@@ -437,6 +452,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4=
github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
......@@ -478,6 +495,7 @@ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4F
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
......@@ -607,6 +625,10 @@ github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqd
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
......@@ -627,15 +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/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.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
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.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.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.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.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
......@@ -851,6 +874,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
......@@ -912,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-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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
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-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
......@@ -972,6 +996,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
......@@ -1033,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.3/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.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
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-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
......@@ -1113,8 +1138,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0=
gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8=
gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8=
gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw=
gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
......
......@@ -105,7 +105,7 @@ func NewCli(GitVersion string, GitCommit string, GitDate string) *Cli {
Action: runApi,
},
{
Name: "indexer",
Name: "index",
Flags: flags,
Description: "Runs the indexing service",
Action: runIndexer,
......
......@@ -18,8 +18,8 @@ import (
*/
type BlockHeader struct {
Hash common.Hash `gorm:"primaryKey;serializer:json"`
ParentHash common.Hash `gorm:"serializer:json"`
Hash common.Hash `gorm:"primaryKey;serializer:bytes"`
ParentHash common.Hash `gorm:"serializer:bytes"`
Number U256
Timestamp uint64
......@@ -50,14 +50,14 @@ type LegacyStateBatch struct {
// violating the primary key constraint.
Index uint64 `gorm:"primaryKey;default:0"`
Root common.Hash `gorm:"serializer:json"`
Root common.Hash `gorm:"serializer:bytes"`
Size uint64
PrevTotal uint64
L1ContractEventGUID uuid.UUID
}
type OutputProposal struct {
OutputRoot common.Hash `gorm:"primaryKey;serializer:json"`
OutputRoot common.Hash `gorm:"primaryKey;serializer:bytes"`
L2OutputIndex U256
L2BlockNumber U256
......
......@@ -16,7 +16,7 @@ import (
*/
type BridgeMessage struct {
MessageHash common.Hash `gorm:"primaryKey;serializer:json"`
MessageHash common.Hash `gorm:"primaryKey;serializer:bytes"`
Nonce U256
SentMessageEventGUID uuid.UUID
......@@ -28,12 +28,12 @@ type BridgeMessage struct {
type L1BridgeMessage struct {
BridgeMessage `gorm:"embedded"`
TransactionSourceHash common.Hash `gorm:"serializer:json"`
TransactionSourceHash common.Hash `gorm:"serializer:bytes"`
}
type L2BridgeMessage struct {
BridgeMessage `gorm:"embedded"`
TransactionWithdrawalHash common.Hash `gorm:"serializer:json"`
TransactionWithdrawalHash common.Hash `gorm:"serializer:bytes"`
}
type BridgeMessagesView interface {
......
......@@ -8,7 +8,6 @@ import (
"gorm.io/gorm"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
/**
......@@ -16,16 +15,16 @@ import (
*/
type Transaction struct {
FromAddress common.Address `gorm:"serializer:json"`
ToAddress common.Address `gorm:"serializer:json"`
FromAddress common.Address `gorm:"serializer:bytes"`
ToAddress common.Address `gorm:"serializer:bytes"`
Amount U256
Data hexutil.Bytes `gorm:"serializer:json"`
Data Bytes `gorm:"serializer:bytes"`
Timestamp uint64
}
type L1TransactionDeposit struct {
SourceHash common.Hash `gorm:"serializer:json;primaryKey"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
SourceHash common.Hash `gorm:"serializer:bytes;primaryKey"`
L2TransactionHash common.Hash `gorm:"serializer:bytes"`
InitiatedL1EventGUID uuid.UUID
Tx Transaction `gorm:"embedded"`
......@@ -33,7 +32,7 @@ type L1TransactionDeposit struct {
}
type L2TransactionWithdrawal struct {
WithdrawalHash common.Hash `gorm:"serializer:json;primaryKey"`
WithdrawalHash common.Hash `gorm:"serializer:bytes;primaryKey"`
Nonce U256
InitiatedL2EventGUID uuid.UUID
......
......@@ -19,12 +19,12 @@ var (
*/
type TokenPair struct {
LocalTokenAddress common.Address `gorm:"serializer:json"`
RemoteTokenAddress common.Address `gorm:"serializer:json"`
LocalTokenAddress common.Address `gorm:"serializer:bytes"`
RemoteTokenAddress common.Address `gorm:"serializer:bytes"`
}
type BridgeTransfer struct {
CrossDomainMessageHash *common.Hash `gorm:"serializer:json"`
CrossDomainMessageHash *common.Hash `gorm:"serializer:bytes"`
Tx Transaction `gorm:"embedded"`
TokenPair TokenPair `gorm:"embedded"`
......@@ -32,27 +32,27 @@ type BridgeTransfer struct {
type L1BridgeDeposit struct {
BridgeTransfer `gorm:"embedded"`
TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:json"`
TransactionSourceHash common.Hash `gorm:"primaryKey;serializer:bytes"`
}
type L1BridgeDepositWithTransactionHashes struct {
L1BridgeDeposit L1BridgeDeposit `gorm:"embedded"`
L1TransactionHash common.Hash `gorm:"serializer:json"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
L1TransactionHash common.Hash `gorm:"serializer:bytes"`
L2TransactionHash common.Hash `gorm:"serializer:bytes"`
}
type L2BridgeWithdrawal struct {
BridgeTransfer `gorm:"embedded"`
TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:json"`
TransactionWithdrawalHash common.Hash `gorm:"primaryKey;serializer:bytes"`
}
type L2BridgeWithdrawalWithTransactionHashes struct {
L2BridgeWithdrawal L2BridgeWithdrawal `gorm:"embedded"`
L2TransactionHash common.Hash `gorm:"serializer:json"`
L2TransactionHash common.Hash `gorm:"serializer:bytes"`
ProvenL1TransactionHash common.Hash `gorm:"serializer:json"`
FinalizedL1TransactionHash common.Hash `gorm:"serializer:json"`
ProvenL1TransactionHash common.Hash `gorm:"serializer:bytes"`
FinalizedL1TransactionHash common.Hash `gorm:"serializer:bytes"`
}
type BridgeTransfersView interface {
......
......@@ -21,12 +21,12 @@ type ContractEvent struct {
GUID uuid.UUID `gorm:"primaryKey"`
// Some useful derived fields
BlockHash common.Hash `gorm:"serializer:json"`
ContractAddress common.Address `gorm:"serializer:json"`
TransactionHash common.Hash `gorm:"serializer:json"`
BlockHash common.Hash `gorm:"serializer:bytes"`
ContractAddress common.Address `gorm:"serializer:bytes"`
TransactionHash common.Hash `gorm:"serializer:bytes"`
LogIndex uint64
EventSignature common.Hash `gorm:"serializer:json"`
EventSignature common.Hash `gorm:"serializer:bytes"`
Timestamp uint64
// NOTE: NOT ALL THE DERIVED FIELDS ON `types.Log` ARE
......
......@@ -5,6 +5,8 @@ import (
"fmt"
"github.com/ethereum-optimism/optimism/indexer/config"
_ "github.com/ethereum-optimism/optimism/indexer/database/serializers"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"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 (
"context"
......@@ -13,38 +13,28 @@ import (
type RLPSerializer struct{}
type RLPInterface interface {
rlp.Encoder
rlp.Decoder
}
func init() {
schema.RegisterSerializer("rlp", RLPSerializer{})
}
func (RLPSerializer) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) error {
fieldValue := reflect.New(field.FieldType)
if dbValue != nil {
var bytes []byte
switch v := dbValue.(type) {
case []byte:
bytes = v
case string:
b, err := hexutil.Decode(v)
if err != nil {
return err
if dbValue == nil {
return nil
}
bytes = b
default:
return fmt.Errorf("unrecognized RLP bytes: %#v", dbValue)
hexStr, ok := dbValue.(string)
if !ok {
return fmt.Errorf("expected hex string as the database value: %T", dbValue)
}
if len(bytes) > 0 {
err := rlp.DecodeBytes(bytes, fieldValue.Interface())
b, err := hexutil.Decode(hexStr)
if err != nil {
return err
}
return fmt.Errorf("failed to decode database value: %w", 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())
......@@ -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) {
// Even though rlp.Encode takes an interface and will error out if the passed interface does not
// satisfy the interface, we check here since we also want to make sure this type satisfies the
// 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)
if fieldValue == nil || (field.FieldType.Kind() == reflect.Pointer && reflect.ValueOf(fieldValue).IsNil()) {
return nil, nil
}
rlpBytes, err := rlp.EncodeToBytes(fieldValue)
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 {
func (h *RLPHeader) Hash() common.Hash {
return h.Header().Hash()
}
type Bytes []byte
func (b Bytes) Bytes() []byte {
return b[:]
}
func (b *Bytes) SetBytes(bytes []byte) {
*b = bytes
}
......@@ -15,26 +15,19 @@ services:
- "5434:5432"
volumes:
- postgres_data:/data/postgres
- ./migrations:/docker-entrypoint-initdb.d/
indexer:
build:
context: ..
dockerfile: indexer/Dockerfile.refresh
command: ["indexer-refresh", "processor"]
# healthcheck:
# Add healthcheck once figure out good way how
# maybe after we add metrics?
ports:
- 8080:8080
dockerfile: indexer/Dockerfile
command: ["indexer", "index"]
environment:
- INDEXER_DB_PORT=5432
- INDEXER_DB_USER=db_username
- INDEXER_DB_PASSWORD=db_password
- INDEXER_DB_NAME=db_name
- INDEXER_DB_HOST=postgres
- INDEXER_CONFIG=/configs/indexer.toml
- INDEXER_RPC_URL_L1=$INDEXER_RPC_URL_L1
- INDEXER_RPC_URL_L2=$INDEXER_RPC_URL_L2
- INDEXER_CONFIG=/indexer/indexer.toml
volumes:
- ./indexer.toml:/configs/indexer.toml
- ./indexer.toml:/indexer/indexer.toml
depends_on:
postgres:
condition: service_healthy
......@@ -43,27 +36,17 @@ services:
build:
context: ..
dockerfile: indexer/Dockerfile
command: ["indexer", "api"]
healthcheck:
test: wget localhost:8080/healthz -q -O - > /dev/null 2>&1
environment:
# Note that you must index goerli with INDEXER_BEDROCK=false first, then
# reindex with INDEXER_BEDROCK=true or seed the database
- INDEXER_BEDROCK=${INDEXER_BEDROCK_GOERLI:-true}
- INDEXER_BUILD_ENV=${INDEXER_BUILD_ENV:-development}
- INDEXER_DB_PORT=${INDEXER_DB_PORT:-5432}
- INDEXER_DB_USER=${INDEXER_DB_USER:-db_username}
- INDEXER_DB_PASSWORD=${INDEXER_DB_PASSWORD:-db_password}
- 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}
- INDEXER_RPC_URL_L1=$INDEXER_RPC_URL_L1
- INDEXER_RPC_URL_L2=$INDEXER_RPC_URL_L2
- INDEXER_CONFIG=/indexer/indexer.toml
volumes:
- ./indexer.toml:/indexer/indexer.toml
ports:
- 8080:8080
depends_on:
......@@ -98,77 +81,6 @@ services:
postgres:
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:
image: ethereumoptimism/gateway-backend:latest
environment:
......
......@@ -155,7 +155,7 @@ func TestE2EBridgeL2CrossDomainMessenger(t *testing.T) {
// (2) Process RelayedMessage on withdrawal finalization
require.Nil(t, sentMessage.RelayedMessageEventGUID)
_, finalizedReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, sentMsgReceipt)
_, finalizedReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.EthInstances["sequencer"], testSuite.OpCfg.Secrets.Alice, sentMsgReceipt)
// wait for processor catchup
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
......
......@@ -129,7 +129,7 @@ func TestE2EBridgeTransactionsL2ToL1MessagePasserWithdrawal(t *testing.T) {
require.Nil(t, withdraw.ProvenL1EventGUID)
require.Nil(t, withdraw.FinalizedL1EventGUID)
withdrawParams, proveReceipt := op_e2e.ProveWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
withdrawParams, proveReceipt := op_e2e.ProveWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.EthInstances["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.BridgeProcessor.LatestL1Header
return l1Header != nil && l1Header.Number.Uint64() >= proveReceipt.BlockNumber.Uint64(), nil
......@@ -189,7 +189,7 @@ func TestE2EBridgeTransactionsL2ToL1MessagePasserFailedWithdrawal(t *testing.T)
require.NoError(t, err)
// Prove&Finalize withdrawal
_, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
_, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.EthInstances["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.BridgeProcessor.LatestL1Header
return l1Header != nil && l1Header.Number.Uint64() >= finalizeReceipt.BlockNumber.Uint64(), nil
......
......@@ -322,7 +322,7 @@ func TestE2EBridgeTransfersStandardBridgeETHWithdrawal(t *testing.T) {
require.Empty(t, aliceWithdrawals.Withdrawals[0].FinalizedL1TransactionHash)
// wait for processor catchup
proveReceipt, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
proveReceipt, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.EthInstances["sequencer"], testSuite.OpCfg.Secrets.Alice, withdrawReceipt)
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.BridgeProcessor.LatestL1Header
return l1Header != nil && l1Header.Number.Uint64() >= finalizeReceipt.BlockNumber.Uint64(), nil
......@@ -400,7 +400,7 @@ func TestE2EBridgeTransfersL2ToL1MessagePasserReceive(t *testing.T) {
require.Empty(t, aliceWithdrawals.Withdrawals[0].FinalizedL1TransactionHash)
// wait for processor catchup
proveReceipt, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.Nodes["sequencer"], testSuite.OpCfg.Secrets.Alice, l2ToL1WithdrawReceipt)
proveReceipt, finalizeReceipt := op_e2e.ProveAndFinalizeWithdrawal(t, *testSuite.OpCfg, testSuite.L1Client, testSuite.OpSys.EthInstances["sequencer"], testSuite.OpCfg.Secrets.Alice, l2ToL1WithdrawReceipt)
require.NoError(t, wait.For(context.Background(), 500*time.Millisecond, func() (bool, error) {
l1Header := testSuite.Indexer.BridgeProcessor.LatestL1Header
return l1Header != nil && l1Header.Number.Uint64() >= finalizeReceipt.BlockNumber.Uint64(), nil
......
......@@ -79,7 +79,7 @@ func TestE2EETL(t *testing.T) {
require.NotNil(t, latestOutput)
require.GreaterOrEqual(t, latestOutput.L2BlockNumber.Int.Uint64(), uint64(9))
l2EthClient, err := node.DialEthClient(testSuite.OpSys.Nodes["sequencer"].HTTPEndpoint())
l2EthClient, err := node.DialEthClient(testSuite.OpSys.EthInstances["sequencer"].HTTPEndpoint())
require.NoError(t, err)
submissionInterval := testSuite.OpCfg.DeployConfig.L2OutputOracleSubmissionInterval
......
......@@ -49,7 +49,8 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
// Rollup System Configuration and Start
opCfg := op_e2e.DefaultSystemConfig(t)
opSys, err := opCfg.Start()
opCfg.DeployConfig.FinalizationPeriodSeconds = 2
opSys, err := opCfg.Start(t)
require.NoError(t, err)
// E2E tests can run on the order of magnitude of minutes. Once
......@@ -66,8 +67,8 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
User: dbUser,
},
RPCs: config.RPCsConfig{
L1RPC: opSys.Nodes["l1"].HTTPEndpoint(),
L2RPC: opSys.Nodes["sequencer"].HTTPEndpoint(),
L1RPC: opSys.EthInstances["l1"].HTTPEndpoint(),
L2RPC: opSys.EthInstances["sequencer"].HTTPEndpoint(),
},
Chain: config.ChainConfig{
L1Contracts: config.L1Contracts{
......
......@@ -11,11 +11,11 @@ l1-rpc = "${INDEXER_RPC_URL_L1}"
l2-rpc = "${INDEXER_RPC_URL_L2}"
[db]
host = "127.0.0.1"
host = "postgres"
port = 5432
user = "postgres"
password = "postgres"
name = "indexer"
user = "db_username"
password = "db_password"
name = "db_name"
[api]
host = "127.0.0.1"
......
......@@ -7,103 +7,200 @@ datasource db {
url = env("DATABASE_URL")
}
model airdrops {
address String @id @db.VarChar(42)
voter_amount String @default("0") @db.VarChar
multisig_signer_amount String @default("0") @db.VarChar
gitcoin_amount String @default("0") @db.VarChar
active_bridged_amount String @default("0") @db.VarChar
op_user_amount String @default("0") @db.VarChar
op_repeat_user_amount String @default("0") @db.VarChar
op_og_amount String @default("0") @db.VarChar
bonus_amount String @default("0") @db.VarChar
total_amount String @db.VarChar
model l1_tokens {
address String @id @db.VarChar
bridge_address String @db.VarChar
l2_token_address String @db.VarChar
name String @db.VarChar
symbol String @db.VarChar
decimals Int
l2_tokens l2_tokens[]
}
model deposits {
guid String @id @db.VarChar
model l2_tokens {
address String @id @db.VarChar
bridge_address String @db.VarChar
l1_token_address String? @db.VarChar
name String @db.VarChar
symbol String @db.VarChar
decimals Int
l1_tokens l1_tokens? @relation(fields: [l1_token_address], references: [address], onDelete: NoAction, onUpdate: NoAction)
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l1_block_headers {
hash String @id @db.VarChar
parent_hash String @db.VarChar
number Decimal @db.Decimal
timestamp Int
rlp_bytes String @db.VarChar
l1_contract_events l1_contract_events[]
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l1_bridge_deposits {
transaction_source_hash String @id @db.VarChar
cross_domain_message_hash String? @unique @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
l1_token String @db.VarChar
l2_token String @db.VarChar
amount String @db.VarChar
data Bytes
log_index Int
local_token_address String @db.VarChar
remote_token_address String @db.VarChar
amount Decimal @db.Decimal
data String @db.VarChar
timestamp Int
l1_bridge_messages l1_bridge_messages? @relation(fields: [cross_domain_message_hash], references: [message_hash], onDelete: NoAction, onUpdate: NoAction)
l1_transaction_deposits l1_transaction_deposits @relation(fields: [transaction_source_hash], references: [source_hash], onDelete: NoAction, onUpdate: NoAction)
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l1_bridge_messages {
message_hash String @id @db.VarChar
nonce Decimal @unique @db.Decimal
transaction_source_hash String @unique @db.VarChar
sent_message_event_guid String @unique @db.VarChar
relayed_message_event_guid String? @unique @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
amount Decimal @db.Decimal
gas_limit Decimal @db.Decimal
data String @db.VarChar
timestamp Int
l1_bridge_deposits l1_bridge_deposits?
l2_contract_events l2_contract_events? @relation(fields: [relayed_message_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l1_contract_events l1_contract_events @relation(fields: [sent_message_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l1_transaction_deposits l1_transaction_deposits @relation(fields: [transaction_source_hash], references: [source_hash], onDelete: NoAction, onUpdate: NoAction)
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l1_contract_events {
guid String @id @db.VarChar
block_hash String @db.VarChar
tx_hash String @db.VarChar
l1_blocks l1_blocks @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction)
l1_tokens l1_tokens @relation(fields: [l1_token], references: [address], onDelete: NoAction, onUpdate: NoAction)
contract_address String @db.VarChar
transaction_hash String @db.VarChar
log_index Int
event_signature String @db.VarChar
timestamp Int
rlp_bytes String @db.VarChar
l1_bridge_messages l1_bridge_messages?
l1_block_headers l1_block_headers @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction)
l1_transaction_deposits l1_transaction_deposits[]
l2_bridge_messages l2_bridge_messages?
l2_transaction_withdrawals_l2_transaction_withdrawals_finalized_l1_event_guidTol1_contract_events l2_transaction_withdrawals[] @relation("l2_transaction_withdrawals_finalized_l1_event_guidTol1_contract_events")
l2_transaction_withdrawals_l2_transaction_withdrawals_proven_l1_event_guidTol1_contract_events l2_transaction_withdrawals[] @relation("l2_transaction_withdrawals_proven_l1_event_guidTol1_contract_events")
legacy_state_batches legacy_state_batches[]
output_proposals output_proposals[]
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l1_transaction_deposits {
source_hash String @id @db.VarChar
l2_transaction_hash String @db.VarChar
initiated_l1_event_guid String @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
amount Decimal @db.Decimal
gas_limit Decimal @db.Decimal
data String @db.VarChar
timestamp Int
l1_bridge_deposits l1_bridge_deposits?
l1_bridge_messages l1_bridge_messages?
l1_contract_events l1_contract_events @relation(fields: [initiated_l1_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
}
model l1_blocks {
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l2_block_headers {
hash String @id @db.VarChar
parent_hash String @db.VarChar
number Int @unique(map: "l1_blocks_number")
number Decimal @db.Decimal
timestamp Int
deposits deposits[]
state_batches state_batches[]
rlp_bytes String @db.VarChar
l2_contract_events l2_contract_events[]
}
model l1_tokens {
address String @id @db.VarChar
name String @db.VarChar
symbol String @db.VarChar
decimals Int
deposits deposits[]
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l2_bridge_messages {
message_hash String @id @db.VarChar
nonce Decimal @unique @db.Decimal
transaction_withdrawal_hash String @unique @db.VarChar
sent_message_event_guid String @unique @db.VarChar
relayed_message_event_guid String? @unique @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
amount Decimal @db.Decimal
gas_limit Decimal @db.Decimal
data String @db.VarChar
timestamp Int
l1_contract_events l1_contract_events? @relation(fields: [relayed_message_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l2_contract_events l2_contract_events @relation(fields: [sent_message_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l2_transaction_withdrawals l2_transaction_withdrawals @relation(fields: [transaction_withdrawal_hash], references: [withdrawal_hash], onDelete: NoAction, onUpdate: NoAction)
l2_bridge_withdrawals l2_bridge_withdrawals?
}
model l2_blocks {
hash String @id @db.VarChar
parent_hash String @db.VarChar
number Int @unique(map: "l2_blocks_number")
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l2_bridge_withdrawals {
transaction_withdrawal_hash String @id @db.VarChar
cross_domain_message_hash String? @unique @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
local_token_address String @db.VarChar
remote_token_address String @db.VarChar
amount Decimal @db.Decimal
data String @db.VarChar
timestamp Int
withdrawals withdrawals[]
l2_bridge_messages l2_bridge_messages? @relation(fields: [cross_domain_message_hash], references: [message_hash], onDelete: NoAction, onUpdate: NoAction)
l2_transaction_withdrawals l2_transaction_withdrawals @relation(fields: [transaction_withdrawal_hash], references: [withdrawal_hash], onDelete: NoAction, onUpdate: NoAction)
}
model l2_tokens {
address String @id
name String
symbol String
decimals Int
withdrawals withdrawals[]
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l2_contract_events {
guid String @id @db.VarChar
block_hash String @db.VarChar
contract_address String @db.VarChar
transaction_hash String @db.VarChar
log_index Int
event_signature String @db.VarChar
timestamp Int
rlp_bytes String @db.VarChar
l1_bridge_messages l1_bridge_messages?
l2_bridge_messages l2_bridge_messages?
l2_block_headers l2_block_headers @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction)
l2_transaction_withdrawals l2_transaction_withdrawals[]
}
/// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info.
model l2_transaction_withdrawals {
withdrawal_hash String @id @db.VarChar
initiated_l2_event_guid String @db.VarChar
proven_l1_event_guid String? @db.VarChar
finalized_l1_event_guid String? @db.VarChar
succeeded Boolean?
nonce Decimal? @unique @db.Decimal
from_address String @db.VarChar
to_address String @db.VarChar
amount Decimal @db.Decimal
gas_limit Decimal @db.Decimal
data String @db.VarChar
timestamp Int
l2_bridge_messages l2_bridge_messages?
l2_bridge_withdrawals l2_bridge_withdrawals?
l1_contract_events_l2_transaction_withdrawals_finalized_l1_event_guidTol1_contract_events l1_contract_events? @relation("l2_transaction_withdrawals_finalized_l1_event_guidTol1_contract_events", fields: [finalized_l1_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l2_contract_events l2_contract_events @relation(fields: [initiated_l2_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
l1_contract_events_l2_transaction_withdrawals_proven_l1_event_guidTol1_contract_events l1_contract_events? @relation("l2_transaction_withdrawals_proven_l1_event_guidTol1_contract_events", fields: [proven_l1_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
}
model state_batches {
model legacy_state_batches {
index Int @id
root String @db.VarChar
size Int
prev_total Int
extra_data Bytes
block_hash String @db.VarChar
l1_blocks l1_blocks @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction)
withdrawals withdrawals[]
@@index([block_hash], map: "state_batches_block_hash")
@@index([prev_total], map: "state_batches_prev_total")
@@index([size], map: "state_batches_size")
l1_contract_event_guid String? @db.VarChar
l1_contract_events l1_contract_events? @relation(fields: [l1_contract_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
}
model withdrawals {
guid String @id @db.VarChar
from_address String @db.VarChar
to_address String @db.VarChar
l1_token String @db.VarChar
l2_token String @db.VarChar
amount String @db.VarChar
data Bytes
log_index Int
block_hash String @db.VarChar
tx_hash String @db.VarChar
state_batch Int?
br_withdrawal_hash String? @db.VarChar
br_withdrawal_proven_tx_hash String? @db.VarChar
br_withdrawal_proven_log_index Int?
br_withdrawal_finalized_tx_hash String? @db.VarChar
br_withdrawal_finalized_log_index Int?
br_withdrawal_finalized_success Boolean?
l2_blocks l2_blocks @relation(fields: [block_hash], references: [hash], onDelete: NoAction, onUpdate: NoAction, map: "l2")
l2_tokens l2_tokens @relation(fields: [l2_token], references: [address], onDelete: NoAction, onUpdate: NoAction)
state_batches state_batches? @relation(fields: [state_batch], references: [index], onDelete: NoAction, onUpdate: NoAction)
@@index([br_withdrawal_hash], map: "withdrawals_br_withdrawal_hash")
model output_proposals {
output_root String @id @db.VarChar
l2_output_index Decimal @db.Decimal
l2_block_number Decimal @db.Decimal
l1_contract_event_guid String? @db.VarChar
l1_contract_events l1_contract_events? @relation(fields: [l1_contract_event_guid], references: [guid], onDelete: NoAction, onUpdate: NoAction)
}
......@@ -31,7 +31,7 @@ var (
// MIPSMetaData contains all meta data concerning the MIPS contract.
var MIPSMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"_oracle\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"oracle_\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x60a060405234801561001057600080fd5b50604051611d67380380611d6783398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051611cd6610091600039600081816085015261149c0152611cd66000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611bdb565b6100d0565b604051908152602001610062565b60006100da611b08565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610619565b915050610611565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106c1565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff168261077d565b945050505050610611565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611c47565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611c47565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff166010610877565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611c47565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f6858784876108ea565b975050505050505050610611565b63ffffffff6000602087831610610469576104248861ffff166010610877565b9095019463fffffffc861661043a8160016106c1565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610afa565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058a578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b8961077d565b9b505050505050505050505050610611565b8063ffffffff16600a03610525576104f3858963ffffffff8a16156111a7565b8063ffffffff16600b03610546576104f3858963ffffffff8a1615156111a7565b8063ffffffff16600c0361055c576104f361128d565b60108163ffffffff16101580156105795750601c8163ffffffff16105b1561058a576104f3818989886117c1565b8863ffffffff1660381480156105a5575063ffffffff861615155b156105da5760018b61016001518763ffffffff16602081106105c9576105c9611c47565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f7576105f7846001846119bb565b610603858360016111a7565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106ac57601c8401518252602090930192600490910190600101610688565b506000815281810382a0819003902092915050565b6000806106cd83611a5f565b905060038416156106dd57600080fd5b6020810190358460051c8160005b601b8110156107435760208501943583821c6001168015610713576001811461072857610739565b60008481526020839052604090209350610739565b600082815260208590526040902093505b50506001016106eb565b50608051915081811461075e57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b6000610787611b08565b60809050806060015160040163ffffffff16816080015163ffffffff1614610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff90811690935285831690529085161561086657806008018261016001518663ffffffff166020811061085557610855611c47565b63ffffffff90921660209290920201525b61086e610619565b95945050505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826108d45760006108d6565b815b90861663ffffffff16179250505092915050565b60006108f4611b08565b608090506000816060015160040163ffffffff16826080015163ffffffff161461097a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610807565b8663ffffffff166004148061099557508663ffffffff166005145b15610a115760008261016001518663ffffffff16602081106109b9576109b9611c47565b602002015190508063ffffffff168563ffffffff161480156109e157508763ffffffff166004145b80610a0957508063ffffffff168563ffffffff1614158015610a0957508763ffffffff166005145b915050610a8e565b8663ffffffff16600603610a2e5760008460030b13159050610a8e565b8663ffffffff16600703610a4a5760008460030b139050610a8e565b8663ffffffff16600103610a8e57601f601087901c166000819003610a735760008560030b1291505b8063ffffffff16600103610a8c5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610ad4576002610ab98861ffff166010610877565b63ffffffff90811690911b8201600401166080840152610ae6565b60808301805160040163ffffffff1690525b610aee610619565b98975050505050505050565b6000603f601a86901c81169086166020821015610ec85760088263ffffffff1610158015610b2e5750600f8263ffffffff16105b15610bce578163ffffffff16600803610b4957506020610bc9565b8163ffffffff16600903610b5f57506021610bc9565b8163ffffffff16600a03610b755750602a610bc9565b8163ffffffff16600b03610b8b5750602b610bc9565b8163ffffffff16600c03610ba157506024610bc9565b8163ffffffff16600d03610bb757506025610bc9565b8163ffffffff16600e03610bc9575060265b600091505b8163ffffffff16600003610e1c57601f600688901c16602063ffffffff83161015610cf65760088263ffffffff1610610c0c57869350505050610611565b8163ffffffff16600003610c2f5763ffffffff86811691161b9250610611915050565b8163ffffffff16600203610c525763ffffffff86811691161c9250610611915050565b8163ffffffff16600303610c8657610c7c8163ffffffff168763ffffffff16901c82602003610877565b9350505050610611565b8163ffffffff16600403610ca9575050505063ffffffff8216601f84161b610611565b8163ffffffff16600603610ccc575050505063ffffffff8216601f84161c610611565b8163ffffffff16600703610cf657610c7c8763ffffffff168763ffffffff16901c88602003610877565b8163ffffffff1660201480610d1157508163ffffffff166021145b15610d23578587019350505050610611565b8163ffffffff1660221480610d3e57508163ffffffff166023145b15610d50578587039350505050610611565b8163ffffffff16602403610d6b578587169350505050610611565b8163ffffffff16602503610d86578587179350505050610611565b8163ffffffff16602603610da1578587189350505050610611565b8163ffffffff16602703610dbc575050505082821719610611565b8163ffffffff16602a03610dee578560030b8760030b12610dde576000610de1565b60015b60ff169350505050610611565b8163ffffffff16602b03610e16578563ffffffff168763ffffffff1610610dde576000610de1565b50611145565b8163ffffffff16600f03610e3e5760108563ffffffff16901b92505050610611565b8163ffffffff16601c03610ec3578063ffffffff16600203610e6557505050828202610611565b8063ffffffff1660201480610e8057508063ffffffff166021145b15610ec3578063ffffffff16602003610e97579419945b60005b6380000000871615610eb9576401fffffffe600197881b169601610e9a565b9250610611915050565b611145565b60288263ffffffff16101561102b578163ffffffff16602003610f1457610f0b8660031660080260180363ffffffff168563ffffffff16901c60ff166008610877565b92505050610611565b8163ffffffff16602103610f4957610f0b8660021660080260100363ffffffff168563ffffffff16901c61ffff166010610877565b8163ffffffff16602203610f795750505063ffffffff60086003851602811681811b198416918316901b17610611565b8163ffffffff16602303610f91578392505050610611565b8163ffffffff16602403610fc4578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610611565b8163ffffffff16602503610ff8578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610611565b8163ffffffff16602603610ec35750505063ffffffff60086003851602601803811681811c198416918316901c17610611565b8163ffffffff166028036110625750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610611565b8163ffffffff1660290361109a5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610611565b8163ffffffff16602a036110ca5750505063ffffffff60086003851602811681811c198316918416901c17610611565b8163ffffffff16602b036110e2578492505050610611565b8163ffffffff16602e036111155750505063ffffffff60086003851602601803811681811b198316918416901b17610611565b8163ffffffff1660300361112d578392505050610611565b8163ffffffff16603803611145578492505050610611565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610807565b60006111b1611b08565b506080602063ffffffff861610611224576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610807565b63ffffffff8516158015906112365750825b1561126a57838161016001518663ffffffff166020811061125957611259611c47565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261086e610619565b6000611297611b08565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113115781610fff8116156112e057610fff811661100003015b8363ffffffff166000036113075760e08801805163ffffffff83820116909152955061130b565b8395505b50611780565b8563ffffffff16610fcd0361132c5763400000009450611780565b8563ffffffff16611018036113445760019450611780565b8563ffffffff166110960361137957600161012088015260ff831661010088015261136d610619565b97505050505050505090565b8563ffffffff16610fa3036115e35763ffffffff831615611780577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161159d5760006113d48363fffffffc1660016106c1565b60208901519091508060001a6001036114415761143e81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156114e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115069190611c76565b9150915060038616806004038281101561151e578092505b508186101561152b578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115828663fffffffc166001866119bb565b60408b018051820163ffffffff16905297506115de92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115d257809450611780565b63ffffffff9450600993505b611780565b8563ffffffff16610fa4036116d45763ffffffff83166001148061160d575063ffffffff83166002145b8061161e575063ffffffff83166004145b1561162b57809450611780565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115d257600061166b8363fffffffc1660016106c1565b60208901519091506003841660040383811015611686578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b17602088015260006040880152935083611780565b8563ffffffff16610fd703611780578163ffffffff166003036117745763ffffffff8316158061170a575063ffffffff83166005145b8061171b575063ffffffff83166003145b156117295760009450611780565b63ffffffff831660011480611744575063ffffffff83166002145b80611755575063ffffffff83166006145b80611766575063ffffffff83166004145b156115d25760019450611780565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261136d610619565b60006117cb611b08565b506080600063ffffffff87166010036117e9575060c0810151611952565b8663ffffffff166011036118085763ffffffff861660c0830152611952565b8663ffffffff16601203611821575060a0810151611952565b8663ffffffff166013036118405763ffffffff861660a0830152611952565b8663ffffffff166018036118745763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611952565b8663ffffffff166019036118a55763ffffffff86811681871602602081901c821660c08501521660a0830152611952565b8663ffffffff16601a036118fb578460030b8660030b816118c8576118c8611c9a565b0763ffffffff1660c0830152600385810b9087900b816118ea576118ea611c9a565b0563ffffffff1660a0830152611952565b8663ffffffff16601b03611952578463ffffffff168663ffffffff168161192457611924611c9a565b0663ffffffff90811660c08401528581169087168161194557611945611c9a565b0463ffffffff1660a08301525b63ffffffff84161561198d57808261016001518563ffffffff166020811061197c5761197c611c47565b63ffffffff90921660209290920201525b60808201805163ffffffff808216606086015260049091011690526119b0610619565b979650505050505050565b60006119c683611a5f565b905060038416156119d657600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a545760208401933582821c6001168015611a245760018114611a3957611a4a565b60008581526020839052604090209450611a4a565b600082815260208690526040902094505b50506001016119fc565b505060805250505050565b60ff811661038002610184810190369061050401811015611b02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610807565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b6e611b73565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611ba457600080fd5b50813567ffffffffffffffff811115611bbc57600080fd5b602083019150836020828501011115611bd457600080fd5b9250929050565b60008060008060408587031215611bf157600080fd5b843567ffffffffffffffff80821115611c0957600080fd5b611c1588838901611b92565b90965094506020870135915080821115611c2e57600080fd5b50611c3b87828801611b92565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c8957600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a",
Bin: "0x60a060405234801561001057600080fd5b50604051611e3e380380611e3e83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051611dad61009160003960008181608501526115730152611dad6000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611cb2565b6100d0565b604051908152602001610062565b60006100da611bdf565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610619565b915050610611565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106c1565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff168261077d565b945050505050610611565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611d1e565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611d1e565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff166010610877565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611d1e565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f6858784876108ea565b975050505050505050610611565b63ffffffff6000602087831610610469576104248861ffff166010610877565b9095019463fffffffc861661043a8160016106c1565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610afa565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058a578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b8961077d565b9b505050505050505050505050610611565b8063ffffffff16600a03610525576104f3858963ffffffff8a161561127e565b8063ffffffff16600b03610546576104f3858963ffffffff8a16151561127e565b8063ffffffff16600c0361055c576104f3611364565b60108163ffffffff16101580156105795750601c8163ffffffff16105b1561058a576104f381898988611898565b8863ffffffff1660381480156105a5575063ffffffff861615155b156105da5760018b61016001518763ffffffff16602081106105c9576105c9611d1e565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f7576105f784600184611a92565b6106038583600161127e565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106ac57601c8401518252602090930192600490910190600101610688565b506000815281810382a0819003902092915050565b6000806106cd83611b36565b905060038416156106dd57600080fd5b6020810190358460051c8160005b601b8110156107435760208501943583821c6001168015610713576001811461072857610739565b60008481526020839052604090209350610739565b600082815260208590526040902093505b50506001016106eb565b50608051915081811461075e57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b6000610787611bdf565b60809050806060015160040163ffffffff16816080015163ffffffff1614610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff90811690935285831690529085161561086657806008018261016001518663ffffffff166020811061085557610855611d1e565b63ffffffff90921660209290920201525b61086e610619565b95945050505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826108d45760006108d6565b815b90861663ffffffff16179250505092915050565b60006108f4611bdf565b608090506000816060015160040163ffffffff16826080015163ffffffff161461097a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610807565b8663ffffffff166004148061099557508663ffffffff166005145b15610a115760008261016001518663ffffffff16602081106109b9576109b9611d1e565b602002015190508063ffffffff168563ffffffff161480156109e157508763ffffffff166004145b80610a0957508063ffffffff168563ffffffff1614158015610a0957508763ffffffff166005145b915050610a8e565b8663ffffffff16600603610a2e5760008460030b13159050610a8e565b8663ffffffff16600703610a4a5760008460030b139050610a8e565b8663ffffffff16600103610a8e57601f601087901c166000819003610a735760008560030b1291505b8063ffffffff16600103610a8c5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610ad4576002610ab98861ffff166010610877565b63ffffffff90811690911b8201600401166080840152610ae6565b60808301805160040163ffffffff1690525b610aee610619565b98975050505050505050565b6000603f601a86901c16801580610b29575060088163ffffffff1610158015610b295750600f8163ffffffff16105b15610f7f57603f86168160088114610b705760098114610b7957600a8114610b8257600b8114610b8b57600c8114610b9457600d8114610b9d57600e8114610ba657610bab565b60209150610bab565b60219150610bab565b602a9150610bab565b602b9150610bab565b60249150610bab565b60259150610bab565b602691505b508063ffffffff16600003610bd25750505063ffffffff8216601f600686901c161b610611565b8063ffffffff16600203610bf85750505063ffffffff8216601f600686901c161c610611565b8063ffffffff16600303610c2e57601f600688901c16610c2463ffffffff8716821c6020839003610877565b9350505050610611565b8063ffffffff16600403610c505750505063ffffffff8216601f84161b610611565b8063ffffffff16600603610c725750505063ffffffff8216601f84161c610611565b8063ffffffff16600703610ca557610c9c8663ffffffff168663ffffffff16901c87602003610877565b92505050610611565b8063ffffffff16600803610cbd578592505050610611565b8063ffffffff16600903610cd5578592505050610611565b8063ffffffff16600a03610ced578592505050610611565b8063ffffffff16600b03610d05578592505050610611565b8063ffffffff16600c03610d1d578592505050610611565b8063ffffffff16600f03610d35578592505050610611565b8063ffffffff16601003610d4d578592505050610611565b8063ffffffff16601103610d65578592505050610611565b8063ffffffff16601203610d7d578592505050610611565b8063ffffffff16601303610d95578592505050610611565b8063ffffffff16601803610dad578592505050610611565b8063ffffffff16601903610dc5578592505050610611565b8063ffffffff16601a03610ddd578592505050610611565b8063ffffffff16601b03610df5578592505050610611565b8063ffffffff16602003610e0e57505050828201610611565b8063ffffffff16602103610e2757505050828201610611565b8063ffffffff16602203610e4057505050818303610611565b8063ffffffff16602303610e5957505050818303610611565b8063ffffffff16602403610e7257505050828216610611565b8063ffffffff16602503610e8b57505050828217610611565b8063ffffffff16602603610ea457505050828218610611565b8063ffffffff16602703610ebe5750505082821719610611565b8063ffffffff16602a03610eef578460030b8660030b12610ee0576000610ee3565b60015b60ff1692505050610611565b8063ffffffff16602b03610f17578463ffffffff168663ffffffff1610610ee0576000610ee3565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610807565b50610f17565b8063ffffffff16601c0361100357603f86166002819003610fa557505050828202610611565b8063ffffffff1660201480610fc057508063ffffffff166021145b15610f79578063ffffffff16602003610fd7579419945b60005b6380000000871615610ff9576401fffffffe600197881b169601610fda565b9250610611915050565b8063ffffffff16600f0361102557505065ffffffff0000601083901b16610611565b8063ffffffff16602003611059576101d38560031660080260180363ffffffff168463ffffffff16901c60ff166008610877565b8063ffffffff1660210361108e576101d38560021660080260100363ffffffff168463ffffffff16901c61ffff166010610877565b8063ffffffff166022036110bd57505063ffffffff60086003851602811681811b198416918316901b17610611565b8063ffffffff166023036110d45782915050610611565b8063ffffffff16602403611106578460031660080260180363ffffffff168363ffffffff16901c60ff16915050610611565b8063ffffffff16602503611139578460021660080260100363ffffffff168363ffffffff16901c61ffff16915050610611565b8063ffffffff1660260361116b57505063ffffffff60086003851602601803811681811c198416918316901c17610611565b8063ffffffff166028036111a157505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610611565b8063ffffffff166029036111d857505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610611565b8063ffffffff16602a0361120757505063ffffffff60086003851602811681811c198316918416901c17610611565b8063ffffffff16602b0361121e5783915050610611565b8063ffffffff16602e0361125057505063ffffffff60086003851602601803811681811b198316918416901b17610611565b8063ffffffff166030036112675782915050610611565b8063ffffffff16603803610f175783915050610611565b6000611288611bdf565b506080602063ffffffff8616106112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610807565b63ffffffff85161580159061130d5750825b1561134157838161016001518663ffffffff166020811061133057611330611d1e565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261086e610619565b600061136e611bdf565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113e85781610fff8116156113b757610fff811661100003015b8363ffffffff166000036113de5760e08801805163ffffffff8382011690915295506113e2565b8395505b50611857565b8563ffffffff16610fcd036114035763400000009450611857565b8563ffffffff166110180361141b5760019450611857565b8563ffffffff166110960361145057600161012088015260ff8316610100880152611444610619565b97505050505050505090565b8563ffffffff16610fa3036116ba5763ffffffff831615611857577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff8416016116745760006114ab8363fffffffc1660016106c1565b60208901519091508060001a6001036115185761151581600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156115b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115dd9190611d4d565b915091506003861680600403828110156115f5578092505b5081861015611602578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506116598663fffffffc16600186611a92565b60408b018051820163ffffffff16905297506116b592505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016116a957809450611857565b63ffffffff9450600993505b611857565b8563ffffffff16610fa4036117ab5763ffffffff8316600114806116e4575063ffffffff83166002145b806116f5575063ffffffff83166004145b1561170257809450611857565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016116a95760006117428363fffffffc1660016106c1565b6020890151909150600384166004038381101561175d578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b17602088015260006040880152935083611857565b8563ffffffff16610fd703611857578163ffffffff1660030361184b5763ffffffff831615806117e1575063ffffffff83166005145b806117f2575063ffffffff83166003145b156118005760009450611857565b63ffffffff83166001148061181b575063ffffffff83166002145b8061182c575063ffffffff83166006145b8061183d575063ffffffff83166004145b156116a95760019450611857565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611444610619565b60006118a2611bdf565b506080600063ffffffff87166010036118c0575060c0810151611a29565b8663ffffffff166011036118df5763ffffffff861660c0830152611a29565b8663ffffffff166012036118f8575060a0810151611a29565b8663ffffffff166013036119175763ffffffff861660a0830152611a29565b8663ffffffff1660180361194b5763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611a29565b8663ffffffff1660190361197c5763ffffffff86811681871602602081901c821660c08501521660a0830152611a29565b8663ffffffff16601a036119d2578460030b8660030b8161199f5761199f611d71565b0763ffffffff1660c0830152600385810b9087900b816119c1576119c1611d71565b0563ffffffff1660a0830152611a29565b8663ffffffff16601b03611a29578463ffffffff168663ffffffff16816119fb576119fb611d71565b0663ffffffff90811660c084015285811690871681611a1c57611a1c611d71565b0463ffffffff1660a08301525b63ffffffff841615611a6457808261016001518563ffffffff1660208110611a5357611a53611d1e565b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611a87610619565b979650505050505050565b6000611a9d83611b36565b90506003841615611aad57600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611b2b5760208401933582821c6001168015611afb5760018114611b1057611b21565b60008581526020839052604090209450611b21565b600082815260208690526040902094505b5050600101611ad3565b505060805250505050565b60ff811661038002610184810190369061050401811015611bd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610807565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611c45611c4a565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611c7b57600080fd5b50813567ffffffffffffffff811115611c9357600080fd5b602083019150836020828501011115611cab57600080fd5b9250929050565b60008060008060408587031215611cc857600080fd5b843567ffffffffffffffff80821115611ce057600080fd5b611cec88838901611c69565b90965094506020870135915080821115611d0557600080fd5b50611d1287828801611c69565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611d6057600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a",
}
// MIPSABI is the input ABI used to generate the binding from.
......
......@@ -13,9 +13,9 @@ const MIPSStorageLayoutJSON = "{\"storage\":null,\"types\":{}}"
var MIPSStorageLayout = new(solc.StorageLayout)
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611bdb565b6100d0565b604051908152602001610062565b60006100da611b08565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610619565b915050610611565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106c1565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff168261077d565b945050505050610611565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611c47565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611c47565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff166010610877565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611c47565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f6858784876108ea565b975050505050505050610611565b63ffffffff6000602087831610610469576104248861ffff166010610877565b9095019463fffffffc861661043a8160016106c1565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610afa565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058a578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b8961077d565b9b505050505050505050505050610611565b8063ffffffff16600a03610525576104f3858963ffffffff8a16156111a7565b8063ffffffff16600b03610546576104f3858963ffffffff8a1615156111a7565b8063ffffffff16600c0361055c576104f361128d565b60108163ffffffff16101580156105795750601c8163ffffffff16105b1561058a576104f3818989886117c1565b8863ffffffff1660381480156105a5575063ffffffff861615155b156105da5760018b61016001518763ffffffff16602081106105c9576105c9611c47565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f7576105f7846001846119bb565b610603858360016111a7565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106ac57601c8401518252602090930192600490910190600101610688565b506000815281810382a0819003902092915050565b6000806106cd83611a5f565b905060038416156106dd57600080fd5b6020810190358460051c8160005b601b8110156107435760208501943583821c6001168015610713576001811461072857610739565b60008481526020839052604090209350610739565b600082815260208590526040902093505b50506001016106eb565b50608051915081811461075e57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b6000610787611b08565b60809050806060015160040163ffffffff16816080015163ffffffff1614610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff90811690935285831690529085161561086657806008018261016001518663ffffffff166020811061085557610855611c47565b63ffffffff90921660209290920201525b61086e610619565b95945050505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826108d45760006108d6565b815b90861663ffffffff16179250505092915050565b60006108f4611b08565b608090506000816060015160040163ffffffff16826080015163ffffffff161461097a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610807565b8663ffffffff166004148061099557508663ffffffff166005145b15610a115760008261016001518663ffffffff16602081106109b9576109b9611c47565b602002015190508063ffffffff168563ffffffff161480156109e157508763ffffffff166004145b80610a0957508063ffffffff168563ffffffff1614158015610a0957508763ffffffff166005145b915050610a8e565b8663ffffffff16600603610a2e5760008460030b13159050610a8e565b8663ffffffff16600703610a4a5760008460030b139050610a8e565b8663ffffffff16600103610a8e57601f601087901c166000819003610a735760008560030b1291505b8063ffffffff16600103610a8c5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610ad4576002610ab98861ffff166010610877565b63ffffffff90811690911b8201600401166080840152610ae6565b60808301805160040163ffffffff1690525b610aee610619565b98975050505050505050565b6000603f601a86901c81169086166020821015610ec85760088263ffffffff1610158015610b2e5750600f8263ffffffff16105b15610bce578163ffffffff16600803610b4957506020610bc9565b8163ffffffff16600903610b5f57506021610bc9565b8163ffffffff16600a03610b755750602a610bc9565b8163ffffffff16600b03610b8b5750602b610bc9565b8163ffffffff16600c03610ba157506024610bc9565b8163ffffffff16600d03610bb757506025610bc9565b8163ffffffff16600e03610bc9575060265b600091505b8163ffffffff16600003610e1c57601f600688901c16602063ffffffff83161015610cf65760088263ffffffff1610610c0c57869350505050610611565b8163ffffffff16600003610c2f5763ffffffff86811691161b9250610611915050565b8163ffffffff16600203610c525763ffffffff86811691161c9250610611915050565b8163ffffffff16600303610c8657610c7c8163ffffffff168763ffffffff16901c82602003610877565b9350505050610611565b8163ffffffff16600403610ca9575050505063ffffffff8216601f84161b610611565b8163ffffffff16600603610ccc575050505063ffffffff8216601f84161c610611565b8163ffffffff16600703610cf657610c7c8763ffffffff168763ffffffff16901c88602003610877565b8163ffffffff1660201480610d1157508163ffffffff166021145b15610d23578587019350505050610611565b8163ffffffff1660221480610d3e57508163ffffffff166023145b15610d50578587039350505050610611565b8163ffffffff16602403610d6b578587169350505050610611565b8163ffffffff16602503610d86578587179350505050610611565b8163ffffffff16602603610da1578587189350505050610611565b8163ffffffff16602703610dbc575050505082821719610611565b8163ffffffff16602a03610dee578560030b8760030b12610dde576000610de1565b60015b60ff169350505050610611565b8163ffffffff16602b03610e16578563ffffffff168763ffffffff1610610dde576000610de1565b50611145565b8163ffffffff16600f03610e3e5760108563ffffffff16901b92505050610611565b8163ffffffff16601c03610ec3578063ffffffff16600203610e6557505050828202610611565b8063ffffffff1660201480610e8057508063ffffffff166021145b15610ec3578063ffffffff16602003610e97579419945b60005b6380000000871615610eb9576401fffffffe600197881b169601610e9a565b9250610611915050565b611145565b60288263ffffffff16101561102b578163ffffffff16602003610f1457610f0b8660031660080260180363ffffffff168563ffffffff16901c60ff166008610877565b92505050610611565b8163ffffffff16602103610f4957610f0b8660021660080260100363ffffffff168563ffffffff16901c61ffff166010610877565b8163ffffffff16602203610f795750505063ffffffff60086003851602811681811b198416918316901b17610611565b8163ffffffff16602303610f91578392505050610611565b8163ffffffff16602403610fc4578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610611565b8163ffffffff16602503610ff8578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610611565b8163ffffffff16602603610ec35750505063ffffffff60086003851602601803811681811c198416918316901c17610611565b8163ffffffff166028036110625750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610611565b8163ffffffff1660290361109a5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610611565b8163ffffffff16602a036110ca5750505063ffffffff60086003851602811681811c198316918416901c17610611565b8163ffffffff16602b036110e2578492505050610611565b8163ffffffff16602e036111155750505063ffffffff60086003851602601803811681811b198316918416901b17610611565b8163ffffffff1660300361112d578392505050610611565b8163ffffffff16603803611145578492505050610611565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610807565b60006111b1611b08565b506080602063ffffffff861610611224576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610807565b63ffffffff8516158015906112365750825b1561126a57838161016001518663ffffffff166020811061125957611259611c47565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261086e610619565b6000611297611b08565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113115781610fff8116156112e057610fff811661100003015b8363ffffffff166000036113075760e08801805163ffffffff83820116909152955061130b565b8395505b50611780565b8563ffffffff16610fcd0361132c5763400000009450611780565b8563ffffffff16611018036113445760019450611780565b8563ffffffff166110960361137957600161012088015260ff831661010088015261136d610619565b97505050505050505090565b8563ffffffff16610fa3036115e35763ffffffff831615611780577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff84160161159d5760006113d48363fffffffc1660016106c1565b60208901519091508060001a6001036114415761143e81600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156114e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115069190611c76565b9150915060038616806004038281101561151e578092505b508186101561152b578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506115828663fffffffc166001866119bb565b60408b018051820163ffffffff16905297506115de92505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016115d257809450611780565b63ffffffff9450600993505b611780565b8563ffffffff16610fa4036116d45763ffffffff83166001148061160d575063ffffffff83166002145b8061161e575063ffffffff83166004145b1561162b57809450611780565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016115d257600061166b8363fffffffc1660016106c1565b60208901519091506003841660040383811015611686578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b17602088015260006040880152935083611780565b8563ffffffff16610fd703611780578163ffffffff166003036117745763ffffffff8316158061170a575063ffffffff83166005145b8061171b575063ffffffff83166003145b156117295760009450611780565b63ffffffff831660011480611744575063ffffffff83166002145b80611755575063ffffffff83166006145b80611766575063ffffffff83166004145b156115d25760019450611780565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261136d610619565b60006117cb611b08565b506080600063ffffffff87166010036117e9575060c0810151611952565b8663ffffffff166011036118085763ffffffff861660c0830152611952565b8663ffffffff16601203611821575060a0810151611952565b8663ffffffff166013036118405763ffffffff861660a0830152611952565b8663ffffffff166018036118745763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611952565b8663ffffffff166019036118a55763ffffffff86811681871602602081901c821660c08501521660a0830152611952565b8663ffffffff16601a036118fb578460030b8660030b816118c8576118c8611c9a565b0763ffffffff1660c0830152600385810b9087900b816118ea576118ea611c9a565b0563ffffffff1660a0830152611952565b8663ffffffff16601b03611952578463ffffffff168663ffffffff168161192457611924611c9a565b0663ffffffff90811660c08401528581169087168161194557611945611c9a565b0463ffffffff1660a08301525b63ffffffff84161561198d57808261016001518563ffffffff166020811061197c5761197c611c47565b63ffffffff90921660209290920201525b60808201805163ffffffff808216606086015260049091011690526119b0610619565b979650505050505050565b60006119c683611a5f565b905060038416156119d657600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611a545760208401933582821c6001168015611a245760018114611a3957611a4a565b60008581526020839052604090209450611a4a565b600082815260208690526040902094505b50506001016119fc565b505060805250505050565b60ff811661038002610184810190369061050401811015611b02576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610807565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611b6e611b73565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611ba457600080fd5b50813567ffffffffffffffff811115611bbc57600080fd5b602083019150836020828501011115611bd457600080fd5b9250929050565b60008060008060408587031215611bf157600080fd5b843567ffffffffffffffff80821115611c0957600080fd5b611c1588838901611b92565b90965094506020870135915080821115611c2e57600080fd5b50611c3b87828801611b92565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611c8957600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d01461006b578063f8e0cb96146100af575b600080fd5b610051634000000081565b60405163ffffffff90911681526020015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610062565b6100c26100bd366004611cb2565b6100d0565b604051908152602001610062565b60006100da611bdf565b608081146100e757600080fd5b604051610600146100f757600080fd5b6064861461010457600080fd5b610184841461011257600080fd5b8535608052602086013560a052604086013560e090811c60c09081526044880135821c82526048880135821c61010052604c880135821c610120526050880135821c61014052605488013590911c61016052605887013560f890811c610180526059880135901c6101a052605a870135901c6101c0526102006101e0819052606287019060005b60208110156101bd57823560e01c8252600490920191602090910190600101610199565b505050806101200151156101db576101d3610619565b915050610611565b6101408101805160010167ffffffffffffffff169052606081015160009061020390826106c1565b9050603f601a82901c16600281148061022257508063ffffffff166003145b156102775760006002836303ffffff1663ffffffff16901b846080015163f00000001617905061026c8263ffffffff1660021461026057601f610263565b60005b60ff168261077d565b945050505050610611565b6101608301516000908190601f601086901c81169190601587901c16602081106102a3576102a3611d1e565b602002015192508063ffffffff851615806102c457508463ffffffff16601c145b156102fb578661016001518263ffffffff16602081106102e6576102e6611d1e565b6020020151925050601f600b86901c166103b7565b60208563ffffffff16101561035d578463ffffffff16600c148061032557508463ffffffff16600d145b8061033657508463ffffffff16600e145b15610347578561ffff1692506103b7565b6103568661ffff166010610877565b92506103b7565b60288563ffffffff1610158061037957508463ffffffff166022145b8061038a57508463ffffffff166026145b156103b7578661016001518263ffffffff16602081106103ac576103ac611d1e565b602002015192508190505b60048563ffffffff16101580156103d4575060088563ffffffff16105b806103e557508463ffffffff166001145b15610404576103f6858784876108ea565b975050505050505050610611565b63ffffffff6000602087831610610469576104248861ffff166010610877565b9095019463fffffffc861661043a8160016106c1565b915060288863ffffffff161015801561045a57508763ffffffff16603014155b1561046757809250600093505b505b600061047789888885610afa565b63ffffffff9081169150603f8a1690891615801561049c575060088163ffffffff1610155b80156104ae5750601c8163ffffffff16105b1561058a578063ffffffff16600814806104ce57508063ffffffff166009145b15610505576104f38163ffffffff166008146104ea57856104ed565b60005b8961077d565b9b505050505050505050505050610611565b8063ffffffff16600a03610525576104f3858963ffffffff8a161561127e565b8063ffffffff16600b03610546576104f3858963ffffffff8a16151561127e565b8063ffffffff16600c0361055c576104f3611364565b60108163ffffffff16101580156105795750601c8163ffffffff16105b1561058a576104f381898988611898565b8863ffffffff1660381480156105a5575063ffffffff861615155b156105da5760018b61016001518763ffffffff16602081106105c9576105c9611d1e565b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146105f7576105f784600184611a92565b6106038583600161127e565b9b5050505050505050505050505b949350505050565b60408051608051815260a051602082015260dc519181019190915260fc51604482015261011c51604882015261013c51604c82015261015c51605082015261017c51605482015261019f5160588201526101bf5160598201526101d851605a8201526000906102009060628101835b60208110156106ac57601c8401518252602090930192600490910190600101610688565b506000815281810382a0819003902092915050565b6000806106cd83611b36565b905060038416156106dd57600080fd5b6020810190358460051c8160005b601b8110156107435760208501943583821c6001168015610713576001811461072857610739565b60008481526020839052604090209350610739565b600082815260208590526040902093505b50506001016106eb565b50608051915081811461075e57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b6000610787611bdf565b60809050806060015160040163ffffffff16816080015163ffffffff1614610810576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6a756d7020696e2064656c617920736c6f74000000000000000000000000000060448201526064015b60405180910390fd5b60608101805160808301805163ffffffff90811690935285831690529085161561086657806008018261016001518663ffffffff166020811061085557610855611d1e565b63ffffffff90921660209290920201525b61086e610619565b95945050505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b01826108d45760006108d6565b815b90861663ffffffff16179250505092915050565b60006108f4611bdf565b608090506000816060015160040163ffffffff16826080015163ffffffff161461097a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6272616e636820696e2064656c617920736c6f740000000000000000000000006044820152606401610807565b8663ffffffff166004148061099557508663ffffffff166005145b15610a115760008261016001518663ffffffff16602081106109b9576109b9611d1e565b602002015190508063ffffffff168563ffffffff161480156109e157508763ffffffff166004145b80610a0957508063ffffffff168563ffffffff1614158015610a0957508763ffffffff166005145b915050610a8e565b8663ffffffff16600603610a2e5760008460030b13159050610a8e565b8663ffffffff16600703610a4a5760008460030b139050610a8e565b8663ffffffff16600103610a8e57601f601087901c166000819003610a735760008560030b1291505b8063ffffffff16600103610a8c5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610ad4576002610ab98861ffff166010610877565b63ffffffff90811690911b8201600401166080840152610ae6565b60808301805160040163ffffffff1690525b610aee610619565b98975050505050505050565b6000603f601a86901c16801580610b29575060088163ffffffff1610158015610b295750600f8163ffffffff16105b15610f7f57603f86168160088114610b705760098114610b7957600a8114610b8257600b8114610b8b57600c8114610b9457600d8114610b9d57600e8114610ba657610bab565b60209150610bab565b60219150610bab565b602a9150610bab565b602b9150610bab565b60249150610bab565b60259150610bab565b602691505b508063ffffffff16600003610bd25750505063ffffffff8216601f600686901c161b610611565b8063ffffffff16600203610bf85750505063ffffffff8216601f600686901c161c610611565b8063ffffffff16600303610c2e57601f600688901c16610c2463ffffffff8716821c6020839003610877565b9350505050610611565b8063ffffffff16600403610c505750505063ffffffff8216601f84161b610611565b8063ffffffff16600603610c725750505063ffffffff8216601f84161c610611565b8063ffffffff16600703610ca557610c9c8663ffffffff168663ffffffff16901c87602003610877565b92505050610611565b8063ffffffff16600803610cbd578592505050610611565b8063ffffffff16600903610cd5578592505050610611565b8063ffffffff16600a03610ced578592505050610611565b8063ffffffff16600b03610d05578592505050610611565b8063ffffffff16600c03610d1d578592505050610611565b8063ffffffff16600f03610d35578592505050610611565b8063ffffffff16601003610d4d578592505050610611565b8063ffffffff16601103610d65578592505050610611565b8063ffffffff16601203610d7d578592505050610611565b8063ffffffff16601303610d95578592505050610611565b8063ffffffff16601803610dad578592505050610611565b8063ffffffff16601903610dc5578592505050610611565b8063ffffffff16601a03610ddd578592505050610611565b8063ffffffff16601b03610df5578592505050610611565b8063ffffffff16602003610e0e57505050828201610611565b8063ffffffff16602103610e2757505050828201610611565b8063ffffffff16602203610e4057505050818303610611565b8063ffffffff16602303610e5957505050818303610611565b8063ffffffff16602403610e7257505050828216610611565b8063ffffffff16602503610e8b57505050828217610611565b8063ffffffff16602603610ea457505050828218610611565b8063ffffffff16602703610ebe5750505082821719610611565b8063ffffffff16602a03610eef578460030b8660030b12610ee0576000610ee3565b60015b60ff1692505050610611565b8063ffffffff16602b03610f17578463ffffffff168663ffffffff1610610ee0576000610ee3565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e000000000000000000000000006044820152606401610807565b50610f17565b8063ffffffff16601c0361100357603f86166002819003610fa557505050828202610611565b8063ffffffff1660201480610fc057508063ffffffff166021145b15610f79578063ffffffff16602003610fd7579419945b60005b6380000000871615610ff9576401fffffffe600197881b169601610fda565b9250610611915050565b8063ffffffff16600f0361102557505065ffffffff0000601083901b16610611565b8063ffffffff16602003611059576101d38560031660080260180363ffffffff168463ffffffff16901c60ff166008610877565b8063ffffffff1660210361108e576101d38560021660080260100363ffffffff168463ffffffff16901c61ffff166010610877565b8063ffffffff166022036110bd57505063ffffffff60086003851602811681811b198416918316901b17610611565b8063ffffffff166023036110d45782915050610611565b8063ffffffff16602403611106578460031660080260180363ffffffff168363ffffffff16901c60ff16915050610611565b8063ffffffff16602503611139578460021660080260100363ffffffff168363ffffffff16901c61ffff16915050610611565b8063ffffffff1660260361116b57505063ffffffff60086003851602601803811681811c198416918316901c17610611565b8063ffffffff166028036111a157505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610611565b8063ffffffff166029036111d857505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610611565b8063ffffffff16602a0361120757505063ffffffff60086003851602811681811c198316918416901c17610611565b8063ffffffff16602b0361121e5783915050610611565b8063ffffffff16602e0361125057505063ffffffff60086003851602601803811681811b198316918416901b17610611565b8063ffffffff166030036112675782915050610611565b8063ffffffff16603803610f175783915050610611565b6000611288611bdf565b506080602063ffffffff8616106112fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c69642072656769737465720000000000000000000000000000000000006044820152606401610807565b63ffffffff85161580159061130d5750825b1561134157838161016001518663ffffffff166020811061133057611330611d1e565b63ffffffff90921660209290920201525b60808101805163ffffffff8082166060850152600490910116905261086e610619565b600061136e611bdf565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa036113e85781610fff8116156113b757610fff811661100003015b8363ffffffff166000036113de5760e08801805163ffffffff8382011690915295506113e2565b8395505b50611857565b8563ffffffff16610fcd036114035763400000009450611857565b8563ffffffff166110180361141b5760019450611857565b8563ffffffff166110960361145057600161012088015260ff8316610100880152611444610619565b97505050505050505090565b8563ffffffff16610fa3036116ba5763ffffffff831615611857577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb63ffffffff8416016116745760006114ab8363fffffffc1660016106c1565b60208901519091508060001a6001036115185761151581600090815233602052604090207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790565b90505b6040808a015190517fe03110e10000000000000000000000000000000000000000000000000000000081526004810183905263ffffffff9091166024820152600090819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e03110e1906044016040805180830381865afa1580156115b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115dd9190611d4d565b915091506003861680600403828110156115f5578092505b5081861015611602578591505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119871617955050506116598663fffffffc16600186611a92565b60408b018051820163ffffffff16905297506116b592505050565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd63ffffffff8416016116a957809450611857565b63ffffffff9450600993505b611857565b8563ffffffff16610fa4036117ab5763ffffffff8316600114806116e4575063ffffffff83166002145b806116f5575063ffffffff83166004145b1561170257809450611857565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa63ffffffff8416016116a95760006117428363fffffffc1660016106c1565b6020890151909150600384166004038381101561175d578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b17602088015260006040880152935083611857565b8563ffffffff16610fd703611857578163ffffffff1660030361184b5763ffffffff831615806117e1575063ffffffff83166005145b806117f2575063ffffffff83166003145b156118005760009450611857565b63ffffffff83166001148061181b575063ffffffff83166002145b8061182c575063ffffffff83166006145b8061183d575063ffffffff83166004145b156116a95760019450611857565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611444610619565b60006118a2611bdf565b506080600063ffffffff87166010036118c0575060c0810151611a29565b8663ffffffff166011036118df5763ffffffff861660c0830152611a29565b8663ffffffff166012036118f8575060a0810151611a29565b8663ffffffff166013036119175763ffffffff861660a0830152611a29565b8663ffffffff1660180361194b5763ffffffff600387810b9087900b02602081901c821660c08501521660a0830152611a29565b8663ffffffff1660190361197c5763ffffffff86811681871602602081901c821660c08501521660a0830152611a29565b8663ffffffff16601a036119d2578460030b8660030b8161199f5761199f611d71565b0763ffffffff1660c0830152600385810b9087900b816119c1576119c1611d71565b0563ffffffff1660a0830152611a29565b8663ffffffff16601b03611a29578463ffffffff168663ffffffff16816119fb576119fb611d71565b0663ffffffff90811660c084015285811690871681611a1c57611a1c611d71565b0463ffffffff1660a08301525b63ffffffff841615611a6457808261016001518563ffffffff1660208110611a5357611a53611d1e565b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611a87610619565b979650505050505050565b6000611a9d83611b36565b90506003841615611aad57600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b811015611b2b5760208401933582821c6001168015611afb5760018114611b1057611b21565b60008581526020839052604090209450611b21565b600082815260208690526040902094505b5050600101611ad3565b505060805250505050565b60ff811661038002610184810190369061050401811015611bd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f636865636b207468617420746865726520697320656e6f7567682063616c6c6460448201527f61746100000000000000000000000000000000000000000000000000000000006064820152608401610807565b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611c45611c4a565b905290565b6040518061040001604052806020906020820280368337509192915050565b60008083601f840112611c7b57600080fd5b50813567ffffffffffffffff811115611c9357600080fd5b602083019150836020828501011115611cab57600080fd5b9250929050565b60008060008060408587031215611cc857600080fd5b843567ffffffffffffffff80821115611ce057600080fd5b611cec88838901611c69565b90965094506020870135915080821115611d0557600080fd5b50611d1287828801611c69565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008060408385031215611d6057600080fd5b505080516020909101519092909150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea164736f6c634300080f000a"
var MIPSDeployedSourceMap = "1131:37346:105:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:257;176:23;;;158:42;;146:2;131:18;1710:45:105;;;;;;;;2448:99;;;412:42:257;2534:6:105;400:55:257;382:74;;370:2;355:18;2448:99:105;211:251:257;24925:6339:105;;;;;;:::i;:::-;;:::i;:::-;;;1687:25:257;;;1675:2;1660:18;24925:6339:105;1541:177:257;24925:6339:105;25003:7;25046:18;;:::i;:::-;25193:4;25186:5;25183:15;25173:134;;25287:1;25284;25277:12;25173:134;25343:4;25337:11;25350;25334:28;25324:137;;25441:1;25438;25431:12;25324:137;25509:3;25491:16;25488:25;25478:150;;25608:1;25605;25598:12;25478:150;25672:3;25658:12;25655:21;25645:145;;25770:1;25767;25760:12;25645:145;26050:24;;26394:4;26096:20;26452:2;26154:21;;26050:24;26212:18;26096:20;26154:21;;;26050:24;26027:21;26023:52;;;26212:18;26096:20;;;26154:21;;;26050:24;26023:52;;26096:20;;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;;26212:18;26096:20;26154:21;;;26050:24;26027:21;26023:52;;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;26154:21;;;26050:24;26023:52;;26212:18;26096:20;27070:10;26212:18;27060:21;;;26154;;;;27168:1;27153:77;27178:2;27175:1;27172:9;27153:77;;;26050:24;;26027:21;26023:52;26096:20;;27226:1;26154:21;;;;26038:2;26212:18;;;;27196:1;27189:9;27153:77;;;27157:14;;;27308:5;:12;;;27304:71;;;27347:13;:11;:13::i;:::-;27340:20;;;;;27304:71;27389:10;;;:15;;27403:1;27389:15;;;;;27474:8;;;;-1:-1:-1;;27466:20:105;;-1:-1:-1;27466:7:105;:20::i;:::-;27452:34;-1:-1:-1;27516:10:105;27524:2;27516:10;;;;27593:1;27583:11;;;:26;;;27598:6;:11;;27608:1;27598:11;27583:26;27579:310;;;27739:13;27808:1;27786:4;27793:10;27786:17;27785:24;;;;27756:5;:12;;;27771:10;27756:25;27755:54;27739:70;;27834:40;27845:6;:11;;27855:1;27845:11;:20;;27863:2;27845:20;;;27859:1;27845:20;27834:40;;27867:6;27834:10;:40::i;:::-;27827:47;;;;;;;;27579:310;28138:15;;;;27933:9;;;;28070:4;28064:2;28056:10;;;28055:19;;;28138:15;28163:2;28155:10;;;28154:19;28138:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;28203:5:105;28227:11;;;;;:29;;;28242:6;:14;;28252:4;28242:14;28227:29;28223:832;;;28319:5;:15;;;28335:5;28319:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;28382:4:105;28376:2;28368:10;;;28367:19;28223:832;;;28420:4;28411:6;:13;;;28407:648;;;28541:6;:13;;28551:3;28541:13;:30;;;;28558:6;:13;;28568:3;28558:13;28541:30;:47;;;;28575:6;:13;;28585:3;28575:13;28541:47;28537:253;;;28651:4;28658:6;28651:13;28646:18;;28407:648;;28537:253;28750:21;28753:4;28760:6;28753:13;28768:2;28750;:21::i;:::-;28745:26;;28407:648;;;28824:4;28814:6;:14;;;;:32;;;;28832:6;:14;;28842:4;28832:14;28814:32;:50;;;;28850:6;:14;;28860:4;28850:14;28814:50;28810:245;;;28934:5;:15;;;28950:5;28934:22;;;;;;;;;:::i;:::-;;;;;28929:27;;29035:5;29027:13;;28810:245;29084:1;29074:6;:11;;;;:25;;;;;29098:1;29089:6;:10;;;29074:25;29073:42;;;;29104:6;:11;;29114:1;29104:11;29073:42;29069:125;;;29142:37;29155:6;29163:4;29169:5;29176:2;29142:12;:37::i;:::-;29135:44;;;;;;;;;;;29069:125;29227:13;29208:16;29379:4;29369:14;;;;29365:446;;29448:21;29451:4;29458:6;29451:13;29466:2;29448;:21::i;:::-;29442:27;;;;29506:10;29501:15;;29540:16;29501:15;29554:1;29540:7;:16::i;:::-;29534:22;;29588:4;29578:6;:14;;;;:32;;;;;29596:6;:14;;29606:4;29596:14;;29578:32;29574:223;;;29675:4;29663:16;;29777:1;29769:9;;29574:223;29385:426;29365:446;29844:10;29857:26;29865:4;29871:2;29875;29879:3;29857:7;:26::i;:::-;29886:10;29857:39;;;;-1:-1:-1;29982:4:105;29975:11;;;30014;;;:24;;;;;30037:1;30029:4;:9;;;;30014:24;:39;;;;;30049:4;30042;:11;;;30014:39;30010:847;;;30077:4;:9;;30085:1;30077:9;:22;;;;30090:4;:9;;30098:1;30090:9;30077:22;30073:144;;;30161:37;30172:4;:9;;30180:1;30172:9;:21;;30188:5;30172:21;;;30184:1;30172:21;30195:2;30161:10;:37::i;:::-;30154:44;;;;;;;;;;;;;;;30073:144;30239:4;:11;;30247:3;30239:11;30235:121;;30309:28;30318:5;30325:2;30329:7;;;;30309:8;:28::i;30235:121::-;30377:4;:11;;30385:3;30377:11;30373:121;;30447:28;30456:5;30463:2;30467:7;;;;;30447:8;:28::i;30373:121::-;30564:4;:11;;30572:3;30564:11;30560:80;;30606:15;:13;:15::i;30560:80::-;30743:4;30735;:12;;;;:27;;;;;30758:4;30751;:11;;;30735:27;30731:112;;;30793:31;30804:4;30810:2;30814;30818:5;30793:10;:31::i;30731:112::-;30917:6;:14;;30927:4;30917:14;:28;;;;-1:-1:-1;30935:10:105;;;;;30917:28;30913:93;;;30990:1;30965:5;:15;;;30981:5;30965:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;30913:93;31052:9;:26;;31065:13;31052:26;31048:92;;31098:27;31107:9;31118:1;31121:3;31098:8;:27::i;:::-;31221:26;31230:5;31237:3;31242:4;31221:8;:26::i;:::-;31214:33;;;;;;;;;;;;;24925:6339;;;;;;;:::o;3087:1709::-;3634:4;3628:11;;3550:4;3353:31;3342:43;;3413:13;3353:31;3752:2;3452:13;;3342:43;3359:24;3353:31;3452:13;;;3342:43;;;;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3359:24;3353:31;3452:13;;;3342:43;3128:12;;4337:13;;3452;;;3128:12;4417:84;4442:2;4439:1;4436:9;4417:84;;;3369:13;3359:24;;3353:31;3342:43;;3373:2;3413:13;;;;4497:1;3452:13;;;;4460:1;4453:9;4417:84;;;4421:14;4564:1;4560:2;4553:13;4659:5;4655:2;4651:14;4644:5;4639:27;4765:14;;;4748:32;;;3087:1709;-1:-1:-1;;3087:1709:105:o;20980:1831::-;21053:11;21164:14;21181:24;21193:11;21181;:24::i;:::-;21164:41;;21313:1;21306:5;21302:13;21299:33;;;21328:1;21325;21318:12;21299:33;21461:2;21449:15;;;21402:20;21891:5;21888:1;21884:13;21926:4;21962:1;21947:343;21972:2;21969:1;21966:9;21947:343;;;22095:2;22083:15;;;22032:20;22130:12;;;22144:1;22126:20;22167:42;;;;22235:1;22230:42;;;;22119:153;;22167:42;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;22176:31;;22167:42;;22230;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;22239:31;;22119:153;-1:-1:-1;;21990:1:105;21983:9;21947:343;;;21951:14;22400:4;22394:11;22379:26;;22486:7;22480:4;22477:17;22467:124;;22528:10;22525:1;22518:21;22570:2;22567:1;22560:13;22467:124;-1:-1:-1;;22718:2:105;22707:14;;;;22695:10;22691:31;22688:1;22684:39;22752:16;;;;22770:10;22748:33;;20980:1831;-1:-1:-1;;;20980:1831:105:o;18090:823::-;18159:12;18246:18;;:::i;:::-;18314:4;18305:13;;18366:5;:8;;;18377:1;18366:12;18350:28;;:5;:12;;;:28;;;18346:95;;18398:28;;;;;2114:2:257;18398:28:105;;;2096:21:257;2153:2;2133:18;;;2126:30;2192:20;2172:18;;;2165:48;2230:18;;18398:28:105;;;;;;;;18346:95;18530:8;;;;;18563:12;;;;;18552:23;;;;;;;18589:20;;;;;18530:8;18721:13;;;18717:90;;18782:6;18791:1;18782:10;18754:5;:15;;;18770:8;18754:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;18717:90;18883:13;:11;:13::i;:::-;18876:20;18090:823;-1:-1:-1;;;;;18090:823:105:o;2645:334::-;2706:6;2765:18;;;;2774:8;;;;2765:18;;;;;;2764:25;;;;;2781:1;2828:2;:9;;;2822:16;;;;;2821:22;;2820:32;;;;;;;2882:9;;2881:15;2764:25;2939:21;;2959:1;2939:21;;;2950:6;2939:21;2924:11;;;;;:37;;-1:-1:-1;;;2645:334:105;;;;:::o;12951:2026::-;13048:12;13134:18;;:::i;:::-;13202:4;13193:13;;13234:17;13294:5;:8;;;13305:1;13294:12;13278:28;;:5;:12;;;:28;;;13274:97;;13326:30;;;;;2461:2:257;13326:30:105;;;2443:21:257;2500:2;2480:18;;;2473:30;2539:22;2519:18;;;2512:50;2579:18;;13326:30:105;2259:344:257;13274:97:105;13441:7;:12;;13452:1;13441:12;:28;;;;13457:7;:12;;13468:1;13457:12;13441:28;13437:947;;;13489:9;13501:5;:15;;;13517:6;13501:23;;;;;;;;;:::i;:::-;;;;;13489:35;;13565:2;13558:9;;:3;:9;;;:25;;;;;13571:7;:12;;13582:1;13571:12;13558:25;13557:58;;;;13596:2;13589:9;;:3;:9;;;;:25;;;;;13602:7;:12;;13613:1;13602:12;13589:25;13542:73;;13471:159;13437:947;;;13727:7;:12;;13738:1;13727:12;13723:661;;13788:1;13780:3;13774:15;;;;13759:30;;13723:661;;;13892:7;:12;;13903:1;13892:12;13888:496;;13952:1;13945:3;13939:14;;;13924:29;;13888:496;;;14073:7;:12;;14084:1;14073:12;14069:315;;14161:4;14155:2;14146:11;;;14145:20;14131:10;14188:8;;;14184:84;;14248:1;14241:3;14235:14;;;14220:29;;14184:84;14289:3;:8;;14296:1;14289:8;14285:85;;14350:1;14342:3;14336:15;;;;14321:30;;14285:85;14087:297;14069:315;14460:8;;;;;14538:12;;;;14527:23;;;;;14694:178;;;;14785:1;14759:22;14762:5;14770:6;14762:14;14778:2;14759;:22::i;:::-;:27;;;;;;;14745:42;;14754:1;14745:42;14730:57;:12;;;:57;14694:178;;;14841:12;;;;;14856:1;14841:16;14826:31;;;;14694:178;14947:13;:11;:13::i;:::-;14940:20;12951:2026;-1:-1:-1;;;;;;;;12951:2026:105:o;31310:7165::-;31397:6;31455:10;31463:2;31455:10;;;;;;31503:11;;31552:4;31543:13;;31539:6876;;;31683:1;31673:6;:11;;;;:27;;;;;31697:3;31688:6;:12;;;31673:27;31669:537;;;31728:6;:11;;31738:1;31728:11;31724:423;;-1:-1:-1;31748:4:105;31724:423;;;31792:6;:11;;31802:1;31792:11;31788:359;;-1:-1:-1;31812:4:105;31788:359;;;31857:6;:13;;31867:3;31857:13;31853:294;;-1:-1:-1;31879:4:105;31853:294;;;31923:6;:13;;31933:3;31923:13;31919:228;;-1:-1:-1;31945:4:105;31919:228;;;31990:6;:13;;32000:3;31990:13;31986:161;;-1:-1:-1;32012:4:105;31986:161;;;32056:6;:13;;32066:3;32056:13;32052:95;;-1:-1:-1;32078:4:105;32052:95;;;32121:6;:13;;32131:3;32121:13;32117:30;;-1:-1:-1;32143:4:105;32117:30;32186:1;32177:10;;31669:537;32267:6;:11;;32277:1;32267:11;32263:3554;;32331:4;32326:1;32318:9;;;32317:18;32368:4;32318:9;32361:11;;;32357:1319;;;32460:4;32452;:12;;;32448:1206;;32503:2;32496:9;;;;;;;32448:1206;32617:4;:12;;32625:4;32617:12;32613:1041;;32668:11;;;;;;;;-1:-1:-1;32661:18:105;;-1:-1:-1;;32661:18:105;32613:1041;32792:4;:12;;32800:4;32792:12;32788:866;;32843:11;;;;;;;;-1:-1:-1;32836:18:105;;-1:-1:-1;;32836:18:105;32788:866;32970:4;:12;;32978:4;32970:12;32966:688;;33021:27;33030:5;33024:11;;:2;:11;;;;33042:5;33037:2;:10;33021:2;:27::i;:::-;33014:34;;;;;;;32966:688;33170:4;:12;;33178:4;33170:12;33166:488;;-1:-1:-1;;;;33221:17:105;;;33233:4;33228:9;;33221:17;33214:24;;33166:488;33361:4;:12;;33369:4;33361:12;33357:297;;-1:-1:-1;;;;33412:17:105;;;33424:4;33419:9;;33412:17;33405:24;;33357:297;33555:4;:12;;33563:4;33555:12;33551:103;;33606:21;33615:2;33609:8;;:2;:8;;;;33624:2;33619;:7;33606:2;:21::i;33551:103::-;33836:4;:12;;33844:4;33836:12;:28;;;;33852:4;:12;;33860:4;33852:12;33836:28;33832:1151;;;33904:2;33899;:7;33892:14;;;;;;;33832:1151;33994:4;:12;;34002:4;33994:12;:28;;;;34010:4;:12;;34018:4;34010:12;33994:28;33990:993;;;34062:2;34057;:7;34050:14;;;;;;;33990:993;34144:4;:12;;34152:4;34144:12;34140:843;;34196:2;34191;:7;34184:14;;;;;;;34140:843;34277:4;:12;;34285:4;34277:12;34273:710;;34330:2;34325;:7;34317:16;;;;;;;34273:710;34413:4;:12;;34421:4;34413:12;34409:574;;34466:2;34461;:7;34453:16;;;;;;;34409:574;34549:4;:12;;34557:4;34549:12;34545:438;;-1:-1:-1;;;;34598:7:105;;;34596:10;34589:17;;34545:438;34709:4;:12;;34717:4;34709:12;34705:278;;34774:2;34756:21;;34762:2;34756:21;;;:29;;34784:1;34756:29;;;34780:1;34756:29;34749:36;;;;;;;;;34705:278;34898:4;:12;;34906:4;34898:12;34894:89;;34950:2;34945:7;;:2;:7;;;:15;;34959:1;34945:15;;34894:89;32280:2721;31539:6876;;32263:3554;35072:6;:13;;35082:3;35072:13;35068:749;;35122:2;35116;:8;;;;35109:15;;;;;;35068:749;35197:6;:14;;35207:4;35197:14;35193:624;;35266:4;:9;;35274:1;35266:9;35262:100;;-1:-1:-1;;;35317:21:105;;;35303:36;;35262:100;35414:4;:12;;35422:4;35414:12;:28;;;;35430:4;:12;;35438:4;35430:12;35414:28;35410:389;;;35474:4;:12;;35482:4;35474:12;35470:83;;35523:3;;;35470:83;35578:8;35616:127;35628:10;35623:15;;:20;35616:127;;35708:8;35675:3;35708:8;;;;;35675:3;35616:127;;;35775:1;-1:-1:-1;35768:8:105;;-1:-1:-1;;35768:8:105;35410:389;31539:6876;;;35850:4;35841:6;:13;;;35837:2578;;;35900:6;:14;;35910:4;35900:14;35896:1208;;35945:42;35963:2;35968:1;35963:6;35973:1;35962:12;35957:2;:17;35949:26;;:3;:26;;;;35979:4;35948:35;35985:1;35945:2;:42::i;:::-;35938:49;;;;;;35896:1208;36054:6;:14;;36064:4;36054:14;36050:1054;;36099:45;36117:2;36122:1;36117:6;36127:1;36116:12;36111:2;:17;36103:26;;:3;:26;;;;36133:6;36102:37;36141:2;36099;:45::i;36050:1054::-;36212:6;:14;;36222:4;36212:14;36208:896;;-1:-1:-1;;;36263:21:105;36282:1;36277;36272:6;;36271:12;36263:21;;36320:36;;;36391:5;36386:10;;36263:21;;;;;36385:18;36378:25;;36208:896;36470:6;:14;;36480:4;36470:14;36466:638;;36515:3;36508:10;;;;;;36466:638;36586:6;:14;;36596:4;36586:14;36582:522;;36646:2;36651:1;36646:6;36656:1;36645:12;36640:2;:17;36632:26;;:3;:26;;;;36662:4;36631:35;36624:42;;;;;;36582:522;36734:6;:14;;36744:4;36734:14;36730:374;;36794:2;36799:1;36794:6;36804:1;36793:12;36788:2;:17;36780:26;;:3;:26;;;;36810:6;36779:37;36772:44;;;;;;36730:374;36884:6;:14;;36894:4;36884:14;36880:224;;-1:-1:-1;;;36935:26:105;36959:1;36954;36949:6;;36948:12;36943:2;:17;36935:26;;36997:41;;;37073:5;37068:10;;36935:26;;;;;37067:18;37060:25;;35837:2578;37158:6;:14;;37168:4;37158:14;37154:1261;;-1:-1:-1;;;37211:4:105;37205:34;37237:1;37232;37227:6;;37226:12;37221:2;:17;37205:34;;37291:27;;;37271:48;;;37345:10;;37206:9;;;37205:34;;37344:18;37337:25;;37154:1261;37417:6;:14;;37427:4;37417:14;37413:1002;;-1:-1:-1;;;37470:6:105;37464:36;37498:1;37493;37488:6;;37487:12;37482:2;:17;37464:36;;37552:29;;;37532:50;;;37608:10;;37465:11;;;37464:36;;37607:18;37600:25;;37413:1002;37681:6;:14;;37691:4;37681:14;37677:738;;-1:-1:-1;;;37728:20:105;37746:1;37741;37736:6;;37735:12;37728:20;;37780:36;;;37848:5;37842:11;;37728:20;;;;;37841:19;37834:26;;37677:738;37915:6;:14;;37925:4;37915:14;37911:504;;37956:2;37949:9;;;;;;37911:504;38014:6;:14;;38024:4;38014:14;38010:405;;-1:-1:-1;;;38061:25:105;38084:1;38079;38074:6;;38073:12;38068:2;:17;38061:25;;38118:41;;;38191:5;38185:11;;38061:25;;;;;38184:19;38177:26;;38010:405;38258:6;:14;;38268:4;38258:14;38254:161;;38299:3;38292:10;;;;;;38254:161;38357:6;:14;;38367:4;38357:14;38353:62;;38398:2;38391:9;;;;;;38353:62;38429:29;;;;;2810:2:257;38429:29:105;;;2792:21:257;2849:2;2829:18;;;2822:30;2888:21;2868:18;;;2861:49;2927:18;;38429:29:105;2608:343:257;19194:782:105;19280:12;19367:18;;:::i;:::-;-1:-1:-1;19435:4:105;19542:2;19530:14;;;;19522:41;;;;;;;3158:2:257;19522:41:105;;;3140:21:257;3197:2;3177:18;;;3170:30;3236:16;3216:18;;;3209:44;3270:18;;19522:41:105;2956:338:257;19522:41:105;19659:14;;;;;;;:30;;;19677:12;19659:30;19655:102;;;19738:4;19709:5;:15;;;19725:9;19709:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;19655:102;19812:12;;;;;19801:23;;;;:8;;;:23;19868:1;19853:16;;;19838:31;;;19946:13;:11;:13::i;4837:7728::-;4880:12;4966:18;;:::i;:::-;-1:-1:-1;5144:15:105;;:18;;;;5034:4;5304:18;;;;5348;;;;5392;;;;;5034:4;;5124:17;;;;5304:18;5348;5482;;;5496:4;5482:18;5478:6777;;5532:2;5561:4;5556:9;;:14;5552:144;;5672:4;5667:9;;5659:4;:18;5653:24;5552:144;5717:2;:7;;5723:1;5717:7;5713:161;;5753:10;;;;;5785:16;;;;;;;;5753:10;-1:-1:-1;5713:161:105;;;5853:2;5848:7;;5713:161;5502:386;5478:6777;;;5990:10;:18;;6004:4;5990:18;5986:6269;;1745:10;6028:14;;5986:6269;;;6126:10;:18;;6140:4;6126:18;6122:6133;;6169:1;6164:6;;6122:6133;;;6294:10;:18;;6308:4;6294:18;6290:5965;;6347:4;6332:12;;;:19;6369:26;;;:14;;;:26;6420:13;:11;:13::i;:::-;6413:20;;;;;;;;;4837:7728;:::o;6290:5965::-;6559:10;:18;;6573:4;6559:18;6555:5700;;6710:14;;;6706:2708;6555:5700;6706:2708;6880:22;;;;;6876:2538;;7005:10;7018:27;7026:2;7031:10;7026:15;7043:1;7018:7;:27::i;:::-;7129:17;;;;7005:40;;-1:-1:-1;7129:17:105;7107:19;7279:14;7298:1;7273:26;7269:131;;7341:36;7365:11;1277:21:106;1426:15;;;1467:8;1461:4;1454:22;1595:4;1582:18;;1602:19;1578:44;1624:11;1575:61;;1222:430;7341:36:105;7327:50;;7269:131;7486:20;;;;;7453:54;;;;;;;;3472:25:257;;;7453:54:105;3533:23:257;;;3513:18;;;3506:51;7422:11:105;;;;7453:19;:6;:19;;;;3445:18:257;;7453:54:105;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7421:86;;;;7734:1;7730:2;7726:10;7831:9;7828:1;7824:17;7913:6;7906:5;7903:17;7900:40;;;7933:5;7923:15;;7900:40;;8016:6;8012:2;8009:14;8006:34;;;8036:2;8026:12;;8006:34;8142:3;8137:1;8129:6;8125:14;8120:3;8116:24;8112:34;8105:41;;8242:3;8238:1;8226:9;8217:6;8214:1;8210:14;8206:30;8202:38;8198:48;8191:55;;8397:1;8393;8389;8377:9;8374:1;8370:17;8366:25;8362:33;8358:41;8524:1;8520;8516;8507:6;8495:9;8492:1;8488:17;8484:30;8480:38;8476:46;8472:54;8454:72;;8655:10;8651:15;8645:4;8641:26;8633:34;;8771:3;8763:4;8759:9;8754:3;8750:19;8747:28;8740:35;;;;8917:33;8926:2;8931:10;8926:15;8943:1;8946:3;8917:8;:33::i;:::-;8972:20;;;:38;;;;;;;;;-1:-1:-1;6876:2538:105;;-1:-1:-1;;;6876:2538:105;;9129:18;;;;;9125:289;;9299:2;9294:7;;6555:5700;;9125:289;9353:10;9348:15;;2053:3;9385:10;;9125:289;6555:5700;;;9543:10;:18;;9557:4;9543:18;9539:2716;;9697:15;;;1824:1;9697:15;;:34;;-1:-1:-1;9716:15:105;;;1859:1;9716:15;9697:34;:57;;;-1:-1:-1;9735:19:105;;;1936:1;9735:19;9697:57;9693:1593;;;9783:2;9778:7;;9539:2716;;9693:1593;9909:23;;;;;9905:1381;;9956:10;9969:27;9977:2;9982:10;9977:15;9994:1;9969:7;:27::i;:::-;10072:17;;;;9956:40;;-1:-1:-1;10315:1:105;10307:10;;10409:1;10405:17;10484:13;;;10481:32;;;10506:5;10500:11;;10481:32;10792:14;;;10598:1;10788:22;;;10784:32;;;;10681:26;10705:1;10590:10;;;10685:18;;;10681:26;10780:43;10586:20;;10888:12;11016:17;;;:23;11084:1;11061:20;;;:24;10594:2;-1:-1:-1;10594:2:105;6555:5700;;9539:2716;11488:10;:18;;11502:4;11488:18;11484:771;;11598:2;:7;;11604:1;11598:7;11594:647;;11691:14;;;;;:40;;-1:-1:-1;11709:22:105;;;1978:1;11709:22;11691:40;:62;;;-1:-1:-1;11735:18:105;;;1897:1;11735:18;11691:62;11687:404;;;11786:1;11781:6;;11594:647;;11687:404;11832:15;;;1824:1;11832:15;;:34;;-1:-1:-1;11851:15:105;;;1859:1;11851:15;11832:34;:61;;;-1:-1:-1;11870:23:105;;;2021:1;11870:23;11832:61;:84;;;-1:-1:-1;11897:19:105;;;1936:1;11897:19;11832:84;11828:263;;;11949:1;11944:6;;6555:5700;;11594:647;12142:10;12137:15;;2087:4;12174:11;;11594:647;12330:15;;;;;:23;;;;:18;;;;:23;;;;12367:15;;:23;;;:18;;;;:23;-1:-1:-1;12456:12:105;;;;12445:23;;;:8;;;:23;12512:1;12497:16;12482:31;;;;;12535:13;:11;:13::i;15318:2480::-;15412:12;15498:18;;:::i;:::-;-1:-1:-1;15566:4:105;15598:10;15706:13;;;15715:4;15706:13;15702:1705;;-1:-1:-1;15745:8:105;;;;15702:1705;;;15864:5;:13;;15873:4;15864:13;15860:1547;;15897:14;;;:8;;;:14;15860:1547;;;16027:5;:13;;16036:4;16027:13;16023:1384;;-1:-1:-1;16066:8:105;;;;16023:1384;;;16185:5;:13;;16194:4;16185:13;16181:1226;;16218:14;;;:8;;;:14;16181:1226;;;16359:5;:13;;16368:4;16359:13;16355:1052;;16486:9;16432:17;16412;;;16432;;;;16412:37;16493:2;16486:9;;;;;16468:8;;;:28;16514:22;:8;;;:22;16355:1052;;;16673:5;:13;;16682:4;16673:13;16669:738;;16740:11;16726;;;16740;;;16726:25;16795:2;16788:9;;;;;16770:8;;;:28;16816:22;:8;;;:22;16669:738;;;16997:5;:13;;17006:4;16997:13;16993:414;;17067:3;17048:23;;17054:3;17048:23;;;;;;;:::i;:::-;;17030:42;;:8;;;:42;17108:23;;;;;;;;;;;;;:::i;:::-;;17090:42;;:8;;;:42;16993:414;;;17301:5;:13;;17310:4;17301:13;17297:110;;17351:3;17345:9;;:3;:9;;;;;;;:::i;:::-;;17334:20;;;;:8;;;:20;17383:9;;;;;;;;;;;:::i;:::-;;17372:20;;:8;;;:20;17297:110;17500:14;;;;17496:85;;17563:3;17534:5;:15;;;17550:9;17534:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;17496:85;17635:12;;;;;17624:23;;;;:8;;;:23;17691:1;17676:16;;;17661:31;;;17768:13;:11;:13::i;:::-;17761:20;15318:2480;-1:-1:-1;;;;;;;15318:2480:105:o;23147:1654::-;23323:14;23340:24;23352:11;23340;:24::i;:::-;23323:41;;23472:1;23465:5;23461:13;23458:33;;;23487:1;23484;23477:12;23458:33;23626:2;23820:15;;;23645:2;23634:14;;23622:10;23618:31;23615:1;23611:39;23776:16;;;23561:20;;23761:10;23750:22;;;23746:27;23736:38;23733:60;24262:5;24259:1;24255:13;24333:1;24318:343;24343:2;24340:1;24337:9;24318:343;;;24466:2;24454:15;;;24403:20;24501:12;;;24515:1;24497:20;24538:42;;;;24606:1;24601:42;;;;24490:153;;24538:42;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;24547:31;;24538:42;;24601;21625:1;21618:12;;;21658:2;21651:13;;;21703:2;21690:16;;24610:31;;24490:153;-1:-1:-1;;24361:1:105;24354:9;24318:343;;;-1:-1:-1;;24760:4:105;24753:18;-1:-1:-1;;;;23147:1654:105:o;20180:586::-;20502:20;;;20526:7;20502:32;20495:3;:40;;;20608:14;;20663:17;;20657:24;;;20649:72;;;;;;;4209:2:257;20649:72:105;;;4191:21:257;4248:2;4228:18;;;4221:30;4287:34;4267:18;;;4260:62;4358:5;4338:18;;;4331:33;4381:19;;20649:72:105;4007:399:257;20649:72:105;20735:14;20180:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:257:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:257;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:717::-;909:6;917;925;933;986:2;974:9;965:7;961:23;957:32;954:52;;;1002:1;999;992:12;954:52;1042:9;1029:23;1071:18;1112:2;1104:6;1101:14;1098:34;;;1128:1;1125;1118:12;1098:34;1167:58;1217:7;1208:6;1197:9;1193:22;1167:58;:::i;:::-;1244:8;;-1:-1:-1;1141:84:257;-1:-1:-1;1332:2:257;1317:18;;1304:32;;-1:-1:-1;1348:16:257;;;1345:36;;;1377:1;1374;1367:12;1345:36;;1416:60;1468:7;1457:8;1446:9;1442:24;1416:60;:::i;:::-;819:717;;;;-1:-1:-1;1495:8:257;-1:-1:-1;;;;819:717:257:o;1723:184::-;1775:77;1772:1;1765:88;1872:4;1869:1;1862:15;1896:4;1893:1;1886:15;3568:245;3647:6;3655;3708:2;3696:9;3687:7;3683:23;3679:32;3676:52;;;3724:1;3721;3714:12;3676:52;-1:-1:-1;;3747:16:257;;3803:2;3788:18;;;3782:25;3747:16;;3782:25;;-1:-1:-1;3568:245:257:o;3818:184::-;3870:77;3867:1;3860:88;3967:4;3964:1;3957:15;3991:4;3988:1;3981:15"
var MIPSDeployedSourceMap = "1131:38919:105:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1710:45;;1745:10;1710:45;;;;;188:10:257;176:23;;;158:42;;146:2;131:18;1710:45:105;;;;;;;;2448:99;;;412:42:257;2534:6:105;400:55:257;382:74;;370:2;355:18;2448:99:105;211:251:257;24930:6339:105;;;;;;:::i;:::-;;:::i;:::-;;;1687:25:257;;;1675:2;1660:18;24930:6339:105;1541:177:257;24930:6339:105;25008:7;25051:18;;:::i;:::-;25198:4;25191:5;25188:15;25178:134;;25292:1;25289;25282:12;25178:134;25348:4;25342:11;25355;25339:28;25329:137;;25446:1;25443;25436:12;25329:137;25514:3;25496:16;25493:25;25483:150;;25613:1;25610;25603:12;25483:150;25677:3;25663:12;25660:21;25650:145;;25775:1;25772;25765:12;25650:145;26055:24;;26399:4;26101:20;26457:2;26159:21;;26055:24;26217:18;26101:20;26159:21;;;26055:24;26032:21;26028:52;;;26217:18;26101:20;;;26159:21;;;26055:24;26028:52;;26101:20;;26159:21;;;26055:24;26028:52;;26217:18;26101:20;26159:21;;;26055:24;26028:52;;26217:18;26101:20;26159:21;;;26055:24;26028:52;;26217:18;26101:20;26159:21;;;26055:24;26028:52;;;26217:18;26101:20;26159:21;;;26055:24;26032:21;26028:52;;;26217:18;26101:20;26159:21;;;26055:24;26028:52;;26217:18;26101:20;26159:21;;;26055:24;26028:52;;26217:18;26101:20;27075:10;26217:18;27065:21;;;26159;;;;27173:1;27158:77;27183:2;27180:1;27177:9;27158:77;;;26055:24;;26032:21;26028:52;26101:20;;27231:1;26159:21;;;;26043:2;26217:18;;;;27201:1;27194:9;27158:77;;;27162:14;;;27313:5;:12;;;27309:71;;;27352:13;:11;:13::i;:::-;27345:20;;;;;27309:71;27394:10;;;:15;;27408:1;27394:15;;;;;27479:8;;;;-1:-1:-1;;27471:20:105;;-1:-1:-1;27471:7:105;:20::i;:::-;27457:34;-1:-1:-1;27521:10:105;27529:2;27521:10;;;;27598:1;27588:11;;;:26;;;27603:6;:11;;27613:1;27603:11;27588:26;27584:310;;;27744:13;27813:1;27791:4;27798:10;27791:17;27790:24;;;;27761:5;:12;;;27776:10;27761:25;27760:54;27744:70;;27839:40;27850:6;:11;;27860:1;27850:11;:20;;27868:2;27850:20;;;27864:1;27850:20;27839:40;;27872:6;27839:10;:40::i;:::-;27832:47;;;;;;;;27584:310;28143:15;;;;27938:9;;;;28075:4;28069:2;28061:10;;;28060:19;;;28143:15;28168:2;28160:10;;;28159:19;28143:36;;;;;;;:::i;:::-;;;;;;-1:-1:-1;28208:5:105;28232:11;;;;;:29;;;28247:6;:14;;28257:4;28247:14;28232:29;28228:832;;;28324:5;:15;;;28340:5;28324:22;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;28387:4:105;28381:2;28373:10;;;28372:19;28228:832;;;28425:4;28416:6;:13;;;28412:648;;;28546:6;:13;;28556:3;28546:13;:30;;;;28563:6;:13;;28573:3;28563:13;28546:30;:47;;;;28580:6;:13;;28590:3;28580:13;28546:47;28542:253;;;28656:4;28663:6;28656:13;28651:18;;28412:648;;28542:253;28755:21;28758:4;28765:6;28758:13;28773:2;28755;:21::i;:::-;28750:26;;28412:648;;;28829:4;28819:6;:14;;;;:32;;;;28837:6;:14;;28847:4;28837:14;28819:32;:50;;;;28855:6;:14;;28865:4;28855:14;28819:50;28815:245;;;28939:5;:15;;;28955:5;28939:22;;;;;;;;;:::i;:::-;;;;;28934:27;;29040:5;29032:13;;28815:245;29089:1;29079:6;:11;;;;:25;;;;;29103:1;29094:6;:10;;;29079:25;29078:42;;;;29109:6;:11;;29119:1;29109:11;29078:42;29074:125;;;29147:37;29160:6;29168:4;29174:5;29181:2;29147:12;:37::i;:::-;29140:44;;;;;;;;;;;29074:125;29232:13;29213:16;29384:4;29374:14;;;;29370:446;;29453:21;29456:4;29463:6;29456:13;29471:2;29453;:21::i;:::-;29447:27;;;;29511:10;29506:15;;29545:16;29506:15;29559:1;29545:7;:16::i;:::-;29539:22;;29593:4;29583:6;:14;;;;:32;;;;;29601:6;:14;;29611:4;29601:14;;29583:32;29579:223;;;29680:4;29668:16;;29782:1;29774:9;;29579:223;29390:426;29370:446;29849:10;29862:26;29870:4;29876:2;29880;29884:3;29862:7;:26::i;:::-;29891:10;29862:39;;;;-1:-1:-1;29987:4:105;29980:11;;;30019;;;:24;;;;;30042:1;30034:4;:9;;;;30019:24;:39;;;;;30054:4;30047;:11;;;30019:39;30015:847;;;30082:4;:9;;30090:1;30082:9;:22;;;;30095:4;:9;;30103:1;30095:9;30082:22;30078:144;;;30166:37;30177:4;:9;;30185:1;30177:9;:21;;30193:5;30177:21;;;30189:1;30177:21;30200:2;30166:10;:37::i;:::-;30159:44;;;;;;;;;;;;;;;30078:144;30244:4;:11;;30252:3;30244:11;30240:121;;30314:28;30323:5;30330:2;30334:7;;;;30314:8;:28::i;30240:121::-;30382:4;:11;;30390:3;30382:11;30378:121;;30452:28;30461:5;30468:2;30472:7;;;;;30452:8;:28::i;30378:121::-;30569:4;:11;;30577:3;30569:11;30565:80;;30611:15;:13;:15::i;30565:80::-;30748:4;30740;:12;;;;:27;;;;;30763:4;30756;:11;;;30740:27;30736:112;;;30798:31;30809:4;30815:2;30819;30823:5;30798:10;:31::i;30736:112::-;30922:6;:14;;30932:4;30922:14;:28;;;;-1:-1:-1;30940:10:105;;;;;30922:28;30918:93;;;30995:1;30970:5;:15;;;30986:5;30970:22;;;;;;;;;:::i;:::-;:26;;;;:22;;;;;;:26;30918:93;31057:9;:26;;31070:13;31057:26;31053:92;;31103:27;31112:9;31123:1;31126:3;31103:8;:27::i;:::-;31226:26;31235:5;31242:3;31247:4;31226:8;:26::i;:::-;31219:33;;;;;;;;;;;;;24930:6339;;;;;;;:::o;3092:1709::-;3639:4;3633:11;;3555:4;3358:31;3347:43;;3418:13;3358:31;3757:2;3457:13;;3347:43;3364:24;3358:31;3457:13;;;3347:43;;;;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3364:24;3358:31;3457:13;;;3347:43;3133:12;;4342:13;;3457;;;3133:12;4422:84;4447:2;4444:1;4441:9;4422:84;;;3374:13;3364:24;;3358:31;3347:43;;3378:2;3418:13;;;;4502:1;3457:13;;;;4465:1;4458:9;4422:84;;;4426:14;4569:1;4565:2;4558:13;4664:5;4660:2;4656:14;4649:5;4644:27;4770:14;;;4753:32;;;3092:1709;-1:-1:-1;;3092:1709:105:o;20985:1831::-;21058:11;21169:14;21186:24;21198:11;21186;:24::i;:::-;21169:41;;21318:1;21311:5;21307:13;21304:33;;;21333:1;21330;21323:12;21304:33;21466:2;21454:15;;;21407:20;21896:5;21893:1;21889:13;21931:4;21967:1;21952:343;21977:2;21974:1;21971:9;21952:343;;;22100:2;22088:15;;;22037:20;22135:12;;;22149:1;22131:20;22172:42;;;;22240:1;22235:42;;;;22124:153;;22172:42;21630:1;21623:12;;;21663:2;21656:13;;;21708:2;21695:16;;22181:31;;22172:42;;22235;21630:1;21623:12;;;21663:2;21656:13;;;21708:2;21695:16;;22244:31;;22124:153;-1:-1:-1;;21995:1:105;21988:9;21952:343;;;21956:14;22405:4;22399:11;22384:26;;22491:7;22485:4;22482:17;22472:124;;22533:10;22530:1;22523:21;22575:2;22572:1;22565:13;22472:124;-1:-1:-1;;22723:2:105;22712:14;;;;22700:10;22696:31;22693:1;22689:39;22757:16;;;;22775:10;22753:33;;20985:1831;-1:-1:-1;;;20985:1831:105:o;18095:823::-;18164:12;18251:18;;:::i;:::-;18319:4;18310:13;;18371:5;:8;;;18382:1;18371:12;18355:28;;:5;:12;;;:28;;;18351:95;;18403:28;;;;;2114:2:257;18403:28:105;;;2096:21:257;2153:2;2133:18;;;2126:30;2192:20;2172:18;;;2165:48;2230:18;;18403:28:105;;;;;;;;18351:95;18535:8;;;;;18568:12;;;;;18557:23;;;;;;;18594:20;;;;;18535:8;18726:13;;;18722:90;;18787:6;18796:1;18787:10;18759:5;:15;;;18775:8;18759:25;;;;;;;;;:::i;:::-;:38;;;;:25;;;;;;:38;18722:90;18888:13;:11;:13::i;:::-;18881:20;18095:823;-1:-1:-1;;;;;18095:823:105:o;2645:339::-;2706:11;2770:18;;;;2779:8;;;;2770:18;;;;;;2769:25;;;;;2786:1;2833:2;:9;;;2827:16;;;;;2826:22;;2825:32;;;;;;;2887:9;;2886:15;2769:25;2944:21;;2964:1;2944:21;;;2955:6;2944:21;2929:11;;;;;:37;;-1:-1:-1;;;2645:339:105;;;;:::o;12956:2026::-;13053:12;13139:18;;:::i;:::-;13207:4;13198:13;;13239:17;13299:5;:8;;;13310:1;13299:12;13283:28;;:5;:12;;;:28;;;13279:97;;13331:30;;;;;2461:2:257;13331:30:105;;;2443:21:257;2500:2;2480:18;;;2473:30;2539:22;2519:18;;;2512:50;2579:18;;13331:30:105;2259:344:257;13279:97:105;13446:7;:12;;13457:1;13446:12;:28;;;;13462:7;:12;;13473:1;13462:12;13446:28;13442:947;;;13494:9;13506:5;:15;;;13522:6;13506:23;;;;;;;;;:::i;:::-;;;;;13494:35;;13570:2;13563:9;;:3;:9;;;:25;;;;;13576:7;:12;;13587:1;13576:12;13563:25;13562:58;;;;13601:2;13594:9;;:3;:9;;;;:25;;;;;13607:7;:12;;13618:1;13607:12;13594:25;13547:73;;13476:159;13442:947;;;13732:7;:12;;13743:1;13732:12;13728:661;;13793:1;13785:3;13779:15;;;;13764:30;;13728:661;;;13897:7;:12;;13908:1;13897:12;13893:496;;13957:1;13950:3;13944:14;;;13929:29;;13893:496;;;14078:7;:12;;14089:1;14078:12;14074:315;;14166:4;14160:2;14151:11;;;14150:20;14136:10;14193:8;;;14189:84;;14253:1;14246:3;14240:14;;;14225:29;;14189:84;14294:3;:8;;14301:1;14294:8;14290:85;;14355:1;14347:3;14341:15;;;;14326:30;;14290:85;14092:297;14074:315;14465:8;;;;;14543:12;;;;14532:23;;;;;14699:178;;;;14790:1;14764:22;14767:5;14775:6;14767:14;14783:2;14764;:22::i;:::-;:27;;;;;;;14750:42;;14759:1;14750:42;14735:57;:12;;;:57;14699:178;;;14846:12;;;;;14861:1;14846:16;14831:31;;;;14699:178;14952:13;:11;:13::i;:::-;14945:20;12956:2026;-1:-1:-1;;;;;;;;12956:2026:105:o;31315:8733::-;31402:10;31464;31472:2;31464:10;;;;31503:11;;;:44;;;31529:1;31519:6;:11;;;;:27;;;;;31543:3;31534:6;:12;;;31519:27;31499:8490;;;31588:4;31581:11;;31712:6;31772:3;31767:25;;;;31847:3;31842:25;;;;31921:3;31916:25;;;;31996:3;31991:25;;;;32070:3;32065:25;;;;32143:3;32138:25;;;;32217:3;32212:25;;;;31705:532;;31767:25;31786:4;31778:12;;31767:25;;31842;31861:4;31853:12;;31842:25;;31916;31935:4;31927:12;;31916:25;;31991;32010:4;32002:12;;31991:25;;32065;32084:4;32076:12;;32065:25;;32138;32157:4;32149:12;;32138:25;;32212;32231:4;32223:12;;31705:532;;32300:4;:12;;32308:4;32300:12;32296:4023;;-1:-1:-1;;;32351:9:105;32343:26;;32364:4;32359:1;32351:9;;;32350:18;32343:26;32336:33;;32296:4023;32437:4;:12;;32445:4;32437:12;32433:3886;;-1:-1:-1;;;32488:9:105;32480:26;;32501:4;32496:1;32488:9;;;32487:18;32480:26;32473:33;;32433:3886;32574:4;:12;;32582:4;32574:12;32570:3749;;32639:4;32634:1;32626:9;;;32625:18;32672:27;32626:9;32675:11;;;;32688:2;:10;;;32672:2;:27::i;:::-;32665:34;;;;;;;32570:3749;32768:4;:12;;32776:4;32768:12;32764:3555;;-1:-1:-1;;;32811:17:105;;;32823:4;32818:9;;32811:17;32804:24;;32764:3555;32897:4;:11;;32905:3;32897:11;32893:3426;;-1:-1:-1;;;32939:17:105;;;32951:4;32946:9;;32939:17;32932:24;;32893:3426;33025:4;:12;;33033:4;33025:12;33021:3298;;33068:21;33077:2;33071:8;;:2;:8;;;;33086:2;33081;:7;33068:2;:21::i;:::-;33061:28;;;;;;33021:3298;33338:4;:12;;33346:4;33338:12;33334:2985;;33381:2;33374:9;;;;;;33334:2985;33452:4;:12;;33460:4;33452:12;33448:2871;;33495:2;33488:9;;;;;;33448:2871;33566:4;:12;;33574:4;33566:12;33562:2757;;33609:2;33602:9;;;;;;33562:2757;33680:4;:12;;33688:4;33680:12;33676:2643;;33723:2;33716:9;;;;;;33676:2643;33797:4;:12;;33805:4;33797:12;33793:2526;;33840:2;33833:9;;;;;;33793:2526;33957:4;:12;;33965:4;33957:12;33953:2366;;34000:2;33993:9;;;;;;33953:2366;34071:4;:12;;34079:4;34071:12;34067:2252;;34114:2;34107:9;;;;;;34067:2252;34185:4;:12;;34193:4;34185:12;34181:2138;;34228:2;34221:9;;;;;;34181:2138;34299:4;:12;;34307:4;34299:12;34295:2024;;34342:2;34335:9;;;;;;34295:2024;34413:4;:12;;34421:4;34413:12;34409:1910;;34456:2;34449:9;;;;;;34409:1910;34527:4;:12;;34535:4;34527:12;34523:1796;;34570:2;34563:9;;;;;;34523:1796;34642:4;:12;;34650:4;34642:12;34638:1681;;34685:2;34678:9;;;;;;34638:1681;34755:4;:12;;34763:4;34755:12;34751:1568;;34798:2;34791:9;;;;;;34751:1568;34869:4;:12;;34877:4;34869:12;34865:1454;;34912:2;34905:9;;;;;;34865:1454;35061:4;:12;;35069:4;35061:12;35057:1262;;-1:-1:-1;;;35105:7:105;;;35097:16;;35057:1262;35182:4;:12;;35190:4;35182:12;35178:1141;;-1:-1:-1;;;35226:7:105;;;35218:16;;35178:1141;35302:4;:12;;35310:4;35302:12;35298:1021;;-1:-1:-1;;;35346:7:105;;;35338:16;;35298:1021;35423:4;:12;;35431:4;35423:12;35419:900;;-1:-1:-1;;;35467:7:105;;;35459:16;;35419:900;35543:4;:12;;35551:4;35543:12;35539:780;;-1:-1:-1;;;35587:7:105;;;35579:16;;35539:780;35662:4;:12;;35670:4;35662:12;35658:661;;-1:-1:-1;;;35706:7:105;;;35698:16;;35658:661;35782:4;:12;;35790:4;35782:12;35778:541;;-1:-1:-1;;;35826:7:105;;;35818:16;;35778:541;35902:4;:12;;35910:4;35902:12;35898:421;;-1:-1:-1;;;35947:7:105;;;35945:10;35938:17;;35898:421;36024:4;:12;;36032:4;36024:12;36020:299;;36085:2;36067:21;;36073:2;36067:21;;;:29;;36095:1;36067:29;;;36091:1;36067:29;36060:36;;;;;;;;36020:299;36166:4;:12;;36174:4;36166:12;36162:157;;36214:2;36209:7;;:2;:7;;;:15;;36223:1;36209:15;;36162:157;36271:29;;;;;2810:2:257;36271:29:105;;;2792:21:257;2849:2;2829:18;;;2822:30;2888:21;2868:18;;;2861:49;2927:18;;36271:29:105;2608:343:257;36162:157:105;31549:4784;31499:8490;;;36389:6;:14;;36399:4;36389:14;36385:3590;;36448:4;36441:11;;36523:3;36515:11;;;36511:549;;-1:-1:-1;;;36568:21:105;;;36554:36;;36511:549;36675:4;:12;;36683:4;36675:12;:28;;;;36691:4;:12;;36699:4;36691:12;36675:28;36671:389;;;36735:4;:12;;36743:4;36735:12;36731:83;;36784:3;;;36731:83;36839:8;36877:127;36889:10;36884:15;;:20;36877:127;;36969:8;36936:3;36969:8;;;;;36936:3;36877:127;;;37036:1;-1:-1:-1;37029:8:105;;-1:-1:-1;;37029:8:105;36385:3590;37127:6;:14;;37137:4;37127:14;37123:2852;;-1:-1:-1;;37172:8:105;37178:2;37172:8;;;;37165:15;;37123:2852;37247:6;:14;;37257:4;37247:14;37243:2732;;37292:42;37310:2;37315:1;37310:6;37320:1;37309:12;37304:2;:17;37296:26;;:3;:26;;;;37326:4;37295:35;37332:1;37292:2;:42::i;37243:2732::-;37401:6;:14;;37411:4;37401:14;37397:2578;;37446:45;37464:2;37469:1;37464:6;37474:1;37463:12;37458:2;:17;37450:26;;:3;:26;;;;37480:6;37449:37;37488:2;37446;:45::i;37397:2578::-;37559:6;:14;;37569:4;37559:14;37555:2420;;-1:-1:-1;;37610:21:105;37629:1;37624;37619:6;;37618:12;37610:21;;37667:36;;;37738:5;37733:10;;37610:21;;;;;37732:18;37725:25;;37555:2420;37817:6;:14;;37827:4;37817:14;37813:2162;;37862:3;37855:10;;;;;37813:2162;37933:6;:14;;37943:4;37933:14;37929:2046;;37993:2;37998:1;37993:6;38003:1;37992:12;37987:2;:17;37979:26;;:3;:26;;;;38009:4;37978:35;37971:42;;;;;37929:2046;38082:6;:14;;38092:4;38082:14;38078:1897;;38142:2;38147:1;38142:6;38152:1;38141:12;38136:2;:17;38128:26;;:3;:26;;;;38158:6;38127:37;38120:44;;;;;38078:1897;38233:6;:14;;38243:4;38233:14;38229:1746;;-1:-1:-1;;38284:26:105;38308:1;38303;38298:6;;38297:12;38292:2;:17;38284:26;;38346:41;;;38422:5;38417:10;;38284:26;;;;;38416:18;38409:25;;38229:1746;38502:6;:14;;38512:4;38502:14;38498:1477;;-1:-1:-1;;38559:4:105;38553:34;38585:1;38580;38575:6;;38574:12;38569:2;:17;38553:34;;38643:27;;;38623:48;;;38701:10;;38554:9;;;38553:34;;38700:18;38693:25;;38498:1477;38786:6;:14;;38796:4;38786:14;38782:1193;;-1:-1:-1;;38843:6:105;38837:36;38871:1;38866;38861:6;;38860:12;38855:2;:17;38837:36;;38929:29;;;38909:50;;;38989:10;;38838:11;;;38837:36;;38988:18;38981:25;;38782:1193;39075:6;:14;;39085:4;39075:14;39071:904;;-1:-1:-1;;39126:20:105;39144:1;39139;39134:6;;39133:12;39126:20;;39182:36;;;39254:5;39248:11;;39126:20;;;;;39247:19;39240:26;;39071:904;39334:6;:14;;39344:4;39334:14;39330:645;;39379:2;39372:9;;;;;39330:645;39450:6;:14;;39460:4;39450:14;39446:529;;-1:-1:-1;;39501:25:105;39524:1;39519;39514:6;;39513:12;39508:2;:17;39501:25;;39562:41;;;39639:5;39633:11;;39501:25;;;;;39632:19;39625:26;;39446:529;39718:6;:14;;39728:4;39718:14;39714:261;;39763:3;39756:10;;;;;39714:261;39833:6;:14;;39843:4;39833:14;39829:146;;39878:2;39871:9;;;;;19199:782;19285:12;19372:18;;:::i;:::-;-1:-1:-1;19440:4:105;19547:2;19535:14;;;;19527:41;;;;;;;3158:2:257;19527:41:105;;;3140:21:257;3197:2;3177:18;;;3170:30;3236:16;3216:18;;;3209:44;3270:18;;19527:41:105;2956:338:257;19527:41:105;19664:14;;;;;;;:30;;;19682:12;19664:30;19660:102;;;19743:4;19714:5;:15;;;19730:9;19714:26;;;;;;;;;:::i;:::-;:33;;;;:26;;;;;;:33;19660:102;19817:12;;;;;19806:23;;;;:8;;;:23;19873:1;19858:16;;;19843:31;;;19951:13;:11;:13::i;4842:7728::-;4885:12;4971:18;;:::i;:::-;-1:-1:-1;5149:15:105;;:18;;;;5039:4;5309:18;;;;5353;;;;5397;;;;;5039:4;;5129:17;;;;5309:18;5353;5487;;;5501:4;5487:18;5483:6777;;5537:2;5566:4;5561:9;;:14;5557:144;;5677:4;5672:9;;5664:4;:18;5658:24;5557:144;5722:2;:7;;5728:1;5722:7;5718:161;;5758:10;;;;;5790:16;;;;;;;;5758:10;-1:-1:-1;5718:161:105;;;5858:2;5853:7;;5718:161;5507:386;5483:6777;;;5995:10;:18;;6009:4;5995:18;5991:6269;;1745:10;6033:14;;5991:6269;;;6131:10;:18;;6145:4;6131:18;6127:6133;;6174:1;6169:6;;6127:6133;;;6299:10;:18;;6313:4;6299:18;6295:5965;;6352:4;6337:12;;;:19;6374:26;;;:14;;;:26;6425:13;:11;:13::i;:::-;6418:20;;;;;;;;;4842:7728;:::o;6295:5965::-;6564:10;:18;;6578:4;6564:18;6560:5700;;6715:14;;;6711:2708;6560:5700;6711:2708;6885:22;;;;;6881:2538;;7010:10;7023:27;7031:2;7036:10;7031:15;7048:1;7023:7;:27::i;:::-;7134:17;;;;7010:40;;-1:-1:-1;7134:17:105;7112:19;7284:14;7303:1;7278:26;7274:131;;7346:36;7370:11;1277:21:106;1426:15;;;1467:8;1461:4;1454:22;1595:4;1582:18;;1602:19;1578:44;1624:11;1575:61;;1222:430;7346:36:105;7332:50;;7274:131;7491:20;;;;;7458:54;;;;;;;;3472:25:257;;;7458:54:105;3533:23:257;;;3513:18;;;3506:51;7427:11:105;;;;7458:19;:6;:19;;;;3445:18:257;;7458:54:105;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7426:86;;;;7739:1;7735:2;7731:10;7836:9;7833:1;7829:17;7918:6;7911:5;7908:17;7905:40;;;7938:5;7928:15;;7905:40;;8021:6;8017:2;8014:14;8011:34;;;8041:2;8031:12;;8011:34;8147:3;8142:1;8134:6;8130:14;8125:3;8121:24;8117:34;8110:41;;8247:3;8243:1;8231:9;8222:6;8219:1;8215:14;8211:30;8207:38;8203:48;8196:55;;8402:1;8398;8394;8382:9;8379:1;8375:17;8371:25;8367:33;8363:41;8529:1;8525;8521;8512:6;8500:9;8497:1;8493:17;8489:30;8485:38;8481:46;8477:54;8459:72;;8660:10;8656:15;8650:4;8646:26;8638:34;;8776:3;8768:4;8764:9;8759:3;8755:19;8752:28;8745:35;;;;8922:33;8931:2;8936:10;8931:15;8948:1;8951:3;8922:8;:33::i;:::-;8977:20;;;:38;;;;;;;;;-1:-1:-1;6881:2538:105;;-1:-1:-1;;;6881:2538:105;;9134:18;;;;;9130:289;;9304:2;9299:7;;6560:5700;;9130:289;9358:10;9353:15;;2053:3;9390:10;;9130:289;6560:5700;;;9548:10;:18;;9562:4;9548:18;9544:2716;;9702:15;;;1824:1;9702:15;;:34;;-1:-1:-1;9721:15:105;;;1859:1;9721:15;9702:34;:57;;;-1:-1:-1;9740:19:105;;;1936:1;9740:19;9702:57;9698:1593;;;9788:2;9783:7;;9544:2716;;9698:1593;9914:23;;;;;9910:1381;;9961:10;9974:27;9982:2;9987:10;9982:15;9999:1;9974:7;:27::i;:::-;10077:17;;;;9961:40;;-1:-1:-1;10320:1:105;10312:10;;10414:1;10410:17;10489:13;;;10486:32;;;10511:5;10505:11;;10486:32;10797:14;;;10603:1;10793:22;;;10789:32;;;;10686:26;10710:1;10595:10;;;10690:18;;;10686:26;10785:43;10591:20;;10893:12;11021:17;;;:23;11089:1;11066:20;;;:24;10599:2;-1:-1:-1;10599:2:105;6560:5700;;9544:2716;11493:10;:18;;11507:4;11493:18;11489:771;;11603:2;:7;;11609:1;11603:7;11599:647;;11696:14;;;;;:40;;-1:-1:-1;11714:22:105;;;1978:1;11714:22;11696:40;:62;;;-1:-1:-1;11740:18:105;;;1897:1;11740:18;11696:62;11692:404;;;11791:1;11786:6;;11599:647;;11692:404;11837:15;;;1824:1;11837:15;;:34;;-1:-1:-1;11856:15:105;;;1859:1;11856:15;11837:34;:61;;;-1:-1:-1;11875:23:105;;;2021:1;11875:23;11837:61;:84;;;-1:-1:-1;11902:19:105;;;1936:1;11902:19;11837:84;11833:263;;;11954:1;11949:6;;6560:5700;;11599:647;12147:10;12142:15;;2087:4;12179:11;;11599:647;12335:15;;;;;:23;;;;:18;;;;:23;;;;12372:15;;:23;;;:18;;;;:23;-1:-1:-1;12461:12:105;;;;12450:23;;;:8;;;:23;12517:1;12502:16;12487:31;;;;;12540:13;:11;:13::i;15323:2480::-;15417:12;15503:18;;:::i;:::-;-1:-1:-1;15571:4:105;15603:10;15711:13;;;15720:4;15711:13;15707:1705;;-1:-1:-1;15750:8:105;;;;15707:1705;;;15869:5;:13;;15878:4;15869:13;15865:1547;;15902:14;;;:8;;;:14;15865:1547;;;16032:5;:13;;16041:4;16032:13;16028:1384;;-1:-1:-1;16071:8:105;;;;16028:1384;;;16190:5;:13;;16199:4;16190:13;16186:1226;;16223:14;;;:8;;;:14;16186:1226;;;16364:5;:13;;16373:4;16364:13;16360:1052;;16491:9;16437:17;16417;;;16437;;;;16417:37;16498:2;16491:9;;;;;16473:8;;;:28;16519:22;:8;;;:22;16360:1052;;;16678:5;:13;;16687:4;16678:13;16674:738;;16745:11;16731;;;16745;;;16731:25;16800:2;16793:9;;;;;16775:8;;;:28;16821:22;:8;;;:22;16674:738;;;17002:5;:13;;17011:4;17002:13;16998:414;;17072:3;17053:23;;17059:3;17053:23;;;;;;;:::i;:::-;;17035:42;;:8;;;:42;17113:23;;;;;;;;;;;;;:::i;:::-;;17095:42;;:8;;;:42;16998:414;;;17306:5;:13;;17315:4;17306:13;17302:110;;17356:3;17350:9;;:3;:9;;;;;;;:::i;:::-;;17339:20;;;;:8;;;:20;17388:9;;;;;;;;;;;:::i;:::-;;17377:20;;:8;;;:20;17302:110;17505:14;;;;17501:85;;17568:3;17539:5;:15;;;17555:9;17539:26;;;;;;;;;:::i;:::-;:32;;;;:26;;;;;;:32;17501:85;17640:12;;;;;17629:23;;;;:8;;;:23;17696:1;17681:16;;;17666:31;;;17773:13;:11;:13::i;:::-;17766:20;15323:2480;-1:-1:-1;;;;;;;15323:2480:105:o;23152:1654::-;23328:14;23345:24;23357:11;23345;:24::i;:::-;23328:41;;23477:1;23470:5;23466:13;23463:33;;;23492:1;23489;23482:12;23463:33;23631:2;23825:15;;;23650:2;23639:14;;23627:10;23623:31;23620:1;23616:39;23781:16;;;23566:20;;23766:10;23755:22;;;23751:27;23741:38;23738:60;24267:5;24264:1;24260:13;24338:1;24323:343;24348:2;24345:1;24342:9;24323:343;;;24471:2;24459:15;;;24408:20;24506:12;;;24520:1;24502:20;24543:42;;;;24611:1;24606:42;;;;24495:153;;24543:42;21630:1;21623:12;;;21663:2;21656:13;;;21708:2;21695:16;;24552:31;;24543:42;;24606;21630:1;21623:12;;;21663:2;21656:13;;;21708:2;21695:16;;24615:31;;24495:153;-1:-1:-1;;24366:1:105;24359:9;24323:343;;;-1:-1:-1;;24765:4:105;24758:18;-1:-1:-1;;;;23152:1654:105:o;20185:586::-;20507:20;;;20531:7;20507:32;20500:3;:40;;;20613:14;;20668:17;;20662:24;;;20654:72;;;;;;;4209:2:257;20654:72:105;;;4191:21:257;4248:2;4228:18;;;4221:30;4287:34;4267:18;;;4260:62;4358:5;4338:18;;;4331:33;4381:19;;20654:72:105;4007:399:257;20654:72:105;20740:14;20185:586;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;467:347:257:-;518:8;528:6;582:3;575:4;567:6;563:17;559:27;549:55;;600:1;597;590:12;549:55;-1:-1:-1;623:20:257;;666:18;655:30;;652:50;;;698:1;695;688:12;652:50;735:4;727:6;723:17;711:29;;787:3;780:4;771:6;763;759:19;755:30;752:39;749:59;;;804:1;801;794:12;749:59;467:347;;;;;:::o;819:717::-;909:6;917;925;933;986:2;974:9;965:7;961:23;957:32;954:52;;;1002:1;999;992:12;954:52;1042:9;1029:23;1071:18;1112:2;1104:6;1101:14;1098:34;;;1128:1;1125;1118:12;1098:34;1167:58;1217:7;1208:6;1197:9;1193:22;1167:58;:::i;:::-;1244:8;;-1:-1:-1;1141:84:257;-1:-1:-1;1332:2:257;1317:18;;1304:32;;-1:-1:-1;1348:16:257;;;1345:36;;;1377:1;1374;1367:12;1345:36;;1416:60;1468:7;1457:8;1446:9;1442:24;1416:60;:::i;:::-;819:717;;;;-1:-1:-1;1495:8:257;-1:-1:-1;;;;819:717:257:o;1723:184::-;1775:77;1772:1;1765:88;1872:4;1869:1;1862:15;1896:4;1893:1;1886:15;3568:245;3647:6;3655;3708:2;3696:9;3687:7;3683:23;3679:32;3676:52;;;3724:1;3721;3714:12;3676:52;-1:-1:-1;;3747:16:257;;3803:2;3788:18;;;3782:25;3747:16;;3782:25;;-1:-1:-1;3568:245:257:o;3818:184::-;3870:77;3867:1;3860:88;3967:4;3964:1;3957:15;3991:4;3988:1;3981:15"
func init() {
if err := json.Unmarshal([]byte(MIPSStorageLayoutJSON), MIPSStorageLayout); err != nil {
......
......@@ -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) {
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address"))
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist"))
require.NoError(t, cfg.Check())
})
t.Run("Valid", func(t *testing.T) {
addr := common.Address{0xbb, 0xcc, 0xdd}
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-address", "--game-address="+addr.Hex()))
require.Equal(t, addr, cfg.GameAddress)
cfg := configForArgs(t, addRequiredArgsExcept(config.TraceTypeAlphabet, "--game-allowlist", "--game-allowlist="+addr.Hex()))
require.Contains(t, cfg.GameAllowlist, addr)
})
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 (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
var (
......@@ -35,27 +36,19 @@ const (
TraceTypeAlphabet TraceType = "alphabet"
TraceTypeCannon TraceType = "cannon"
// Devnet game IDs
DevnetGameIDAlphabet = uint8(0)
DevnetGameIDCannon = uint8(1)
// Mainnet games
CannonFaultGameID = 0
// Mainnet game IDs
MainnetGameIDFault = uint8(0)
// Devnet games
AlphabetFaultGameID = 255
)
var TraceTypes = []TraceType{TraceTypeAlphabet, TraceTypeCannon}
// GameIdToString maps game IDs to their string representation on a per-network basis.
var GameIdToString = map[uint64]map[uint8]string{
// Mainnet
1: {
MainnetGameIDFault: "fault-cannon",
},
// Devnet
900: {
DevnetGameIDAlphabet: "fault-alphabet",
DevnetGameIDCannon: "fault-cannon",
},
// GameIdToString maps game IDs to their string representation.
var GameIdToString = map[uint8]string{
CannonFaultGameID: "Cannon",
AlphabetFaultGameID: "Alphabet",
}
func (t TraceType) String() string {
......@@ -88,7 +81,7 @@ const DefaultCannonSnapshotFreq = uint(1_000_000_000)
type Config struct {
L1EthRpc string // L1 RPC Url
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
TraceType TraceType // Type of trace
......@@ -165,7 +158,7 @@ func (c Config) Check() error {
if c.CannonL2GenesisPath != "" {
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)
}
}
......
......@@ -3,9 +3,10 @@ package config
import (
"testing"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
)
var (
......@@ -68,9 +69,9 @@ func TestGameFactoryAddressRequired(t *testing.T) {
require.ErrorIs(t, config.Check(), ErrMissingGameFactoryAddress)
}
func TestGameAddressNotRequired(t *testing.T) {
func TestGameAllowlistNotRequired(t *testing.T) {
config := validConfig(TraceTypeCannon)
config.GameAddress = common.Address{}
config.GameAllowlist = []common.Address{}
require.NoError(t, config.Check())
}
......
......@@ -4,13 +4,11 @@ import (
"context"
"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/common"
"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 {
......@@ -19,62 +17,39 @@ type FaultDisputeGameCaller interface {
}
type FaultCaller struct {
FaultDisputeGameCaller
log log.Logger
contract FaultDisputeGameCaller
}
func NewFaultCaller(caller FaultDisputeGameCaller, log log.Logger) *FaultCaller {
func NewFaultCaller(caller FaultDisputeGameCaller) *FaultCaller {
return &FaultCaller{
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)
if err != nil {
return nil, err
}
return &FaultCaller{
caller,
log,
}, 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.
// 0: In Progress
// 1: Challenger Won
// 2: Defender Won
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
}
// GetClaimDataLength returns the number of claims in the game.
func (fc *FaultCaller) GetClaimDataLength(ctx context.Context) (*big.Int, error) {
return fc.ClaimDataLen(&bind.CallOpts{Context: ctx})
}
func (fc *FaultCaller) LogClaimDataLength(ctx context.Context) {
claimLen, err := fc.GetClaimDataLength(ctx)
// GetClaimCount returns the number of claims in the game.
func (fc *FaultCaller) GetClaimCount(ctx context.Context) (uint64, error) {
count, err := fc.contract.ClaimDataLen(&bind.CallOpts{Context: ctx})
if err != nil {
fc.log.Error("failed to get claim count", "err", err)
return
return 0, err
}
fc.log.Info("Number of claims", "length", claimLen)
return count.Uint64(), nil
}
......@@ -64,7 +64,7 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fc := NewFaultCaller(test.caller, nil)
fc := NewFaultCaller(test.caller)
status, err := fc.GetGameStatus(context.Background())
require.Equal(t, test.expectedStatus, status)
require.Equal(t, test.expectedErr, err)
......@@ -72,11 +72,11 @@ func TestFaultCaller_GetGameStatus(t *testing.T) {
}
}
func TestFaultCaller_GetClaimDataLength(t *testing.T) {
func TestFaultCaller_GetClaimCount(t *testing.T) {
tests := []struct {
name string
caller FaultDisputeGameCaller
expectedClaimDataLen *big.Int
expectedClaimDataLen uint64
expectedErr error
}{
{
......@@ -84,7 +84,7 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) {
caller: &mockFaultDisputeGameCaller{
claimDataLen: big.NewInt(1),
},
expectedClaimDataLen: big.NewInt(1),
expectedClaimDataLen: 1,
expectedErr: nil,
},
{
......@@ -92,15 +92,15 @@ func TestFaultCaller_GetClaimDataLength(t *testing.T) {
caller: &mockFaultDisputeGameCaller{
errClaimDataLen: true,
},
expectedClaimDataLen: nil,
expectedClaimDataLen: 0,
expectedErr: errMock,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fc := NewFaultCaller(test.caller, nil)
claimDataLen, err := fc.GetClaimDataLength(context.Background())
fc := NewFaultCaller(test.caller)
claimDataLen, err := fc.GetClaimCount(context.Background())
require.Equal(t, test.expectedClaimDataLen, claimDataLen)
require.Equal(t, test.expectedErr, err)
})
......
......@@ -39,7 +39,6 @@ type Executor struct {
rollupConfig string
l2Genesis string
absolutePreState string
dataDir string
snapshotFreq uint
selectSnapshot snapshotSelect
cmdExecutor cmdExecutor
......@@ -57,7 +56,6 @@ func NewExecutor(logger log.Logger, cfg *config.Config, inputs LocalGameInputs)
rollupConfig: cfg.CannonRollupConfigPath,
l2Genesis: cfg.CannonL2GenesisPath,
absolutePreState: cfg.CannonAbsolutePreState,
dataDir: cfg.CannonDatadir,
snapshotFreq: cfg.CannonSnapshotFreq,
selectSnapshot: findStartingSnapshot,
cmdExecutor: runCmd,
......@@ -71,7 +69,7 @@ func (e *Executor) GenerateProof(ctx context.Context, dir string, i uint64) erro
return fmt.Errorf("find starting snapshot: %w", err)
}
proofDir := filepath.Join(dir, proofsDir)
dataDir := filepath.Join(e.dataDir, preimagesDir)
dataDir := filepath.Join(dir, preimagesDir)
lastGeneratedState := filepath.Join(dir, finalState)
args := []string{
"run",
......
......@@ -22,7 +22,9 @@ const execTestCannonPrestate = "/foo/pre.json"
func TestGenerateProof(t *testing.T) {
input := "starting.json"
cfg := config.NewConfig(common.Address{0xbb}, "http://localhost:8888", config.TraceTypeCannon, true)
cfg.CannonDatadir = t.TempDir()
tempDir := t.TempDir()
dir := filepath.Join(tempDir, "gameDir")
cfg.CannonDatadir = tempDir
cfg.CannonAbsolutePreState = "pre.json"
cfg.CannonBin = "./bin/cannon"
cfg.CannonServer = "./bin/op-program"
......@@ -58,7 +60,7 @@ func TestGenerateProof(t *testing.T) {
}
return nil
}
err := executor.GenerateProof(context.Background(), cfg.CannonDatadir, proofAt)
err := executor.GenerateProof(context.Background(), dir, proofAt)
require.NoError(t, err)
return binary, subcommand, args
}
......@@ -68,15 +70,15 @@ func TestGenerateProof(t *testing.T) {
cfg.CannonRollupConfigPath = ""
cfg.CannonL2GenesisPath = ""
binary, subcommand, args := captureExec(t, cfg, 150_000_000)
require.DirExists(t, filepath.Join(cfg.CannonDatadir, preimagesDir))
require.DirExists(t, filepath.Join(cfg.CannonDatadir, proofsDir))
require.DirExists(t, filepath.Join(cfg.CannonDatadir, snapsDir))
require.DirExists(t, filepath.Join(dir, preimagesDir))
require.DirExists(t, filepath.Join(dir, proofsDir))
require.DirExists(t, filepath.Join(dir, snapsDir))
require.Equal(t, cfg.CannonBin, binary)
require.Equal(t, "run", subcommand)
require.Equal(t, input, args["--input"])
require.Contains(t, args, "--meta")
require.Equal(t, "", args["--meta"])
require.Equal(t, filepath.Join(cfg.CannonDatadir, finalState), args["--output"])
require.Equal(t, filepath.Join(dir, finalState), args["--output"])
require.Equal(t, "=150000000", args["--proof-at"])
require.Equal(t, "=150000001", args["--stop-at"])
require.Equal(t, "%500", args["--snapshot-at"])
......@@ -86,9 +88,9 @@ func TestGenerateProof(t *testing.T) {
require.Equal(t, "--server", args[cfg.CannonServer])
require.Equal(t, cfg.L1EthRpc, args["--l1"])
require.Equal(t, cfg.CannonL2, args["--l2"])
require.Equal(t, filepath.Join(cfg.CannonDatadir, preimagesDir), args["--datadir"])
require.Equal(t, filepath.Join(cfg.CannonDatadir, proofsDir, "%d.json"), args["--proof-fmt"])
require.Equal(t, filepath.Join(cfg.CannonDatadir, snapsDir, "%d.json"), args["--snapshot-fmt"])
require.Equal(t, filepath.Join(dir, preimagesDir), args["--datadir"])
require.Equal(t, filepath.Join(dir, proofsDir, "%d.json"), args["--proof-fmt"])
require.Equal(t, filepath.Join(dir, snapsDir, "%d.json"), args["--snapshot-fmt"])
require.Equal(t, cfg.CannonNetwork, args["--network"])
require.NotContains(t, args, "--rollup.config")
require.NotContains(t, args, "--l2.genesis")
......
......@@ -64,13 +64,14 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, cfg *config.Config
if err != nil {
return nil, fmt.Errorf("fetch local game inputs: %w", err)
}
return NewTraceProviderFromInputs(logger, cfg, localInputs), nil
return NewTraceProviderFromInputs(logger, cfg, gameAddr.Hex(), localInputs), nil
}
func NewTraceProviderFromInputs(logger log.Logger, cfg *config.Config, localInputs LocalGameInputs) *CannonTraceProvider {
func NewTraceProviderFromInputs(logger log.Logger, cfg *config.Config, gameDirName string, localInputs LocalGameInputs) *CannonTraceProvider {
dir := filepath.Join(cfg.CannonDatadir, gameDirName)
return &CannonTraceProvider{
logger: logger,
dir: cfg.CannonDatadir,
dir: dir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, cfg, localInputs),
}
......
......@@ -11,6 +11,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/common"
......@@ -149,7 +150,6 @@ func TestGetStepData(t *testing.T) {
func TestAbsolutePreState(t *testing.T) {
dataDir := t.TempDir()
_ = os.Mkdir(dataDir, 0o777)
prestate := "state.json"
......@@ -189,6 +189,21 @@ func TestAbsolutePreState(t *testing.T) {
})
}
func TestUseGameSpecificSubdir(t *testing.T) {
tempDir := t.TempDir()
dataDir := filepath.Join(tempDir, "data")
setupPreState(t, tempDir, "state.json")
logger := testlog.Logger(t, log.LvlInfo)
cfg := &config.Config{
CannonAbsolutePreState: filepath.Join(tempDir, "state.json"),
CannonDatadir: dataDir,
}
gameDirName := "gameSubdir"
localInputs := LocalGameInputs{}
provider := NewTraceProviderFromInputs(logger, cfg, gameDirName, localInputs)
require.Equal(t, filepath.Join(dataDir, gameDirName), provider.dir, "should use game specific subdir")
}
func setupPreState(t *testing.T, dataDir string, filename string) {
srcDir := filepath.Join("test_data")
path := filepath.Join(srcDir, filename)
......
......@@ -6,6 +6,7 @@ import (
"math/big"
"time"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
......@@ -24,24 +25,38 @@ type gameSource interface {
type gameMonitor struct {
logger log.Logger
clock clock.Clock
source gameSource
createPlayer playerCreator
fetchBlockNumber blockNumberFetcher
allowedGame common.Address
allowedGames []common.Address
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{
logger: logger,
clock: cl,
source: source,
createPlayer: createGame,
fetchBlockNumber: fetchBlockNumber,
allowedGame: allowedGame,
allowedGames: allowedGames,
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 {
blockNum, err := m.fetchBlockNumber(ctx)
if err != nil {
......@@ -52,7 +67,7 @@ func (m *gameMonitor) progressGames(ctx context.Context) error {
return fmt.Errorf("failed to load games: %w", err)
}
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)
continue
}
......@@ -86,11 +101,8 @@ func (m *gameMonitor) MonitorGames(ctx context.Context) error {
if err != nil {
m.logger.Error("Failed to progress games", "err", err)
}
select {
case <-time.After(300 * time.Millisecond):
// Continue
case <-ctx.Done():
return ctx.Err()
if err := m.clock.SleepCtx(ctx, 300*time.Millisecond); err != nil {
return err
}
}
}
......@@ -5,6 +5,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-service/clock"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
......@@ -13,7 +14,7 @@ import (
)
func TestMonitorExitsWhenContextDone(t *testing.T) {
monitor, _, _ := setupMonitorTest(t, common.Address{})
monitor, _, _ := setupMonitorTest(t, []common.Address{common.Address{}})
ctx, cancel := context.WithCancel(context.Background())
cancel()
err := monitor.MonitorGames(ctx)
......@@ -21,7 +22,7 @@ func TestMonitorExitsWhenContextDone(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}
addr2 := common.Address{0xbb}
......@@ -54,7 +55,7 @@ func TestMonitorCreateAndProgressGameAgents(t *testing.T) {
func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
addr1 := common.Address{0xaa}
addr2 := common.Address{0xbb}
monitor, source, games := setupMonitorTest(t, addr2)
monitor, source, games := setupMonitorTest(t, []common.Address{addr2})
source.games = []FaultDisputeGame{
{
......@@ -76,7 +77,7 @@ func TestMonitorOnlyCreateSpecifiedGame(t *testing.T) {
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)
source := &stubGameSource{}
games := &createdGames{
......@@ -86,7 +87,7 @@ func setupMonitorTest(t *testing.T, allowedGame common.Address) (*gameMonitor, *
fetchBlockNum := func(ctx context.Context) (uint64, error) {
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
}
......
......@@ -21,7 +21,7 @@ type Actor interface {
type GameInfo interface {
GetGameStatus(context.Context) (types.GameStatus, error)
LogGameInfo(ctx context.Context)
GetClaimCount(context.Context) (uint64, error)
}
type GamePlayer struct {
......@@ -80,7 +80,7 @@ func NewGamePlayer(
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 {
return nil, fmt.Errorf("failed to bind the fault contract: %w", err)
}
......@@ -100,7 +100,23 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) bool {
}
if status, err := g.caller.GetGameStatus(ctx); err != nil {
g.logger.Warn("Unable to retrieve game status", "err", err)
} else if status != 0 {
} else {
g.logGameStatus(ctx, status)
return status != types.GameStatusInProgress
}
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
......@@ -112,9 +128,4 @@ func (g *GamePlayer) ProgressGame(ctx context.Context) bool {
} else {
g.logger.Error("Game lost", "status", status)
}
return true
} else {
g.caller.LogGameInfo(ctx)
}
return false
}
......@@ -11,27 +11,23 @@ import (
"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) {
handler, game, actor, gameInfo := setupProgressGameTest(t, true)
handler, game, actor, _ := setupProgressGameTest(t, true)
actor.err = errors.New("boom")
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")
errLog := handler.FindLog(log.LvlError, "Error when acting on game")
require.NotNil(t, errLog, "should log error")
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 {
name string
status types.GameStatus
......@@ -67,16 +63,23 @@ func TestProgressGame_LogErrorWhenGameLost(t *testing.T) {
logLevel: log.LvlInfo,
logMsg: "Game won",
},
{
name: "GameInProgress",
status: types.GameStatusInProgress,
agreeWithOutput: true,
logLevel: log.LvlInfo,
logMsg: "Game info",
},
}
for _, test := range tests {
test := test
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
done := game.ProgressGame(context.Background())
require.True(t, done, "should be done")
require.Equal(t, 0, gameInfo.logCount, "should not log latest game state")
require.Equal(t, 1, actor.callCount, "should perform next actions")
require.Equal(t, test.status != types.GameStatusInProgress, done, "should be done when not in progress")
errLog := handler.FindLog(test.logLevel, test.logMsg)
require.NotNil(t, errLog, "should log game result")
require.Equal(t, test.status, errLog.GetContextValue("status"))
......@@ -91,7 +94,7 @@ func setupProgressGameTest(t *testing.T, agreeWithProposedRoot bool) (*testlog.C
}
logger.SetHandler(handler)
actor := &stubActor{}
gameInfo := &stubGameInfo{}
gameInfo := &stubGameInfo{claimCount: 1}
game := &GamePlayer{
agent: actor,
agreeWithProposedOutput: agreeWithProposedRoot,
......@@ -113,14 +116,14 @@ func (a *stubActor) Act(ctx context.Context) error {
type stubGameInfo struct {
status types.GameStatus
claimCount uint64
err error
logCount int
}
func (s *stubGameInfo) GetGameStatus(ctx context.Context) (types.GameStatus, error) {
return s.status, s.err
}
func (s *stubGameInfo) LogGameInfo(ctx context.Context) {
s.logCount++
func (s *stubGameInfo) GetClaimCount(ctx context.Context) (uint64, error) {
return s.claimCount, s.err
}
......@@ -11,6 +11,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/version"
"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"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
......@@ -33,6 +34,7 @@ type service struct {
// NewService creates a new Service.
func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*service, error) {
cl := clock.SystemClock
m := metrics.NewMetrics()
txMgr, err := txmgr.NewSimpleTxManager("challenger", logger, &m.TxMetrics, cfg.TxMgrConfig)
if err != nil {
......@@ -71,7 +73,7 @@ func NewService(ctx context.Context, logger log.Logger, cfg *config.Config) (*se
}
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)
})
......
......@@ -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 {
isOddLevel := claim.Depth()%2 == 1
// If we agree with the proposed output, we agree with odd levels
......
......@@ -4,6 +4,9 @@ import (
"fmt"
"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-node/chaincfg"
opservice "github.com/ethereum-optimism/optimism/op-service"
......@@ -12,9 +15,6 @@ import (
opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof "github.com/ethereum-optimism/optimism/op-service/pprof"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
)
const (
......@@ -37,10 +37,11 @@ var (
Usage: "Address of the fault game factory contract.",
EnvVars: prefixEnvVars("GAME_FACTORY_ADDRESS"),
}
GameAddressFlag = &cli.StringFlag{
Name: "game-address",
Usage: "Address of the Fault Game contract.",
EnvVars: prefixEnvVars("GAME_ADDRESS"),
GameAllowlistFlag = &cli.StringSliceFlag{
Name: "game-allowlist",
Usage: "List of Fault Game contract addresses the challenger is allowed to play. " +
"If empty, the challenger will play all games.",
EnvVars: prefixEnvVars("GAME_ALLOWLIST"),
}
TraceTypeFlag = &cli.GenericFlag{
Name: "trace-type",
......@@ -121,7 +122,7 @@ var requiredFlags = []cli.Flag{
// optionalFlags is a list of unchecked cli flags
var optionalFlags = []cli.Flag{
AlphabetFlag,
GameAddressFlag,
GameAllowlistFlag,
CannonNetworkFlag,
CannonRollupConfigFlag,
CannonL2GenesisFlag,
......@@ -154,11 +155,13 @@ func CheckRequired(ctx *cli.Context) error {
gameType := config.TraceType(strings.ToLower(ctx.String(TraceTypeFlag.Name)))
switch gameType {
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",
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",
CannonNetworkFlag.Name, CannonRollupConfigFlag.Name, CannonL2GenesisFlag.Name)
}
......@@ -196,12 +199,15 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
if err != nil {
return nil, err
}
var gameAddress common.Address
if ctx.IsSet(GameAddressFlag.Name) {
gameAddress, err = opservice.ParseAddress(ctx.String(GameAddressFlag.Name))
var allowedGames []common.Address
if ctx.StringSlice(GameAllowlistFlag.Name) != nil {
for _, addr := range ctx.StringSlice(GameAllowlistFlag.Name) {
gameAddress, err := opservice.ParseAddress(addr)
if err != nil {
return nil, err
}
allowedGames = append(allowedGames, gameAddress)
}
}
txMgrConfig := txmgr.ReadCLIConfig(ctx)
......@@ -215,7 +221,7 @@ func NewConfigFromCLI(ctx *cli.Context) (*config.Config, error) {
L1EthRpc: ctx.String(L1EthRpcFlag.Name),
TraceType: traceTypeFlag,
GameFactoryAddress: gameFactoryAddress,
GameAddress: gameAddress,
GameAllowlist: allowedGames,
AlphabetTrace: ctx.String(AlphabetFlag.Name),
CannonNetwork: ctx.String(CannonNetworkFlag.Name),
CannonRollupConfigPath: ctx.String(CannonRollupConfigFlag.Name),
......
......@@ -78,8 +78,8 @@ cast call $L2_OUTPUT_ORACLE_PROXY "getL2Output(uint256)" $PRIOR_INDEX
echo "Getting the l2 output at index $INDEX"
cast call $L2_OUTPUT_ORACLE_PROXY "getL2Output(uint256)" $INDEX
# (Alphabet) Fault game type = 0
GAME_TYPE=0
# (Alphabet) Fault game type = 255
GAME_TYPE=255
# Root claim commits to the entire trace.
# Alphabet game claim construction: keccak256(abi.encode(trace_index, trace[trace_index]))
......
external_*/shim
......@@ -28,6 +28,11 @@ clean:
lint:
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./...
test-external-%: pre-test
make -C ./external_$*/
go test -v --externalL2 ./external_$*/shim
.PHONY: \
test \
lint
......@@ -24,7 +24,7 @@ func TestERC20BridgeDeposits(t *testing.T) {
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......
......@@ -26,6 +26,11 @@ var (
L1Deployments *genesis.L1Deployments
// DeployConfig represents the deploy config used by the system.
DeployConfig *genesis.DeployConfig
// ExternalL2Nodes is the shim to use if external ethereum client testing is
// enabled
ExternalL2Nodes string
// EthNodeVerbosity is the level of verbosity to output
EthNodeVerbosity int
)
// Init testing to enable test flags
......@@ -53,6 +58,8 @@ func init() {
flag.StringVar(&l1AllocsPath, "l1-allocs", defaultL1AllocsPath, "")
flag.StringVar(&l1DeploymentsPath, "l1-deployments", defaultL1DeploymentsPath, "")
flag.StringVar(&deployConfigPath, "deploy-config", defaultDeployConfigPath, "")
flag.StringVar(&ExternalL2Nodes, "externalL2", "", "Enable tests with external L2")
flag.IntVar(&EthNodeVerbosity, "ethLogVerbosity", 3, "The level of verbosity to use for the eth node logs")
flag.Parse()
if err := allExist(l1AllocsPath, l1DeploymentsPath, deployConfigPath); err != nil {
......
......@@ -38,7 +38,10 @@ func WithFactoryAddress(addr common.Address) Option {
func WithGameAddress(addr common.Address) Option {
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 (
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum/go-ethereum/common"
)
type AlphabetGameHelper struct {
......@@ -16,7 +18,7 @@ func (g *AlphabetGameHelper) StartChallenger(ctx context.Context, l1Endpoint str
opts := []challenger.Option{
func(c *config.Config) {
c.GameFactoryAddress = g.factoryAddr
c.GameAddress = g.addr
c.GameAllowlist = []common.Address{g.addr}
c.TraceType = config.TraceTypeAlphabet
// By default the challenger agrees with the root claim (thus disagrees with the proposed output)
// This can be overridden by passing in options
......
......@@ -15,19 +15,21 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/alphabet"
"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/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
const alphabetGameType uint8 = 0
const cannonGameType uint8 = 1
const alphabetGameType uint8 = 255
const cannonGameType uint8 = 0
const alphabetGameDepth = 4
const lastAlphabetTraceIndex = 1<<alphabetGameDepth - 1
......@@ -106,8 +108,11 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
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.opts.GasLimit = 0
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.Len(rcpt.Logs, 1, "should have emitted a single DisputeGameCreated event")
......@@ -170,7 +175,7 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll
L2Claim: challengedOutput.OutputRoot,
L2BlockNumber: challengedOutput.L2BlockNumber,
}
provider := cannon.NewTraceProviderFromInputs(testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"), cfg, inputs)
provider := cannon.NewTraceProviderFromInputs(testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"), cfg, "correct", inputs)
rootClaim, err := provider.Get(ctx, math.MaxUint64)
h.require.NoError(err, "Compute correct root hash")
......@@ -191,7 +196,9 @@ func (h *FactoryHelper) createCannonGame(ctx context.Context, l2BlockNumber uint
extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
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")
rcpt, err := wait.ForReceiptOK(ctx, h.client, tx.Hash())
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,7 +56,11 @@ func (s *jsonRawString) UnmarshalJSON(input []byte) error {
// printDebugTrace logs debug_traceTransaction output to aid in debugging unexpected receipt statuses
func printDebugTrace(ctx context.Context, client *ethclient.Client, txHash common.Hash) {
var trace jsonRawString
options := map[string]string{}
options := map[string]any{
"enableReturnData": true,
"tracer": "callTracer",
"tracerConfig": map[string]any{},
}
err := client.Client().CallContext(ctx, &trace, "debug_traceTransaction", hexutil.Bytes(txHash.Bytes()), options)
if err != nil {
fmt.Printf("TxTrace unavailable: %v\n", err)
......
package op_e2e
import (
"encoding/json"
"math/big"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/external"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/params"
"github.com/onsi/gomega/gexec"
"github.com/stretchr/testify/require"
)
type ExternalRunner struct {
Name string
BinPath string
Genesis *core.Genesis
JWTPath string
}
type ExternalEthClient struct {
Session *gexec.Session
Endpoints external.Endpoints
}
func (eec *ExternalEthClient) HTTPEndpoint() string {
return eec.Endpoints.HTTPEndpoint
}
func (eec *ExternalEthClient) WSEndpoint() string {
return eec.Endpoints.WSEndpoint
}
func (eec *ExternalEthClient) HTTPAuthEndpoint() string {
return eec.Endpoints.HTTPAuthEndpoint
}
func (eec *ExternalEthClient) WSAuthEndpoint() string {
return eec.Endpoints.WSAuthEndpoint
}
func (eec *ExternalEthClient) Close() {
eec.Session.Terminate()
select {
case <-time.After(5 * time.Second):
eec.Session.Kill()
case <-eec.Session.Exited:
}
}
func (er *ExternalRunner) Run(t *testing.T) *ExternalEthClient {
if er.BinPath == "" {
t.Error("no external bin path set")
}
if er.JWTPath == "" {
er.JWTPath = writeDefaultJWT(t)
}
if er.Genesis == nil {
er.Genesis = &core.Genesis{
Alloc: core.GenesisAlloc{
common.Address{1}: core.GenesisAccount{Balance: big.NewInt(1)},
},
Config: params.OptimismTestConfig,
Difficulty: big.NewInt(0),
}
}
workDir := t.TempDir()
config := external.Config{
DataDir: filepath.Join(workDir, "datadir"),
JWTPath: er.JWTPath,
ChainID: er.Genesis.Config.ChainID.Uint64(),
GenesisPath: filepath.Join(workDir, "genesis.json"),
EndpointsReadyPath: filepath.Join(workDir, "endpoints.json"),
Verbosity: uint64(config.EthNodeVerbosity),
}
err := os.Mkdir(config.DataDir, 0o700)
require.NoError(t, err)
genesisFile, err := os.Create(config.GenesisPath)
require.NoError(t, err)
err = json.NewEncoder(genesisFile).Encode(er.Genesis)
require.NoError(t, err)
configPath := filepath.Join(workDir, "config.json")
configFile, err := os.Create(configPath)
require.NoError(t, err)
err = json.NewEncoder(configFile).Encode(config)
require.NoError(t, err)
cmd := exec.Command(er.BinPath, "--config", configPath)
cmd.Dir = filepath.Dir(er.BinPath)
sess, err := gexec.Start(
cmd,
gexec.NewPrefixedWriter("[extout:"+er.Name+"]", os.Stdout),
gexec.NewPrefixedWriter("[exterr:"+er.Name+"]", os.Stderr),
)
require.NoError(t, err)
// 2 minutes may seem like a long timeout, and, it definitely is. That
// being said, when running these tests with high parallelism turned on, the
// node startup time can be substantial (remember, this usually is a
// multi-step process initializing the database and then starting the
// client).
require.Eventually(
t,
func() bool {
_, err := os.Stat(config.EndpointsReadyPath)
return err == nil
},
2*time.Minute,
10*time.Millisecond,
"external runner did not create ready file at %s within timeout",
config.EndpointsReadyPath,
)
readyFile, err := os.Open(config.EndpointsReadyPath)
require.NoError(t, err)
var endpoints external.Endpoints
err = json.NewDecoder(readyFile).Decode(&endpoints)
require.NoError(t, err)
return &ExternalEthClient{
Session: sess,
Endpoints: endpoints,
}
}
package external
import (
"encoding/json"
"os"
)
type Config struct {
DataDir string `json:"data_dir"`
JWTPath string `json:"jwt_path"`
ChainID uint64 `json:"chain_id"`
GasCeil uint64 `json:"gas_ceil"`
GenesisPath string `json:"genesis_path"`
Verbosity uint64 `json:"verbosity"`
// EndpointsReadyPath is the location to write the endpoint configuration file.
// Note, this should be written atomically by writing the JSON, then moving
// it to this path to avoid races. A helper AtomicEncode is provided for
// golang clients.
EndpointsReadyPath string `json:"endpoints_ready_path"`
}
// AtomicEncode json encodes val to path+".atomic" then moves the path+".atomic"
// file to path
func AtomicEncode(path string, val any) error {
atomicPath := path + ".atomic"
atomicFile, err := os.Create(atomicPath)
if err != nil {
return err
}
if err = json.NewEncoder(atomicFile).Encode(val); err != nil {
return err
}
return os.Rename(atomicPath, path)
}
type Endpoints struct {
HTTPEndpoint string `json:"http_endpoint"`
WSEndpoint string `json:"ws_endpoint"`
HTTPAuthEndpoint string `json:"http_auth_endpoint"`
WSAuthEndpoint string `json:"ws_auth_endpoint"`
}
default: shim op-geth
op-geth:
go build -o op-geth "github.com/ethereum/go-ethereum/cmd/geth"
.PHONY: op-geth
shim: main.go
go build -o shim .
# external_geth shim
This shim is an example of how to write an adapter for an external ethereum
client to allow for its use in the op-e2e tests.
## Invocation
Generally speaking, you can utilize this shim by simply executing:
```
make test-external-geth
```
The `Makefile` is structured such that if you duplicate this directory and
tweak this code, you may simply execute:
```
make test-external-<your-client>
```
and the execution should happen as well.
*NOTE:* Attempting to iterate for development requires explicit rebuilding of
the binary being shimmed. Most likely to accomplish this, you may want to add
initialization code to the TestMain of the e2e to build your binary, or use
some other technique like custom build scripts or IDE integrations which cause
the binary to be rebuilt before executing the tests.
## Arguments
*--config <path>* The config path is a required argument, it points to a JSON
file which contains details of the L2 environment to bring up (including the
`genesis.json` path, the chain ID, the JWT path, and a ready file path). See
the data structures in `op-e2e/external/config.go` for more details.
## Operation
This shim will first execute a process to initialize the op-geth database.
Then, it will start the op-geth process itself. It watches the output of the
process and looks for the lines indicating that the HTTP server and Auth HTTP
server have started up. It then reads the ports which were allocated (because
the requested ports were passed in as ephemeral via the CLI arguments).
## Generalization
This shim is included to help document an demonstrate the usage of the
external ethereum process e2e test execution. It is configured to execute in
CI to help ensure that the tests remain compatible with external clients.
To create your own external test client, these files can likely be used as a
starting point, changing the arguments, log scraping, and other details. Or,
depending on the client and your preference, any binary which is capable of
reading and writing the necessary JSON files should be sufficient (though
will be required to replicate some of the parsing and other logic encapsulated
here).
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/external"
"github.com/onsi/gomega/gbytes"
"github.com/onsi/gomega/gexec"
)
func main() {
var configPath string
flag.StringVar(&configPath, "config", "", "Execute based on the config in this file")
flag.Parse()
if err := run(configPath); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
os.Exit(0)
}
func run(configPath string) error {
if configPath == "" {
return fmt.Errorf("must supply a '--config <path>' flag")
}
configFile, err := os.Open(configPath)
if err != nil {
return fmt.Errorf("could not open config: %w", err)
}
var config external.Config
if err := json.NewDecoder(configFile).Decode(&config); err != nil {
return fmt.Errorf("could not decode config file: %w", err)
}
binPath, err := filepath.Abs("op-geth")
if err != nil {
return fmt.Errorf("could not get absolute path of op-geth")
}
if _, err := os.Stat(binPath); err != nil {
return fmt.Errorf("could not locate op-geth in working directory, did you forget to run '--init'?")
}
fmt.Printf("================== op-geth shim initializing chain config ==========================\n")
if err := initialize(binPath, config); err != nil {
return fmt.Errorf("could not initialize datadir: %s %w", binPath, err)
}
fmt.Printf("================== op-geth shim executing op-geth ==========================\n")
sess, err := execute(binPath, config)
if err != nil {
return fmt.Errorf("could not execute geth: %w", err)
}
defer sess.Close()
fmt.Printf("================== op-geth shim encoding ready-file ==========================\n")
if err := external.AtomicEncode(config.EndpointsReadyPath, sess.endpoints); err != nil {
return fmt.Errorf("could not encode endpoints")
}
fmt.Printf("================== op-geth shim awaiting termination ==========================\n")
select {
case <-sess.session.Exited:
return fmt.Errorf("geth exited")
case <-time.After(30 * time.Minute):
return fmt.Errorf("exiting after 30 minute timeout")
}
}
func initialize(binPath string, config external.Config) error {
cmd := exec.Command(
binPath,
"--datadir", config.DataDir,
"init", config.GenesisPath,
)
return cmd.Run()
}
type gethSession struct {
session *gexec.Session
endpoints *external.Endpoints
}
func (es *gethSession) Close() {
es.session.Terminate()
select {
case <-time.After(5 * time.Second):
es.session.Kill()
case <-es.session.Exited:
}
}
func execute(binPath string, config external.Config) (*gethSession, error) {
if config.Verbosity < 2 {
return nil, fmt.Errorf("a minimum configured verbosity of 2 is required")
}
cmd := exec.Command(
binPath,
"--datadir", config.DataDir,
"--http",
"--http.addr", "127.0.0.1",
"--http.port", "0",
"--http.api", "web3,debug,eth,txpool,net,engine",
"--ws",
"--ws.addr", "127.0.0.1",
"--ws.port", "0",
"--ws.api", "debug,eth,txpool,net,engine",
"--syncmode=full",
"--nodiscover",
"--port", "0",
"--maxpeers", "0",
"--networkid", strconv.FormatUint(config.ChainID, 10),
"--authrpc.addr", "127.0.0.1",
"--authrpc.port", "0",
"--authrpc.jwtsecret", config.JWTPath,
"--gcmode=archive",
"--verbosity", strconv.FormatUint(config.Verbosity, 10),
)
sess, err := gexec.Start(cmd, os.Stdout, os.Stderr)
if err != nil {
return nil, fmt.Errorf("could not start op-geth session: %w", err)
}
matcher := gbytes.Say("HTTP server started\\s*endpoint=127.0.0.1:")
var enginePort, httpPort int
for enginePort == 0 || httpPort == 0 {
match, err := matcher.Match(sess.Err)
if err != nil {
return nil, fmt.Errorf("could not execute matcher")
}
if !match {
if sess.Err.Closed() {
return nil, fmt.Errorf("op-geth exited before announcing http ports")
}
// Wait for a bit more output, then try again
time.Sleep(10 * time.Millisecond)
continue
}
var authString string
var port int
fmt.Fscanf(sess.Err, "%d %s", &port, &authString)
switch authString {
case "auth=true":
enginePort = port
case "auth=false":
httpPort = port
default:
return nil, fmt.Errorf("unexpected auth string %q", authString)
}
}
return &gethSession{
session: sess,
endpoints: &external.Endpoints{
HTTPEndpoint: fmt.Sprintf("http://127.0.0.1:%d/", httpPort),
WSEndpoint: fmt.Sprintf("ws://127.0.0.1:%d/", httpPort),
HTTPAuthEndpoint: fmt.Sprintf("http://127.0.0.1:%d/", enginePort),
WSAuthEndpoint: fmt.Sprintf("ws://127.0.0.1:%d/", enginePort),
},
}, nil
}
package main
import (
"net"
"net/url"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/stretchr/testify/require"
)
func TestShim(t *testing.T) {
shimPath, err := filepath.Abs("shim")
require.NoError(t, err)
cmd := exec.Command("go", "build", "-o", shimPath, ".")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
require.NoError(t, err)
require.FileExists(t, "shim")
opGethPath, err := filepath.Abs("op-geth")
require.NoError(t, err)
cmd = exec.Command("go", "build", "-o", opGethPath, "github.com/ethereum/go-ethereum/cmd/geth")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
require.NoError(t, err)
require.FileExists(t, "op-geth")
config.EthNodeVerbosity = 4
ec := (&e2e.ExternalRunner{
Name: "TestShim",
BinPath: shimPath,
}).Run(t)
t.Cleanup(ec.Close)
for _, endpoint := range []string{
ec.HTTPEndpoint(),
ec.HTTPAuthEndpoint(),
ec.WSEndpoint(),
ec.WSAuthEndpoint(),
} {
plainURL, err := url.ParseRequestURI(endpoint)
require.NoError(t, err)
_, err = net.DialTimeout("tcp", plainURL.Host, time.Second)
require.NoError(t, err, "could not connect to HTTP port")
}
}
//go:build tools
package main
import _ "github.com/ethereum/go-ethereum/cmd/geth"
......@@ -50,7 +50,6 @@ func TestMultipleAlphabetGames(t *testing.T) {
}
func TestMultipleCannonGames(t *testing.T) {
t.Skip("Cannon provider doesn't currently isolate different game traces")
InitParallel(t)
ctx := context.Background()
......@@ -409,7 +408,7 @@ func startFaultDisputeSystem(t *testing.T) (*System, *ethclient.Client) {
cfg.SupportL1TimeTravel = true
cfg.DeployConfig.L2OutputOracleSubmissionInterval = 1
cfg.NonFinalizedProposals = true // Submit output proposals asap
sys, err := cfg.Start()
require.NoError(t, err, "Error starting up system")
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
return sys, sys.Clients["l1"]
}
......@@ -24,6 +24,10 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"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 (
......
package op_e2e
import (
"flag"
"os"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum/go-ethereum/log"
)
var enableParallelTesting bool = true
// Init testing to enable test flags
var _ = func() bool {
testing.Init()
return true
}()
var verboseGethNodes bool
func init() {
flag.BoolVar(&verboseGethNodes, "gethlogs", true, "Enable logs on geth nodes")
flag.Parse()
if os.Getenv("OP_E2E_DISABLE_PARALLEL") == "true" {
enableParallelTesting = false
}
}
var enableParallelTesting bool = os.Getenv("OP_E2E_DISABLE_PARALLEL") != "true"
func InitParallel(t *testing.T) {
t.Helper()
if enableParallelTesting {
t.Parallel()
}
if !verboseGethNodes {
if config.EthNodeVerbosity < 0 {
log.Root().SetHandler(log.DiscardHandler())
}
}
......@@ -48,7 +48,7 @@ func TestMissingGasLimit(t *testing.T) {
func TestTxGasSameAsBlockGasLimit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......
......@@ -139,6 +139,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
GethOptions: map[string][]GethOption{},
P2PTopology: nil, // no P2P connectivity by default
NonFinalizedProposals: false,
ExternalL2Nodes: config.ExternalL2Nodes,
BatcherTargetL1TxSizeBytes: 100_000,
}
}
......@@ -146,7 +147,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
func writeDefaultJWT(t *testing.T) string {
// Sadly the geth node config cannot load JWT secret from memory, it has to be a file
jwtPath := path.Join(t.TempDir(), "jwt_secret")
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(testingJWTSecret[:])), 0600); err != nil {
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(testingJWTSecret[:])), 0o600); err != nil {
t.Fatalf("failed to prepare jwt file for geth: %v", err)
}
return jwtPath
......@@ -174,6 +175,8 @@ type SystemConfig struct {
ProposerLogger log.Logger
BatcherLogger log.Logger
ExternalL2Nodes string
// map of outbound connections to other nodes. Node names prefixed with "~" are unconnected but linked.
// A nil map disables P2P completely.
// Any node name not in the topology will not have p2p enabled.
......@@ -195,6 +198,41 @@ type SystemConfig struct {
SupportL1TimeTravel bool
}
type GethInstance struct {
Backend *geth_eth.Ethereum
Node *node.Node
}
func (gi *GethInstance) HTTPEndpoint() string {
return gi.Node.HTTPEndpoint()
}
func (gi *GethInstance) WSEndpoint() string {
return gi.Node.WSEndpoint()
}
func (gi *GethInstance) WSAuthEndpoint() string {
return gi.Node.WSAuthEndpoint()
}
func (gi *GethInstance) HTTPAuthEndpoint() string {
return gi.Node.HTTPAuthEndpoint()
}
func (gi *GethInstance) Close() {
gi.Node.Close()
}
// EthInstance is either an in process Geth or external process exposing its
// endpoints over the network
type EthInstance interface {
HTTPEndpoint() string
WSEndpoint() string
HTTPAuthEndpoint() string
WSAuthEndpoint() string
Close()
}
type System struct {
cfg SystemConfig
......@@ -203,9 +241,9 @@ type System struct {
L2GenesisCfg *core.Genesis
// Connections to running nodes
Nodes map[string]*node.Node
Backends map[string]*geth_eth.Ethereum
EthInstances map[string]EthInstance
Clients map[string]*ethclient.Client
RawClients map[string]*rpc.Client
RollupNodes map[string]*rollupNode.OpNode
L2OutputSubmitter *l2os.L2OutputSubmitter
BatchSubmitter *bss.BatchSubmitter
......@@ -220,7 +258,7 @@ type System struct {
}
func (sys *System) NodeEndpoint(name string) string {
return selectEndpoint(sys.Nodes[name])
return selectEndpoint(sys.EthInstances[name])
}
func (sys *System) Close() {
......@@ -236,8 +274,8 @@ func (sys *System) Close() {
for _, node := range sys.RollupNodes {
node.Close()
}
for _, node := range sys.Nodes {
node.Close()
for _, ei := range sys.EthInstances {
ei.Close()
}
sys.Mocknet.Close()
}
......@@ -273,7 +311,7 @@ func (s *SystemConfigOptions) Get(key, role string) (systemConfigHook, bool) {
return v, ok
}
func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*System, error) {
opts, err := NewSystemConfigOptions(_opts)
if err != nil {
return nil, err
......@@ -281,9 +319,9 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
sys := &System{
cfg: cfg,
Nodes: make(map[string]*node.Node),
Backends: make(map[string]*geth_eth.Ethereum),
EthInstances: make(map[string]EthInstance),
Clients: make(map[string]*ethclient.Client),
RawClients: make(map[string]*rpc.Client),
RollupNodes: make(map[string]*rollupNode.OpNode),
}
didErrAfterStart := false
......@@ -292,8 +330,8 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
for _, node := range sys.RollupNodes {
node.Close()
}
for _, node := range sys.Nodes {
node.Close()
for _, ei := range sys.EthInstances {
ei.Close()
}
}
}()
......@@ -388,41 +426,53 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
if err != nil {
return nil, err
}
sys.Nodes["l1"] = l1Node
sys.Backends["l1"] = l1Backend
sys.EthInstances["l1"] = &GethInstance{
Backend: l1Backend,
Node: l1Node,
}
err = l1Node.Start()
if err != nil {
didErrAfterStart = true
return nil, err
}
for name := range cfg.Nodes {
var ethClient EthInstance
if cfg.ExternalL2Nodes == "" {
node, backend, err := initL2Geth(name, big.NewInt(int64(cfg.DeployConfig.L2ChainID)), l2Genesis, cfg.JWTFilePath, cfg.GethOptions[name]...)
if err != nil {
return nil, err
}
sys.Nodes[name] = node
sys.Backends[name] = backend
gethInst := &GethInstance{
Backend: backend,
Node: node,
}
// Start
err = l1Node.Start()
err = gethInst.Node.Start()
if err != nil {
didErrAfterStart = true
return nil, err
}
for name, node := range sys.Nodes {
if name == "l1" {
continue
ethClient = gethInst
} else {
if len(cfg.GethOptions[name]) > 0 {
t.Errorf("External L2 nodes do not support configuration through GethOptions")
}
err = node.Start()
if err != nil {
didErrAfterStart = true
return nil, err
ethClient = (&ExternalRunner{
Name: name,
BinPath: cfg.ExternalL2Nodes,
Genesis: l2Genesis,
JWTPath: cfg.JWTFilePath,
}).Run(t)
}
sys.EthInstances[name] = ethClient
}
// Configure connections to L1 and L2 for rollup nodes.
// TODO: refactor testing to use in-process rpc connections instead of websockets.
// TODO: refactor testing to allow use of in-process rpc connections instead
// of only websockets (which are required for external eth client tests).
for name, rollupCfg := range cfg.Nodes {
configureL1(rollupCfg, l1Node)
configureL2(rollupCfg, sys.Nodes[name], cfg.JWTSecret)
configureL1(rollupCfg, sys.EthInstances["l1"])
configureL2(rollupCfg, sys.EthInstances[name], cfg.JWTSecret)
rollupCfg.L2Sync = &rollupNode.PreparedL2SyncEndpoint{
Client: nil,
......@@ -438,14 +488,18 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
didErrAfterStart = true
return nil, err
}
l1Client := ethclient.NewClient(rpc.DialInProc(l1Srv))
rawL1Client := rpc.DialInProc(l1Srv)
l1Client := ethclient.NewClient(rawL1Client)
sys.Clients["l1"] = l1Client
for name, node := range sys.Nodes {
client, err := ethclient.DialContext(ctx, node.WSEndpoint())
sys.RawClients["l1"] = rawL1Client
for name, ethInst := range sys.EthInstances {
rawClient, err := rpc.DialContext(ctx, ethInst.WSEndpoint())
if err != nil {
didErrAfterStart = true
return nil, err
}
client := ethclient.NewClient(rawClient)
sys.RawClients[name] = rawClient
sys.Clients[name] = client
}
......@@ -532,7 +586,7 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
}
}
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(""))
if err != nil {
......@@ -579,11 +633,11 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
// L2Output Submitter
sys.L2OutputSubmitter, err = l2os.NewL2OutputSubmitterFromCLIConfig(l2os.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
L1EthRpc: sys.EthInstances["l1"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
L2OOAddress: config.L1Deployments.L2OutputOracleProxy.Hex(),
PollInterval: 50 * time.Millisecond,
TxMgrConfig: newTxMgrConfig(sys.Nodes["l1"].WSEndpoint(), cfg.Secrets.Proposer),
TxMgrConfig: newTxMgrConfig(sys.EthInstances["l1"].WSEndpoint(), cfg.Secrets.Proposer),
AllowNonFinalized: cfg.NonFinalizedProposals,
LogConfig: oplog.CLIConfig{
Level: "info",
......@@ -600,8 +654,8 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
// Batch Submitter
sys.BatchSubmitter, err = bss.NewBatchSubmitterFromCLIConfig(bss.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
L2EthRpc: sys.Nodes["sequencer"].WSEndpoint(),
L1EthRpc: sys.EthInstances["l1"].WSEndpoint(),
L2EthRpc: sys.EthInstances["sequencer"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
MaxPendingTransactions: 0,
MaxChannelDuration: 1,
......@@ -613,7 +667,7 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
},
SubSafetyMargin: 4,
PollInterval: 50 * time.Millisecond,
TxMgrConfig: newTxMgrConfig(sys.Nodes["l1"].WSEndpoint(), cfg.Secrets.Batcher),
TxMgrConfig: newTxMgrConfig(sys.EthInstances["l1"].WSEndpoint(), cfg.Secrets.Batcher),
LogConfig: oplog.CLIConfig{
Level: "info",
Format: "text",
......@@ -678,7 +732,7 @@ func (sys *System) newMockNetPeer() (host.Host, error) {
return sys.Mocknet.AddPeerWithPeerstore(p, eps)
}
func selectEndpoint(node *node.Node) string {
func selectEndpoint(node EthInstance) string {
useHTTP := os.Getenv("OP_E2E_USE_HTTP") == "true"
if useHTTP {
log.Info("using HTTP client")
......@@ -687,7 +741,7 @@ func selectEndpoint(node *node.Node) string {
return node.WSEndpoint()
}
func configureL1(rollupNodeCfg *rollupNode.Config, l1Node *node.Node) {
func configureL1(rollupNodeCfg *rollupNode.Config, l1Node EthInstance) {
l1EndpointConfig := selectEndpoint(l1Node)
rollupNodeCfg.L1 = &rollupNode.L1EndpointConfig{
L1NodeAddr: l1EndpointConfig,
......@@ -698,7 +752,13 @@ func configureL1(rollupNodeCfg *rollupNode.Config, l1Node *node.Node) {
HttpPollInterval: time.Millisecond * 100,
}
}
func configureL2(rollupNodeCfg *rollupNode.Config, l2Node *node.Node, jwtSecret [32]byte) {
type WSOrHTTPEndpoint interface {
WSAuthEndpoint() string
HTTPAuthEndpoint() string
}
func configureL2(rollupNodeCfg *rollupNode.Config, l2Node WSOrHTTPEndpoint, jwtSecret [32]byte) {
useHTTP := os.Getenv("OP_E2E_USE_HTTP") == "true"
l2EndpointConfig := l2Node.WSAuthEndpoint()
if useHTTP {
......
......@@ -17,7 +17,7 @@ func TestStopStartSequencer(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -83,7 +83,7 @@ func TestPersistSequencerStateWhenChanged(t *testing.T) {
delete(cfg.Nodes, "verifier")
cfg.Nodes["sequencer"].ConfigPersistence = node.NewConfigPersistence(stateFile)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.NoError(t, err)
defer sys.Close()
......@@ -118,7 +118,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
seqCfg := cfg.Nodes["sequencer"]
seqCfg.ConfigPersistence = node.NewConfigPersistence(stateFile)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.NoError(t, err)
defer sys.Close()
......@@ -152,7 +152,7 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
seqCfg.Driver.SequencerStopped = true
seqCfg.ConfigPersistence = node.NewConfigPersistence(stateFile)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.NoError(t, err)
defer sys.Close()
......
......@@ -56,7 +56,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool) {
// But not too small to ensure that our claim and subsequent state change is published
cfg.DeployConfig.SequencerWindowSize = 16
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -154,7 +154,7 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool) {
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -260,8 +260,8 @@ func testFaultProofProgramScenario(t *testing.T, ctx context.Context, sys *Syste
sys.BatchSubmitter.StopIfRunning(context.Background())
sys.L2OutputSubmitter.Stop()
sys.L2OutputSubmitter = nil
for _, node := range sys.Nodes {
require.NoError(t, node.Close())
for _, node := range sys.EthInstances {
node.Close()
}
t.Log("Running fault proof in offline mode")
......
......@@ -4,6 +4,9 @@ import (
"context"
"fmt"
"math/big"
"os"
"path/filepath"
"runtime"
"testing"
"time"
......@@ -20,12 +23,14 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
"golang.org/x/exp/slices"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/metrics"
rollupNode "github.com/ethereum-optimism/optimism/op-node/node"
......@@ -39,13 +44,44 @@ import (
"github.com/ethereum-optimism/optimism/op-service/retry"
)
func TestMain(m *testing.M) {
if config.ExternalL2Nodes != "" {
fmt.Println("Running tests with external L2 process adapter at ", config.ExternalL2Nodes)
shimPath, err := filepath.Abs(config.ExternalL2Nodes)
if err != nil {
fmt.Printf("Could not compute abs of externalL2Nodes shim: %s\n", err)
os.Exit(2)
}
// We convert the passed in path to an absolute path, as it simplifies
// the path handling logic for the rest of the testing
config.ExternalL2Nodes = shimPath
_, err = os.Stat(config.ExternalL2Nodes)
if err != nil {
fmt.Printf("Failed to stat externalL2Nodes path: %s\n", err)
os.Exit(3)
}
// As these are integration tests which launch many other processes, the
// default parallelism makes the tests flaky. This change aims to
// reduce the flakiness of these tests.
maxProcs := runtime.NumCPU() / 4
if maxProcs == 0 {
maxProcs = 1
}
runtime.GOMAXPROCS(maxProcs)
}
os.Exit(m.Run())
}
func TestL2OutputSubmitter(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
cfg.NonFinalizedProposals = true // speed up the time till we see output proposals
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -115,7 +151,7 @@ func TestSystemE2E(t *testing.T) {
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -197,7 +233,7 @@ func TestConfirmationDepth(t *testing.T) {
cfg.Nodes["sequencer"].Driver.VerifierConfDepth = 0
cfg.Nodes["verifier"].Driver.VerifierConfDepth = verConfDepth
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -237,6 +273,13 @@ func TestPendingGasLimit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
if cfg.ExternalL2Nodes != "" {
// Some eth clients such as Erigon don't currently build blocks until
// they receive the engine call which includes the gas limit. After we
// provide a mechanism for external clients to advertise test support we
// should enable for those which support it.
t.Skip()
}
// configure the L2 gas limit to be high, and the pending gas limits to be lower for resource saving.
cfg.DeployConfig.L2GenesisBlockGasLimit = 30_000_000
......@@ -255,7 +298,7 @@ func TestPendingGasLimit(t *testing.T) {
},
}
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -297,7 +340,7 @@ func TestFinalize(t *testing.T) {
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -321,14 +364,14 @@ func TestMintOnRevertedDeposit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l1Client := sys.Clients["l1"]
l2Verif := sys.Clients["verifier"]
l1Node := sys.Nodes["l1"]
l1Node := sys.EthInstances["l1"].(*GethInstance).Node
// create signer
ks := l1Node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
......@@ -391,7 +434,7 @@ func TestMissingBatchE2E(t *testing.T) {
// Specifically set batch submitter balance to stop batches from being included
cfg.Premine[cfg.Secrets.Addresses().Batcher] = big.NewInt(0)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -428,8 +471,11 @@ func TestMissingBatchE2E(t *testing.T) {
ctx2, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
block, err := l2Seq.BlockByNumber(ctx2, receipt.BlockNumber)
require.Nil(t, err, "Get block from sequencer")
if err != nil {
require.Equal(t, "not found", err.Error(), "A not found error indicates the chain must have re-orged back before it")
} else {
require.NotEqual(t, block.Hash(), receipt.BlockHash, "L2 Sequencer did not reorg out transaction on it's safe chain")
}
}
func L1InfoFromState(ctx context.Context, contract *bindings.L1Block, l2Number *big.Int) (derive.L1BlockInfo, error) {
......@@ -517,7 +563,7 @@ func TestSystemMockP2P(t *testing.T) {
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["verifier"].Tracer = verifTracer
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -601,13 +647,12 @@ func TestSystemRPCAltSync(t *testing.T) {
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["verifier"].Tracer = verifTracer
sys, err := cfg.Start(SystemConfigOption{
sys, err := cfg.Start(t, SystemConfigOption{
key: "afterRollupNodeStart",
role: "sequencer",
action: func(sCfg *SystemConfig, system *System) {
rpc, _ := system.Nodes["sequencer"].Attach() // never errors
cfg.Nodes["verifier"].L2Sync = &rollupNode.PreparedL2SyncEndpoint{
Client: client.NewBaseRPCClient(rpc),
Client: client.NewBaseRPCClient(system.RawClients["sequencer"]),
}
},
})
......@@ -685,7 +730,7 @@ func TestSystemP2PAltSync(t *testing.T) {
// Blocks are now received via the RPC based alt-sync method
cfg.Nodes["sequencer"].Tracer = seqTracer
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -739,7 +784,7 @@ func TestSystemP2PAltSync(t *testing.T) {
},
},
}
configureL1(syncNodeCfg, sys.Nodes["l1"])
configureL1(syncNodeCfg, sys.EthInstances["l1"])
syncerL2Engine, _, err := initL2Geth("syncer", big.NewInt(int64(cfg.DeployConfig.L2ChainID)), sys.L2GenesisCfg, cfg.JWTFilePath)
require.NoError(t, err)
require.NoError(t, syncerL2Engine.Start())
......@@ -842,7 +887,7 @@ func TestSystemDenseTopology(t *testing.T) {
cfg.Nodes["verifier2"].Tracer = verifTracer2
cfg.Nodes["verifier3"].Tracer = verifTracer3
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -882,7 +927,7 @@ func TestL1InfoContract(t *testing.T) {
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -990,7 +1035,7 @@ func TestWithdrawals(t *testing.T) {
cfg := DefaultSystemConfig(t)
cfg.DeployConfig.FinalizationPeriodSeconds = 2 // 2s finalization period
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -1065,7 +1110,7 @@ func TestWithdrawals(t *testing.T) {
startBalance, err = l1Client.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err)
proveReceipt, finalizeReceipt := ProveAndFinalizeWithdrawal(t, cfg, l1Client, sys.Nodes["verifier"], ethPrivKey, receipt)
proveReceipt, finalizeReceipt := ProveAndFinalizeWithdrawal(t, cfg, l1Client, sys.EthInstances["verifier"], ethPrivKey, receipt)
// Verify balance after withdrawal
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
......@@ -1084,6 +1129,22 @@ func TestWithdrawals(t *testing.T) {
require.Equal(t, withdrawAmount, diff)
}
type stateGetterAdapter struct {
ctx context.Context
t *testing.T
client *ethclient.Client
blockNum *big.Int
}
func (sga *stateGetterAdapter) GetState(addr common.Address, key common.Hash) common.Hash {
sga.t.Helper()
val, err := sga.client.StorageAt(sga.ctx, addr, key, sga.blockNum)
require.NoError(sga.t, err)
var res common.Hash
copy(res[:], val)
return res
}
// TestFees checks that L1/L2 fees are handled.
func TestFees(t *testing.T) {
InitParallel(t)
......@@ -1093,7 +1154,7 @@ func TestFees(t *testing.T) {
cfg.DeployConfig.L2GenesisRegolithTimeOffset = nil
cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7))
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -1101,11 +1162,21 @@ func TestFees(t *testing.T) {
l2Verif := sys.Clients["verifier"]
l1 := sys.Clients["l1"]
seqBackend := sys.Backends["sequencer"]
seqState, err := seqBackend.BlockChain().State()
require.Nil(t, err, "Error getting sequencer state")
config := &params.ChainConfig{
Optimism: &params.OptimismConfig{
EIP1559Elasticity: cfg.DeployConfig.EIP1559Elasticity,
EIP1559Denominator: cfg.DeployConfig.EIP1559Denominator,
},
BedrockBlock: big.NewInt(0),
}
sga := &stateGetterAdapter{
ctx: context.Background(),
t: t,
client: l2Seq,
}
l1CostFn := types.NewL1CostFunc(seqBackend.BlockChain().Config(), seqState)
l1CostFn := types.NewL1CostFunc(config, sga)
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
......@@ -1234,7 +1305,7 @@ func TestStopStartBatcher(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -1317,7 +1388,7 @@ func TestBatcherMultiTx(t *testing.T) {
cfg := DefaultSystemConfig(t)
cfg.BatcherTargetL1TxSizeBytes = 2 // ensures that batcher txs are as small as possible
cfg.DisableBatcher = true
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -1366,7 +1437,7 @@ func TestPendingBlockIsLatest(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
l2Seq := sys.Clients["sequencer"]
......
......@@ -41,7 +41,7 @@ func TestGasPriceOracleFeeUpdates(t *testing.T) {
// Create our system configuration for L1/L2 and start it
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -124,7 +124,7 @@ func TestL2SequencerRPCDepositTx(t *testing.T) {
// Create our system configuration for L1/L2 and start it
cfg := DefaultSystemConfig(t)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -169,7 +169,7 @@ type TestAccount struct {
// startConfigWithTestAccounts takes a SystemConfig, generates additional accounts, adds them to the config, so they
// are funded on startup, starts the system, and imports the keys into the keystore, and obtains transaction opts for
// each account.
func startConfigWithTestAccounts(cfg *SystemConfig, accountsToGenerate int) (*System, []*TestAccount, error) {
func startConfigWithTestAccounts(t *testing.T, cfg *SystemConfig, accountsToGenerate int) (*System, []*TestAccount, error) {
// Create our test accounts and add them to the pre-mine cfg.
testAccounts := make([]*TestAccount, 0)
var err error
......@@ -211,7 +211,7 @@ func startConfigWithTestAccounts(cfg *SystemConfig, accountsToGenerate int) (*Sy
}
// Start our system
sys, err := cfg.Start()
sys, err := cfg.Start(t)
if err != nil {
return sys, nil, err
}
......@@ -233,7 +233,7 @@ func TestMixedDepositValidity(t *testing.T) {
// Create our system configuration, funding all accounts we created for L1/L2, and start it
cfg := DefaultSystemConfig(t)
sys, testAccounts, err := startConfigWithTestAccounts(&cfg, accountUsedToDeposit)
sys, testAccounts, err := startConfigWithTestAccounts(t, &cfg, accountUsedToDeposit)
require.Nil(t, err, "Error starting up system")
defer sys.Close()
......@@ -400,7 +400,7 @@ func TestMixedWithdrawalValidity(t *testing.T) {
cfg.DeployConfig.L2BlockTime = 2
require.LessOrEqual(t, cfg.DeployConfig.FinalizationPeriodSeconds, uint64(6))
require.Equal(t, cfg.DeployConfig.FundDevAccounts, true)
sys, err := cfg.Start()
sys, err := cfg.Start(t)
require.NoError(t, err, "error starting up system")
defer sys.Close()
......@@ -544,7 +544,7 @@ func TestMixedWithdrawalValidity(t *testing.T) {
cancel()
require.Nil(t, err)
rpcClient, err := rpc.Dial(sys.Nodes["verifier"].WSEndpoint())
rpcClient, err := rpc.Dial(sys.EthInstances["verifier"].WSEndpoint())
require.Nil(t, err)
proofCl := gethclient.New(rpcClient)
receiptCl := ethclient.NewClient(rpcClient)
......@@ -715,7 +715,7 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// TODO: Check L1 balance as well here. We avoided this due to time constraints as it seems L1 fees
// were off slightly.
_ = endL1Balance
//require.Equal(t, transactor.ExpectedL1Balance, endL1Balance, "Unexpected L1 balance for transactor")
// require.Equal(t, transactor.ExpectedL1Balance, endL1Balance, "Unexpected L1 balance for transactor")
require.Equal(t, transactor.ExpectedL1Nonce, endL1Nonce, "Unexpected L1 nonce for transactor")
require.Equal(t, transactor.ExpectedL2Nonce, endL2SeqNonce, "Unexpected L2 sequencer nonce for transactor")
require.Equal(t, transactor.ExpectedL2Balance, endL2SeqBalance, "Unexpected L2 sequencer balance for transactor")
......
......@@ -8,6 +8,7 @@ import (
"time"
"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/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -29,19 +30,12 @@ func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l
require.Nil(t, err)
// 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
// for buying L2 gas in the portal contracts.
l1Opts.GasLimit = tx.Gas() + (tx.Gas() / 10)
// Now resend with gas specified
tx, err = depositContract.DepositTransaction(l1Opts, l2Opts.ToAddr, l2Opts.Value, l2Opts.GasLimit, l2Opts.IsCreation, l2Opts.Data)
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)
})
require.Nil(t, err, "with deposit tx")
l1Opts.GasLimit = 0
// Wait for transaction on L1
receipt, err := waitForTransaction(tx.Hash(), l1Client, 10*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
......
......@@ -17,7 +17,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)
......@@ -79,13 +78,13 @@ func defaultWithdrawalTxOpts() *WithdrawalTxOpts {
}
}
func ProveAndFinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node *node.Node, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (*types.Receipt, *types.Receipt) {
func ProveAndFinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node EthInstance, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (*types.Receipt, *types.Receipt) {
params, proveReceipt := ProveWithdrawal(t, cfg, l1Client, l2Node, ethPrivKey, l2WithdrawalReceipt)
finalizeReceipt := FinalizeWithdrawal(t, cfg, l1Client, ethPrivKey, proveReceipt, params)
return proveReceipt, finalizeReceipt
}
func ProveWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node *node.Node, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (withdrawals.ProvenWithdrawalParameters, *types.Receipt) {
func ProveWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Node EthInstance, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (withdrawals.ProvenWithdrawalParameters, *types.Receipt) {
// Get l2BlockNumber for proof generation
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
......
......@@ -6,7 +6,7 @@ import (
"sync/atomic"
"time"
lru "github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
......@@ -31,7 +31,7 @@ type metrics struct {
// Groups heartbeats per unique IP, version and chain ID combination.
// string(IP ++ version ++ chainID) -> *heartbeatEntry
heartbeatUsers *lru.Cache
heartbeatUsers *lru.Cache[string, *heartbeatEntry]
}
type heartbeatEntry struct {
......@@ -42,7 +42,7 @@ type heartbeatEntry struct {
}
func NewMetrics(r *prometheus.Registry) Metrics {
lruCache, _ := lru.New(UsersCacheSize)
lruCache, _ := lru.New[string, *heartbeatEntry](UsersCacheSize)
m := &metrics{
heartbeats: promauto.With(r).NewCounterVec(prometheus.CounterOpts{
Namespace: MetricsNamespace,
......@@ -89,7 +89,7 @@ func (m *metrics) RecordHeartbeat(payload heartbeat.Payload, ip string) {
key := fmt.Sprintf("%s;%s;%s", ip, version, chainID)
now := time.Now()
previous, ok, _ := m.heartbeatUsers.PeekOrAdd(key, &heartbeatEntry{Time: now, Count: 1})
entry, ok, _ := m.heartbeatUsers.PeekOrAdd(key, &heartbeatEntry{Time: now, Count: 1})
if !ok {
// if it's a new entry, observe it and exit.
m.sameIP.WithLabelValues(chainID, version).Observe(1)
......@@ -97,7 +97,6 @@ func (m *metrics) RecordHeartbeat(payload heartbeat.Payload, ip string) {
return
}
entry := previous.(*heartbeatEntry)
if now.Sub(entry.Time) < MinHeartbeatInterval {
// if the span is still going, then add it up
atomic.AddUint64(&entry.Count, 1)
......
......@@ -2,135 +2,100 @@ package chaincfg
import (
"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-service/eth"
)
var Mainnet = 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 Mainnet, Goerli, Sepolia *rollup.Config
var NetworksByName = map[string]rollup.Config{
"goerli": Goerli,
"mainnet": Mainnet,
"sepolia": Sepolia,
func init() {
mustCfg := func(name string) *rollup.Config {
cfg, err := GetRollupConfig(name)
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)
for name, netCfg := range NetworksByName {
out[netCfg.L2ChainID.String()] = name
for _, netCfg := range superchain.OPChains {
out[fmt.Sprintf("%d", netCfg.ChainID)] = netCfg.Name
}
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 {
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
for name := range NetworksByName {
networks = append(networks, name)
for _, cfg := range superchain.OPChains {
networks = append(networks, cfg.Chain+"-"+cfg.Superchain)
}
return networks
}
func GetRollupConfig(name string) (rollup.Config, error) {
network, ok := NetworksByName[name]
if !ok {
return rollup.Config{}, fmt.Errorf("invalid network %s", name)
func IsAvailableNetwork(name string, beta bool) bool {
name = handleLegacyName(name)
available := AvailableNetworks()
if beta {
available = BetaAvailableNetworks()
}
for _, v := range available {
if v == name {
return true
}
}
return false
}
return network, nil
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
}
}
func u64Ptr(v uint64) *uint64 {
return &v
// 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 GetRollupConfig(name string) (*rollup.Config, error) {
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 {
// Only pretty-print the banner if it is a terminal log. Other log it as key-value pairs.
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 {
cfg.Rollup.LogDescription(log, chaincfg.L2ChainIDToNetworkName)
cfg.Rollup.LogDescription(log, chaincfg.L2ChainIDToNetworkDisplayName)
}
n, err := node.New(context.Background(), cfg, log, snapshotLog, VersionWithMeta, m)
......
......@@ -229,6 +229,14 @@ var (
Required: 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{
......@@ -269,6 +277,7 @@ var optionalFlags = []cli.Flag{
BackupL2UnsafeSyncRPCTrustRPC,
L2EngineSyncEnabled,
SkipSyncStartCheck,
BetaExtraNetworks,
}
// Flags contains the list of configuration options available to the binary.
......
......@@ -50,7 +50,8 @@ var (
// Banning Flag - whether or not we want to act on the scoring
Banning = &cli.BoolFlag{
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,
EnvVars: p2pEnv("PEER_BANNING"),
}
......
......@@ -10,7 +10,7 @@ import (
"time"
"github.com/golang/snappy"
lru "github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pb "github.com/libp2p/go-libp2p-pubsub/pb"
"github.com/libp2p/go-libp2p/core/host"
......@@ -242,7 +242,7 @@ func BuildBlocksValidator(log log.Logger, cfg *rollup.Config, runCfg GossipRunti
// Seen block hashes per block height
// uint64 -> *seenBlocks
blockHeightLRU, err := lru.New(1000)
blockHeightLRU, err := lru.New[uint64, *seenBlocks](1000)
if err != nil {
panic(fmt.Errorf("failed to set up block height LRU cache: %w", err))
}
......@@ -315,7 +315,7 @@ func BuildBlocksValidator(log log.Logger, cfg *rollup.Config, runCfg GossipRunti
blockHeightLRU.Add(uint64(payload.BlockNumber), seen)
}
if count, hasSeen := seen.(*seenBlocks).hasSeen(payload.BlockHash); count > 5 {
if count, hasSeen := seen.hasSeen(payload.BlockHash); count > 5 {
// [REJECT] if more than 5 blocks have been seen with the same block height
log.Warn("seen too many different blocks at same height", "height", payload.BlockNumber)
return pubsub.ValidationReject
......@@ -327,7 +327,7 @@ func BuildBlocksValidator(log log.Logger, cfg *rollup.Config, runCfg GossipRunti
// mark it as seen. (note: with concurrent validation more than 5 blocks may be marked as seen still,
// but validator concurrency is limited anyway)
seen.(*seenBlocks).markSeen(payload.BlockHash)
seen.markSeen(payload.BlockHash)
// remember the decoded payload for later usage in topic subscriber.
message.ValidatorData = &payload
......
......@@ -186,9 +186,6 @@ func (conf *Config) Host(log log.Logger, reporter metrics.Reporter, metrics Host
tcpTransport := libp2p.Transport(
tcp.NewTCPTransport,
tcp.WithConnectionTimeout(time.Minute*60)) // break unused connections
if err != nil {
return nil, fmt.Errorf("failed to create TCP transport: %w", err)
}
// TODO: technically we can also run the node on websocket and QUIC transports. Maybe in the future?
var nat lconf.NATManagerC // disabled if nil
......
......@@ -43,7 +43,7 @@ func (testSuite *PeerParamsTestSuite) TestNewPeerScoreThresholds() {
// TestGetPeerScoreParams validates the peer score parameters.
func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_None() {
params, err := GetScoringParams("none", &chaincfg.Goerli)
params, err := GetScoringParams("none", chaincfg.Goerli)
testSuite.NoError(err)
testSuite.Nil(params)
}
......@@ -62,12 +62,12 @@ func (testSuite *PeerParamsTestSuite) TestGetPeerScoreParams_Light() {
testSuite.Equal(0.9261187281287935, decay)
// Test the params
scoringParams, err := GetScoringParams("light", &cfg)
scoringParams, err := GetScoringParams("light", cfg)
peerParams := scoringParams.PeerScoring
testSuite.NoError(err)
// Topics should contain options for block topic
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.NotZero(topicParams.TimeInMeshQuantum)
testSuite.Equal(peerParams.TopicScoreCap, float64(34))
......@@ -101,7 +101,7 @@ func (testSuite *PeerParamsTestSuite) TestParamsZeroBlockTime() {
cfg := chaincfg.Goerli
cfg.BlockTime = 0
slot := 2 * time.Second
params, err := GetScoringParams("light", &cfg)
params, err := GetScoringParams("light", cfg)
testSuite.NoError(err)
testSuite.Equal(params.PeerScoring.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.
Conflicting configuration is deprecated, and will stop the op-node from starting in the future.
`, "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)
if err != nil {
return nil, err
}
return &config, nil
return config, nil
}
file, err := os.Open(rollupConfigPath)
......
package caching
import lru "github.com/hashicorp/golang-lru"
import lru "github.com/hashicorp/golang-lru/v2"
type Metrics interface {
CacheAdd(label string, cacheSize int, evicted bool)
......@@ -8,13 +8,13 @@ type Metrics interface {
}
// LRUCache wraps hashicorp *lru.Cache and tracks cache metrics
type LRUCache struct {
type LRUCache[K comparable, V any] struct {
m Metrics
label string
inner *lru.Cache
inner *lru.Cache[K, V]
}
func (c *LRUCache) Get(key any) (value any, ok bool) {
func (c *LRUCache[K, V]) Get(key K) (value V, ok bool) {
value, ok = c.inner.Get(key)
if c.m != nil {
c.m.CacheGet(c.label, ok)
......@@ -22,7 +22,7 @@ func (c *LRUCache) Get(key any) (value any, ok bool) {
return value, ok
}
func (c *LRUCache) Add(key, value any) (evicted bool) {
func (c *LRUCache[K, V]) Add(key K, value V) (evicted bool) {
evicted = c.inner.Add(key, value)
if c.m != nil {
c.m.CacheAdd(c.label, c.inner.Len(), evicted)
......@@ -32,10 +32,10 @@ func (c *LRUCache) Add(key, value any) (evicted bool) {
// NewLRUCache creates a LRU cache with the given metrics, labeling the cache adds/gets.
// Metrics are optional: no metrics will be tracked if m == nil.
func NewLRUCache(m Metrics, label string, maxSize int) *LRUCache {
func NewLRUCache[K comparable, V any](m Metrics, label string, maxSize int) *LRUCache[K, V] {
// no errors if the size is positive
cache, _ := lru.New(maxSize)
return &LRUCache{
cache, _ := lru.New[K, V](maxSize)
return &LRUCache[K, V]{
m: m,
label: label,
inner: cache,
......
......@@ -106,19 +106,19 @@ type EthClient struct {
// cache receipts in bundles per block hash
// We cache the receipts fetching job to not lose progress when we have to retry the `Fetch` call
// common.Hash -> *receiptsFetchingJob
receiptsCache *caching.LRUCache
receiptsCache *caching.LRUCache[common.Hash, *receiptsFetchingJob]
// cache transactions in bundles per block hash
// common.Hash -> types.Transactions
transactionsCache *caching.LRUCache
transactionsCache *caching.LRUCache[common.Hash, types.Transactions]
// cache block headers of blocks by hash
// common.Hash -> *HeaderInfo
headersCache *caching.LRUCache
headersCache *caching.LRUCache[common.Hash, eth.BlockInfo]
// cache payloads by hash
// common.Hash -> *eth.ExecutionPayload
payloadsCache *caching.LRUCache
payloadsCache *caching.LRUCache[common.Hash, *eth.ExecutionPayload]
// availableReceiptMethods tracks which receipt methods can be used for fetching receipts
// This may be modified concurrently, but we don't lock since it's a single
......@@ -172,10 +172,10 @@ func NewEthClient(client client.RPC, log log.Logger, metrics caching.Metrics, co
mustBePostMerge: config.MustBePostMerge,
provKind: config.RPCProviderKind,
log: log,
receiptsCache: caching.NewLRUCache(metrics, "receipts", config.ReceiptsCacheSize),
transactionsCache: caching.NewLRUCache(metrics, "txs", config.TransactionsCacheSize),
headersCache: caching.NewLRUCache(metrics, "headers", config.HeadersCacheSize),
payloadsCache: caching.NewLRUCache(metrics, "payloads", config.PayloadsCacheSize),
receiptsCache: caching.NewLRUCache[common.Hash, *receiptsFetchingJob](metrics, "receipts", config.ReceiptsCacheSize),
transactionsCache: caching.NewLRUCache[common.Hash, types.Transactions](metrics, "txs", config.TransactionsCacheSize),
headersCache: caching.NewLRUCache[common.Hash, eth.BlockInfo](metrics, "headers", config.HeadersCacheSize),
payloadsCache: caching.NewLRUCache[common.Hash, *eth.ExecutionPayload](metrics, "payloads", config.PayloadsCacheSize),
availableReceiptMethods: AvailableReceiptsFetchingMethods(config.RPCProviderKind),
lastMethodsReset: time.Now(),
methodResetDuration: config.MethodResetDuration,
......@@ -292,7 +292,7 @@ func (s *EthClient) ChainID(ctx context.Context) (*big.Int, error) {
func (s *EthClient) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) {
if header, ok := s.headersCache.Get(hash); ok {
return header.(eth.BlockInfo), nil
return header, nil
}
return s.headerCall(ctx, "eth_getBlockByHash", hashID(hash))
}
......@@ -310,7 +310,7 @@ func (s *EthClient) InfoByLabel(ctx context.Context, label eth.BlockLabel) (eth.
func (s *EthClient) InfoAndTxsByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, types.Transactions, error) {
if header, ok := s.headersCache.Get(hash); ok {
if txs, ok := s.transactionsCache.Get(hash); ok {
return header.(eth.BlockInfo), txs.(types.Transactions), nil
return header, txs, nil
}
}
return s.blockCall(ctx, "eth_getBlockByHash", hashID(hash))
......@@ -328,7 +328,7 @@ func (s *EthClient) InfoAndTxsByLabel(ctx context.Context, label eth.BlockLabel)
func (s *EthClient) PayloadByHash(ctx context.Context, hash common.Hash) (*eth.ExecutionPayload, error) {
if payload, ok := s.payloadsCache.Get(hash); ok {
return payload.(*eth.ExecutionPayload), nil
return payload, nil
}
return s.payloadCall(ctx, "eth_getBlockByHash", hashID(hash))
}
......@@ -354,7 +354,7 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e
// The underlying fetcher uses the receipts hash to verify receipt integrity.
var job *receiptsFetchingJob
if v, ok := s.receiptsCache.Get(blockHash); ok {
job = v.(*receiptsFetchingJob)
job = v
} else {
txHashes := eth.TransactionsToHashes(txs)
job = NewReceiptsFetchingJob(s, s.client, s.maxBatchSize, eth.ToBlockID(info), info.ReceiptHash(), txHashes)
......
......@@ -56,7 +56,7 @@ type L1Client struct {
// cache L1BlockRef by hash
// common.Hash -> eth.L1BlockRef
l1BlockRefsCache *caching.LRUCache
l1BlockRefsCache *caching.LRUCache[common.Hash, eth.L1BlockRef]
}
// NewL1Client wraps a RPC with bindings to fetch L1 data, while logging errors, tracking metrics (optional), and caching.
......@@ -68,7 +68,7 @@ func NewL1Client(client client.RPC, log log.Logger, metrics caching.Metrics, con
return &L1Client{
EthClient: ethClient,
l1BlockRefsCache: caching.NewLRUCache(metrics, "blockrefs", config.L1BlockRefsCacheSize),
l1BlockRefsCache: caching.NewLRUCache[common.Hash, eth.L1BlockRef](metrics, "blockrefs", config.L1BlockRefsCacheSize),
}, nil
}
......@@ -105,7 +105,7 @@ func (s *L1Client) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1Bl
// We cache the block reference by hash as it is safe to assume collision will not occur.
func (s *L1Client) L1BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L1BlockRef, error) {
if v, ok := s.l1BlockRefsCache.Get(hash); ok {
return v.(eth.L1BlockRef), nil
return v, nil
}
info, err := s.InfoByHash(ctx, hash)
if err != nil {
......
......@@ -68,11 +68,11 @@ type L2Client struct {
// cache L2BlockRef by hash
// common.Hash -> eth.L2BlockRef
l2BlockRefsCache *caching.LRUCache
l2BlockRefsCache *caching.LRUCache[common.Hash, eth.L2BlockRef]
// cache SystemConfig by L2 hash
// common.Hash -> eth.SystemConfig
systemConfigsCache *caching.LRUCache
systemConfigsCache *caching.LRUCache[common.Hash, eth.SystemConfig]
}
// NewL2Client constructs a new L2Client instance. The L2Client is a thin wrapper around the EthClient with added functions
......@@ -87,8 +87,8 @@ func NewL2Client(client client.RPC, log log.Logger, metrics caching.Metrics, con
return &L2Client{
EthClient: ethClient,
rollupCfg: config.RollupCfg,
l2BlockRefsCache: caching.NewLRUCache(metrics, "blockrefs", config.L2BlockRefsCacheSize),
systemConfigsCache: caching.NewLRUCache(metrics, "systemconfigs", config.L1ConfigsCacheSize),
l2BlockRefsCache: caching.NewLRUCache[common.Hash, eth.L2BlockRef](metrics, "blockrefs", config.L2BlockRefsCacheSize),
systemConfigsCache: caching.NewLRUCache[common.Hash, eth.SystemConfig](metrics, "systemconfigs", config.L1ConfigsCacheSize),
}, nil
}
......@@ -131,7 +131,7 @@ func (s *L2Client) L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2Bl
// The returned BlockRef may not be in the canonical chain.
func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L2BlockRef, error) {
if ref, ok := s.l2BlockRefsCache.Get(hash); ok {
return ref.(eth.L2BlockRef), nil
return ref, nil
}
payload, err := s.PayloadByHash(ctx, hash)
......@@ -151,7 +151,7 @@ func (s *L2Client) L2BlockRefByHash(ctx context.Context, hash common.Hash) (eth.
// The returned [eth.SystemConfig] may not be in the canonical chain when the hash is not canonical.
func (s *L2Client) SystemConfigByL2Hash(ctx context.Context, hash common.Hash) (eth.SystemConfig, error) {
if ref, ok := s.systemConfigsCache.Get(hash); ok {
return ref.(eth.SystemConfig), nil
return ref, nil
}
payload, err := s.PayloadByHash(ctx, hash)
......
......@@ -2,123 +2,40 @@ package chainconfig
import (
"fmt"
"math/big"
"strconv"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/params"
)
var enabledFromBedrockBlock = uint64(0)
var OPGoerliChainConfig, OPSepoliaChainConfig, OPMainnetChainConfig *params.ChainConfig
var OPGoerliChainConfig = &params.ChainConfig{
ChainID: big.NewInt(420),
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(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,
},
func init() {
mustLoadConfig := func(chainID uint64) *params.ChainConfig {
cfg, err := params.LoadOPStackChainConfig(chainID)
if err != nil {
panic(err)
}
return cfg
}
OPGoerliChainConfig = mustLoadConfig(420)
OPSepoliaChainConfig = mustLoadConfig(11155420)
OPMainnetChainConfig = mustLoadConfig(10)
}
var L2ChainConfigsByName = map[string]*params.ChainConfig{
"goerli": OPGoerliChainConfig,
"sepolia": OPSepoliaChainConfig,
"mainnet": OPMainnetChainConfig,
var L2ChainConfigsByChainID = map[uint64]*params.ChainConfig{
420: OPGoerliChainConfig,
11155420: OPSepoliaChainConfig,
10: OPMainnetChainConfig,
}
func RollupConfigByChainID(chainID uint64) (*rollup.Config, error) {
network := chaincfg.L2ChainIDToNetworkName[strconv.FormatUint(chainID, 10)]
if network == "" {
return nil, fmt.Errorf("unknown chain ID: %d", chainID)
config, err := rollup.LoadOPStackRollupConfig(chainID)
if err != nil {
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) {
network := chaincfg.L2ChainIDToNetworkName[strconv.FormatUint(chainID, 10)]
chainConfig, ok := L2ChainConfigsByName[network]
if !ok {
return nil, fmt.Errorf("unknown network %s for chain ID %d", network, chainID)
}
return chainConfig, nil
return params.LoadOPStackChainConfig(chainID)
}
......@@ -21,7 +21,7 @@ func TestBootstrapClient(t *testing.T) {
L2ClaimBlockNumber: 1,
L2ChainID: chaincfg.Goerli.L2ChainID.Uint64(),
L2ChainConfig: chainconfig.OPGoerliChainConfig,
RollupConfig: &chaincfg.Goerli,
RollupConfig: chaincfg.Goerli,
}
mockOracle := &mockBoostrapOracle{bootInfo, false}
readBootInfo := NewBootstrapClient(mockOracle).BootInfo()
......@@ -36,7 +36,7 @@ func TestBootstrapClient_CustomChain(t *testing.T) {
L2ClaimBlockNumber: 1,
L2ChainID: CustomChainIDIndicator,
L2ChainConfig: chainconfig.OPGoerliChainConfig,
RollupConfig: &chaincfg.Goerli,
RollupConfig: chaincfg.Goerli,
}
mockOracle := &mockBoostrapOracle{bootInfo, true}
readBootInfo := NewBootstrapClient(mockOracle).BootInfo()
......
......@@ -161,7 +161,7 @@ func createOracleEngine(t *testing.T) (*OracleEngine, *stubEngineBackend) {
}
engine := OracleEngine{
backend: backend,
rollupCfg: &chaincfg.Goerli,
rollupCfg: chaincfg.Goerli,
}
return &engine, backend
}
......
......@@ -45,8 +45,10 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs())
rollupCfg, err := chaincfg.GetRollupConfig("op-goerli")
require.NoError(t, err)
defaultCfg := config.NewConfig(
&chaincfg.Goerli,
rollupCfg,
chainconfig.OPGoerliChainConfig,
common.HexToHash(l1HeadValue),
common.HexToHash(l2HeadValue),
......@@ -58,7 +60,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
func TestNetwork(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) {
......@@ -74,16 +76,17 @@ func TestNetwork(t *testing.T) {
genesisFile := writeValidGenesis(t)
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
expected := cfg
expected, err := chaincfg.GetRollupConfig(name)
require.NoError(t, err)
t.Run("Network_"+name, func(t *testing.T) {
args := replaceRequiredArg("--network", name)
cfg := configForArgs(t, args)
require.Equal(t, expected, *cfg.Rollup)
require.Equal(t, *expected, *cfg.Rollup)
})
}
}
......
......@@ -6,10 +6,11 @@ import (
"fmt"
"os"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
opnode "github.com/ethereum-optimism/optimism/op-node"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"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/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
......@@ -157,10 +158,15 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) {
var l2ChainConfig *params.ChainConfig
if l2GenesisPath == "" {
networkName := ctx.String(flags.Network.Name)
l2ChainConfig = chainconfig.L2ChainConfigsByName[networkName]
if l2ChainConfig == nil {
ch := chaincfg.ChainByName(networkName)
if ch == nil {
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 {
l2ChainConfig, err = loadChainConfigFromGenesis(l2GenesisPath)
}
......
......@@ -11,7 +11,7 @@ import (
)
var (
validRollupConfig = &chaincfg.Goerli
validRollupConfig = chaincfg.Goerli
validL2Genesis = params.GoerliChainConfig
validL1Head = common.Hash{0xaa}
validL2Head = common.Hash{0xbb}
......
......@@ -35,7 +35,7 @@ func Main(logger log.Logger, cfg *config.Config) error {
return fmt.Errorf("invalid config: %w", err)
}
opservice.ValidateEnvVars(flags.EnvVarPrefix, flags.Flags, logger)
cfg.Rollup.LogDescription(logger, chaincfg.L2ChainIDToNetworkName)
cfg.Rollup.LogDescription(logger, chaincfg.L2ChainIDToNetworkDisplayName)
ctx := context.Background()
if cfg.ServerMode {
......
......@@ -25,7 +25,7 @@ func TestServerMode(t *testing.T) {
l1Head := common.Hash{0x11}
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.ServerMode = true
......
......@@ -16,7 +16,7 @@ import (
func TestLocalPreimageSource(t *testing.T) {
cfg := &config.Config{
Rollup: &chaincfg.Goerli,
Rollup: chaincfg.Goerli,
L1Head: common.HexToHash("0x1111"),
L2OutputRoot: common.HexToHash("0x2222"),
L2Claim: common.HexToHash("0x3333"),
......
// Package clock provides an abstraction for time to enable testing of functionality that uses time as an input.
package clock
import "time"
import (
"context"
"time"
)
// 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 {
// Now provides the current local time. Equivalent to time.Now
Now() time.Time
......@@ -26,6 +30,10 @@ type Clock interface {
// NewTimer creates a new Timer that will send
// the current time on its channel after at least duration d.
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
......@@ -104,3 +112,14 @@ func (t *SystemTimer) Ch() <-chan time.Time {
func (s systemClock) AfterFunc(d time.Duration, f func()) Timer {
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 {
return t
}
func (s *DeterministicClock) SleepCtx(ctx context.Context, d time.Duration) error {
return sleepCtx(ctx, d, s)
}
func (s *DeterministicClock) addPending(t action) {
s.pending = append(s.pending, t)
select {
......
......@@ -315,3 +315,38 @@ func TestWaitForPending(t *testing.T) {
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
import (
"fmt"
"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.
// 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
for i, v := range values {
out.WriteString(v.String())
out.WriteString(string(v))
if i+1 < len(values) {
out.WriteString(", ")
}
......
......@@ -8,30 +8,15 @@ import (
// TestEnumString_MultipleInputs tests the EnumString function with multiple inputs.
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.
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.
func TestEnumString_EmptyString(t *testing.T) {
require.Equal(t, "", EnumString([]Stringered{}))
}
// 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{}))
require.Equal(t, "", EnumString([]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)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38689)
MIPS_Test:test_add_succeeds() (gas: 121593)
MIPS_Test:test_addi_succeeds() (gas: 121918)
MIPS_Test:test_addu_succeeds() (gas: 121601)
MIPS_Test:test_addui_succeeds() (gas: 121975)
MIPS_Test:test_and_succeeds() (gas: 121650)
MIPS_Test:test_andi_succeeds() (gas: 121792)
MIPS_Test:test_add_succeeds() (gas: 122197)
MIPS_Test:test_addiSign_succeeds() (gas: 122188)
MIPS_Test:test_addi_succeeds() (gas: 122385)
MIPS_Test:test_addu_succeeds() (gas: 122239)
MIPS_Test:test_addui_succeeds() (gas: 122447)
MIPS_Test:test_and_succeeds() (gas: 122258)
MIPS_Test:test_andi_succeeds() (gas: 122191)
MIPS_Test:test_beq_succeeds() (gas: 202355)
MIPS_Test:test_bgez_succeeds() (gas: 121484)
MIPS_Test:test_bgtz_succeeds() (gas: 121405)
......@@ -311,67 +312,67 @@ MIPS_Test:test_blez_succeeds() (gas: 121361)
MIPS_Test:test_bltz_succeeds() (gas: 121504)
MIPS_Test:test_bne_succeeds() (gas: 121570)
MIPS_Test:test_branch_inDelaySlot_fails() (gas: 85999)
MIPS_Test:test_brk_succeeds() (gas: 121531)
MIPS_Test:test_clo_succeeds() (gas: 121991)
MIPS_Test:test_clone_succeeds() (gas: 121484)
MIPS_Test:test_clz_succeeds() (gas: 122462)
MIPS_Test:test_div_succeeds() (gas: 121806)
MIPS_Test:test_divu_succeeds() (gas: 121762)
MIPS_Test:test_exit_succeeds() (gas: 121408)
MIPS_Test:test_fcntl_succeeds() (gas: 203129)
MIPS_Test:test_illegal_instruction_fails() (gas: 91175)
MIPS_Test:test_invalid_root_fails() (gas: 435678)
MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120492)
MIPS_Test:test_jal_succeeds() (gas: 120481)
MIPS_Test:test_jalr_succeeds() (gas: 121349)
MIPS_Test:test_jr_succeeds() (gas: 121094)
MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85345)
MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120236)
MIPS_Test:test_brk_succeeds() (gas: 121869)
MIPS_Test:test_clo_succeeds() (gas: 121926)
MIPS_Test:test_clone_succeeds() (gas: 121822)
MIPS_Test:test_clz_succeeds() (gas: 122397)
MIPS_Test:test_div_succeeds() (gas: 122376)
MIPS_Test:test_divu_succeeds() (gas: 122361)
MIPS_Test:test_exit_succeeds() (gas: 121746)
MIPS_Test:test_fcntl_succeeds() (gas: 203827)
MIPS_Test:test_illegal_instruction_fails() (gas: 91462)
MIPS_Test:test_invalid_root_fails() (gas: 435636)
MIPS_Test:test_jal_nonzeroRegion_succeeds() (gas: 120514)
MIPS_Test:test_jal_succeeds() (gas: 120503)
MIPS_Test:test_jalr_succeeds() (gas: 121622)
MIPS_Test:test_jr_succeeds() (gas: 121316)
MIPS_Test:test_jump_inDelaySlot_fails() (gas: 85367)
MIPS_Test:test_jump_nonzeroRegion_succeeds() (gas: 120258)
MIPS_Test:test_jump_succeeds() (gas: 120188)
MIPS_Test:test_lb_succeeds() (gas: 127346)
MIPS_Test:test_lbu_succeeds() (gas: 127222)
MIPS_Test:test_lh_succeeds() (gas: 127367)
MIPS_Test:test_lhu_succeeds() (gas: 127284)
MIPS_Test:test_ll_succeeds() (gas: 127304)
MIPS_Test:test_lui_succeeds() (gas: 121488)
MIPS_Test:test_lw_succeeds() (gas: 127158)
MIPS_Test:test_lwl_succeeds() (gas: 241434)
MIPS_Test:test_lwr_succeeds() (gas: 241722)
MIPS_Test:test_mfhi_succeeds() (gas: 121458)
MIPS_Test:test_mflo_succeeds() (gas: 121484)
MIPS_Test:test_mmap_succeeds() (gas: 118451)
MIPS_Test:test_movn_succeeds() (gas: 202409)
MIPS_Test:test_movz_succeeds() (gas: 202313)
MIPS_Test:test_mthi_succeeds() (gas: 121450)
MIPS_Test:test_mtlo_succeeds() (gas: 121478)
MIPS_Test:test_mul_succeeds() (gas: 121563)
MIPS_Test:test_mult_succeeds() (gas: 121667)
MIPS_Test:test_multu_succeeds() (gas: 121675)
MIPS_Test:test_nor_succeeds() (gas: 121697)
MIPS_Test:test_or_succeeds() (gas: 121657)
MIPS_Test:test_ori_succeeds() (gas: 121865)
MIPS_Test:test_preimage_read_succeeds() (gas: 233847)
MIPS_Test:test_preimage_write_succeeds() (gas: 126473)
MIPS_Test:test_lb_succeeds() (gas: 127429)
MIPS_Test:test_lbu_succeeds() (gas: 127327)
MIPS_Test:test_lh_succeeds() (gas: 127450)
MIPS_Test:test_lhu_succeeds() (gas: 127367)
MIPS_Test:test_ll_succeeds() (gas: 127589)
MIPS_Test:test_lui_succeeds() (gas: 121470)
MIPS_Test:test_lw_succeeds() (gas: 127218)
MIPS_Test:test_lwl_succeeds() (gas: 241600)
MIPS_Test:test_lwr_succeeds() (gas: 241888)
MIPS_Test:test_mfhi_succeeds() (gas: 121831)
MIPS_Test:test_mflo_succeeds() (gas: 121960)
MIPS_Test:test_mmap_succeeds() (gas: 118789)
MIPS_Test:test_movn_succeeds() (gas: 203027)
MIPS_Test:test_movz_succeeds() (gas: 202895)
MIPS_Test:test_mthi_succeeds() (gas: 121875)
MIPS_Test:test_mtlo_succeeds() (gas: 121983)
MIPS_Test:test_mul_succeeds() (gas: 121475)
MIPS_Test:test_mult_succeeds() (gas: 122179)
MIPS_Test:test_multu_succeeds() (gas: 122216)
MIPS_Test:test_nor_succeeds() (gas: 122308)
MIPS_Test:test_or_succeeds() (gas: 122265)
MIPS_Test:test_ori_succeeds() (gas: 122268)
MIPS_Test:test_preimage_read_succeeds() (gas: 234185)
MIPS_Test:test_preimage_write_succeeds() (gas: 126811)
MIPS_Test:test_prestate_exited_succeeds() (gas: 112992)
MIPS_Test:test_sb_succeeds() (gas: 159993)
MIPS_Test:test_sc_succeeds() (gas: 160187)
MIPS_Test:test_sh_succeeds() (gas: 160052)
MIPS_Test:test_sll_succeeds() (gas: 121456)
MIPS_Test:test_sllv_succeeds() (gas: 121646)
MIPS_Test:test_slt_succeeds() (gas: 203266)
MIPS_Test:test_sltu_succeeds() (gas: 121871)
MIPS_Test:test_sra_succeeds() (gas: 121763)
MIPS_Test:test_srav_succeeds() (gas: 121959)
MIPS_Test:test_srl_succeeds() (gas: 121514)
MIPS_Test:test_srlv_succeeds() (gas: 121707)
MIPS_Test:test_step_abi_succeeds() (gas: 57876)
MIPS_Test:test_sub_succeeds() (gas: 121696)
MIPS_Test:test_subu_succeeds() (gas: 121659)
MIPS_Test:test_sw_succeeds() (gas: 160027)
MIPS_Test:test_swl_succeeds() (gas: 160088)
MIPS_Test:test_swr_succeeds() (gas: 160163)
MIPS_Test:test_xor_succeeds() (gas: 121685)
MIPS_Test:test_xori_succeeds() (gas: 121916)
MIPS_Test:test_sb_succeeds() (gas: 160300)
MIPS_Test:test_sc_succeeds() (gas: 160494)
MIPS_Test:test_sh_succeeds() (gas: 160337)
MIPS_Test:test_sll_succeeds() (gas: 121436)
MIPS_Test:test_sllv_succeeds() (gas: 121665)
MIPS_Test:test_slt_succeeds() (gas: 204222)
MIPS_Test:test_sltu_succeeds() (gas: 122482)
MIPS_Test:test_sra_succeeds() (gas: 121687)
MIPS_Test:test_srav_succeeds() (gas: 121955)
MIPS_Test:test_srl_succeeds() (gas: 121518)
MIPS_Test:test_srlv_succeeds() (gas: 121683)
MIPS_Test:test_step_abi_succeeds() (gas: 58312)
MIPS_Test:test_sub_succeeds() (gas: 122292)
MIPS_Test:test_subu_succeeds() (gas: 122289)
MIPS_Test:test_sw_succeeds() (gas: 160312)
MIPS_Test:test_swl_succeeds() (gas: 160373)
MIPS_Test:test_swr_succeeds() (gas: 160448)
MIPS_Test:test_xor_succeeds() (gas: 122293)
MIPS_Test:test_xori_succeeds() (gas: 122345)
MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5733)
MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58889)
MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35845)
......
......@@ -76,7 +76,8 @@ contract Deploy is Deployer {
initializeL2OutputOracle();
initializeOptimismPortal();
setFaultGameImplementation();
setAlphabetFaultGameImplementation();
setCannonFaultGameImplementation();
transferProxyAdminOwnership();
transferDisputeGameFactoryOwnership();
......@@ -759,10 +760,13 @@ contract Deploy is Deployer {
}
/// @notice Sets the implementation for the `FAULT` game type in the `DisputeGameFactory`
function setFaultGameImplementation() public onlyDevnet broadcast {
// Create the absolute prestate dump
function setCannonFaultGameImplementation() public onlyDevnet broadcast {
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
Claim mipsAbsolutePrestate;
if (block.chainid == Chains.LocalDevnet || block.chainid == Chains.GethDevnet) {
// Fetch the absolute prestate dump
string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof.json");
bytes32 mipsAbsolutePrestate;
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
......@@ -771,35 +775,74 @@ contract Deploy is Deployer {
revert("Cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root.");
}
commands[2] = string.concat("cat ", filePath, " | jq -r .pre");
mipsAbsolutePrestate = abi.decode(vm.ffi(commands), (bytes32));
console.log("Absolute prestate: %s", vm.toString(mipsAbsolutePrestate));
mipsAbsolutePrestate = Claim.wrap(abi.decode(vm.ffi(commands), (bytes32)));
console.log(
"[Cannon Dispute Game] Using devnet MIPS Absolute prestate: %s",
vm.toString(Claim.unwrap(mipsAbsolutePrestate))
);
} else {
console.log(
"[Cannon Dispute Game] Using absolute prestate from config: %s", cfg.faultGameAbsolutePrestate()
);
mipsAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
}
// Set the Cannon FaultDisputeGame implementation in the factory.
_setFaultGameImplementation(
factory, GameTypes.FAULT, mipsAbsolutePrestate, IBigStepper(mustGetAddress("Mips")), cfg.faultGameMaxDepth()
);
}
/// @notice Sets the implementation for the alphabet game type in the `DisputeGameFactory`
function setAlphabetFaultGameImplementation() public onlyDevnet broadcast {
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
for (uint8 i; i < 2; i++) {
Claim absolutePrestate =
Claim.wrap(i == 0 ? bytes32(cfg.faultGameAbsolutePrestate()) : mipsAbsolutePrestate);
IBigStepper faultVm =
IBigStepper(i == 0 ? address(new AlphabetVM(absolutePrestate)) : mustGetAddress("Mips"));
GameType gameType = GameType.wrap(i);
if (address(factory.gameImpls(gameType)) == address(0)) {
factory.setImplementation(
gameType,
// Set the Alphabet FaultDisputeGame implementation in the factory.
Claim alphabetAbsolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
_setFaultGameImplementation(
factory,
GameType.wrap(255),
alphabetAbsolutePrestate,
IBigStepper(new AlphabetVM(alphabetAbsolutePrestate)),
4 // The max game depth of the alphabet game is always 4.
);
}
/// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
function _setFaultGameImplementation(
DisputeGameFactory _factory,
GameType _gameType,
Claim _absolutePrestate,
IBigStepper _faultVm,
uint256 _maxGameDepth
)
internal
{
if (address(_factory.gameImpls(_gameType)) == address(0)) {
_factory.setImplementation(
_gameType,
new FaultDisputeGame({
_gameType: gameType,
_absolutePrestate: absolutePrestate,
_maxGameDepth: i == 0 ? 4 : cfg.faultGameMaxDepth(), // The max depth of the alphabet game is always 4
_gameType: _gameType,
_absolutePrestate: _absolutePrestate,
_maxGameDepth: _maxGameDepth,
_gameDuration: Duration.wrap(uint64(cfg.faultGameMaxDuration())),
_vm: faultVm,
_vm: _faultVm,
_l2oo: L2OutputOracle(mustGetAddress("L2OutputOracleProxy")),
_blockOracle: BlockOracle(mustGetAddress("BlockOracle"))
})
);
uint8 rawGameType = GameType.unwrap(_gameType);
console.log(
"DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: %s | GameType: %s)",
i == 0 ? "AlphabetVM" : "MIPS",
vm.toString(i)
rawGameType == 0 ? "Cannon" : "Alphabet",
vm.toString(rawGameType)
);
} else {
console.log(
"[WARN] DisputeGameFactoryProxy: `FaultDisputeGame` implementation already set for game type: %s",
vm.toString(GameType.unwrap(_gameType))
);
}
}
}
}
......@@ -277,7 +277,8 @@ func main() {
checkErr(err, "Error creating secure trie")
// Put a "true" bool in the storage slot
state.UpdateStorage(common.Address{}, hash.Bytes(), []byte{0x01})
err = state.UpdateStorage(common.Address{}, hash.Bytes(), []byte{0x01})
checkErr(err, "Error updating storage")
// Create a secure trie for the world state
world, err := trie.NewStateTrie(
......@@ -294,7 +295,8 @@ func main() {
}
writer := new(bytes.Buffer)
checkErr(account.EncodeRLP(writer), "Error encoding account")
world.UpdateStorage(common.Address{}, predeploys.L2ToL1MessagePasserAddr.Bytes(), writer.Bytes())
err = world.UpdateStorage(common.Address{}, predeploys.L2ToL1MessagePasserAddr.Bytes(), writer.Bytes())
checkErr(err, "Error updating storage")
// Get the proof
var proof proofList
......
......@@ -67,7 +67,7 @@ contract MIPS {
}
/// @notice Extends the value leftwards with its most significant bit (sign extension).
function SE(uint32 _dat, uint32 _idx) internal pure returns (uint32) {
function SE(uint32 _dat, uint32 _idx) internal pure returns (uint32 out_) {
unchecked {
bool isSigned = (_dat >> (_idx - 1)) != 0;
uint256 signed = ((1 << (32 - _idx)) - 1) << _idx;
......@@ -771,78 +771,135 @@ contract MIPS {
}
/// @notice Execute an instruction.
function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32) {
function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32 out) {
unchecked {
uint32 opcode = insn >> 26; // 6-bits
uint32 func = insn & 0x3f; // 6-bits
if (opcode < 0x20) {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if (opcode >= 8 && opcode < 0xF) {
if (opcode == 8) func = 0x20; // addi
else if (opcode == 9) func = 0x21; // addiu
else if (opcode == 0xa) func = 0x2a; // slti
else if (opcode == 0xb) func = 0x2B; // sltiu
else if (opcode == 0xc) func = 0x24; // andi
else if (opcode == 0xd) func = 0x25; // ori
else if (opcode == 0xe) func = 0x26; // xori
opcode = 0;
}
// 0 is opcode SPECIAL
if (opcode == 0) {
uint32 shamt = (insn >> 6) & 0x1f;
if (func < 0x20) {
// jr/jalr/div + others
if (func >= 0x08) {
return rs;
}
// sll: Logical Shift Left
else if (func == 0x00) {
return rt << shamt;
}
// srl: Logical Shift Right
if (opcode == 0 || (opcode >= 8 && opcode < 0xF)) {
uint32 func = insn & 0x3f; // 6-bits
assembly {
// transform ArithLogI to SPECIAL
switch opcode
// addi
case 0x8 { func := 0x20 }
// addiu
case 0x9 { func := 0x21 }
// stli
case 0xA { func := 0x2A }
// sltiu
case 0xB { func := 0x2B }
// andi
case 0xC { func := 0x24 }
// ori
case 0xD { func := 0x25 }
// xori
case 0xE { func := 0x26 }
}
// sll
if (func == 0x00) {
return rt << ((insn >> 6) & 0x1F);
}
// srl
else if (func == 0x02) {
return rt >> shamt;
return rt >> ((insn >> 6) & 0x1F);
}
// sra: Arithmetic Shift Right
// sra
else if (func == 0x03) {
uint32 shamt = (insn >> 6) & 0x1F;
return SE(rt >> shamt, 32 - shamt);
}
// sllv: Variable Logical Shift Left
// sllv
else if (func == 0x04) {
return rt << (rs & 0x1F);
}
// srlv: Variable Logical Shift Right
else if (func == 0x06) {
// srlv
else if (func == 0x6) {
return rt >> (rs & 0x1F);
}
// srav: Variable Arithmetic Shift Right
// srav
else if (func == 0x07) {
return SE(rt >> rs, 32 - rs);
}
// functs in range [0x8, 0x1b] are handled specially by other functions
// Explicitly enumerate each funct in range to reduce code diff against Go Vm
// jr
else if (func == 0x08) {
return rs;
}
// jalr
else if (func == 0x09) {
return rs;
}
// R-type (ArithLog)
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// add or addu
if (func == 0x20 || func == 0x21) {
return rs + rt;
// movz
else if (func == 0x0a) {
return rs;
}
// movn
else if (func == 0x0b) {
return rs;
}
// syscall
else if (func == 0x0c) {
return rs;
}
// 0x0d - break not supported
// sync
else if (func == 0x0f) {
return rs;
}
// mfhi
else if (func == 0x10) {
return rs;
}
// mthi
else if (func == 0x11) {
return rs;
}
// mflo
else if (func == 0x12) {
return rs;
}
// mtlo
else if (func == 0x13) {
return rs;
}
// mult
else if (func == 0x18) {
return rs;
}
// multu
else if (func == 0x19) {
return rs;
}
// div
else if (func == 0x1a) {
return rs;
}
// divu
else if (func == 0x1b) {
return rs;
}
// The rest includes transformed R-type arith imm instructions
// add
else if (func == 0x20) {
return (rs + rt);
}
// addu
else if (func == 0x21) {
return (rs + rt);
}
// sub or subu
else if (func == 0x22 || func == 0x23) {
return rs - rt;
// sub
else if (func == 0x22) {
return (rs - rt);
}
// subu
else if (func == 0x23) {
return (rs - rt);
}
// and
else if (func == 0x24) {
return rs & rt;
return (rs & rt);
}
// or
else if (func == 0x25) {
......@@ -856,27 +913,26 @@ contract MIPS {
else if (func == 0x27) {
return ~(rs | rt);
}
// slt: Set to 1 if less than
// slti
else if (func == 0x2a) {
return int32(rs) < int32(rt) ? 1 : 0;
}
// sltu: Set to 1 if less than unsigned
else if (func == 0x2B) {
// sltiu
else if (func == 0x2b) {
return rs < rt ? 1 : 0;
} else {
revert("invalid instruction");
}
}
// lui: Load Upper Immediate
else if (opcode == 0xf) {
return rt << 16;
}
} else {
// SPECIAL2
else if (opcode == 0x1c) {
if (opcode == 0x1C) {
uint32 func = insn & 0x3f; // 6-bits
// mul
if (func == 2) {
if (func == 0x2) {
return uint32(int32(rs) * int32(rt));
}
// clo
if (func == 0x20 || func == 0x21) {
// clz, clo
else if (func == 0x20 || func == 0x21) {
if (func == 0x20) {
rs = ~rs;
}
......@@ -888,9 +944,12 @@ contract MIPS {
return i;
}
}
} else if (opcode < 0x28) {
// lui
else if (opcode == 0x0F) {
return rt << 16;
}
// lb
if (opcode == 0x20) {
else if (opcode == 0x20) {
return SE((mem >> (24 - (rs & 3) * 8)) & 0xFF, 8);
}
// lh
......@@ -921,7 +980,6 @@ contract MIPS {
uint32 mask = uint32(0xFFFFFFFF) >> (24 - (rs & 3) * 8);
return (rt & ~mask) | val;
}
}
// sb
else if (opcode == 0x28) {
uint32 val = (rt & 0xFF) << (24 - (rs & 3) * 8);
......@@ -957,8 +1015,10 @@ contract MIPS {
// sc
else if (opcode == 0x38) {
return rt;
} else {
revert("invalid instruction");
}
}
revert("invalid instruction");
}
}
......
......@@ -102,6 +102,26 @@ contract MIPS_Test is CommonTest {
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 {
uint16 imm = 40;
uint32 insn = encodeitype(0x9, 17, 8, imm); // addui t0, s1, 40
......@@ -305,15 +325,15 @@ contract MIPS_Test is CommonTest {
function test_slt_succeeds() external {
uint32 insn = encodespec(17, 18, 8, 0x2a); // slt t0, s1, s2
(MIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0);
state.registers[17] = 1200;
state.registers[18] = 490;
state.registers[17] = 0xFF_FF_FF_FE; // -2
state.registers[18] = 5;
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] = state.registers[17] < state.registers[18] ? 1 : 0; // t0
expect.registers[8] = 1; // t0
expect.registers[17] = state.registers[17];
expect.registers[18] = state.registers[18];
......@@ -326,7 +346,7 @@ contract MIPS_Test is CommonTest {
state.registers[18] = tmp;
expect.registers[17] = state.registers[17];
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);
assertEq(postState, outputState(expect), "unexpected post state");
}
......@@ -1127,14 +1147,14 @@ contract MIPS_Test is CommonTest {
uint8 shiftamt = 4;
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);
state.registers[9] = 0x20; // t1
state.registers[9] = 0x80_00_00_20; // t1
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] = state.registers[9] >> shiftamt;
expect.registers[8] = 0xF8_00_00_02; // 4 shifts while preserving sign bit
expect.registers[9] = state.registers[9];
bytes memory enc = encodeState(state);
......
......@@ -88,8 +88,8 @@ importers:
specifier: ^42.0.0
version: 42.0.0(eslint@8.47.0)
husky:
specifier: ^6.0.0
version: 6.0.0
specifier: ^8.0.3
version: 8.0.3
lerna:
specifier: ^7.1.5
version: 7.1.5
......@@ -109,8 +109,8 @@ importers:
specifier: ^10.2.0
version: 10.2.0
nx:
specifier: 16.7.1
version: 16.7.1
specifier: 16.7.2
version: 16.7.2
nyc:
specifier: ^15.1.0
version: 15.1.0
......@@ -2517,7 +2517,7 @@ packages:
dependencies:
'@lerna/child-process': 7.1.5
'@npmcli/run-script': 6.0.2
'@nx/devkit': 16.7.1(nx@16.7.1)
'@nx/devkit': 16.7.1(nx@16.7.2)
'@octokit/plugin-enterprise-rest': 6.0.1
'@octokit/rest': 19.0.11
byte-size: 8.1.1
......@@ -2553,7 +2553,7 @@ packages:
npm-packlist: 5.1.1
npm-registry-fetch: 14.0.5
npmlog: 6.0.2
nx: 16.7.1
nx: 16.7.2
p-map: 4.0.0
p-map-series: 2.1.0
p-queue: 6.6.2
......@@ -2838,10 +2838,10 @@ packages:
- supports-color
dev: true
/@nrwl/devkit@16.7.1(nx@16.7.1):
/@nrwl/devkit@16.7.1(nx@16.7.2):
resolution: {integrity: sha512-ysAgNju6o7QjG/ZHW0wIRJ8yWxjhErjqQ8GZ2Smqsb1myrr6UbYsuxaXjoOHI56fMmGyNPK04zzyNXXWQw/UAA==}
dependencies:
'@nx/devkit': 16.7.1(nx@16.7.1)
'@nx/devkit': 16.7.1(nx@16.7.2)
transitivePeerDependencies:
- nx
dev: true
......@@ -2854,11 +2854,11 @@ packages:
- debug
dev: true
/@nrwl/tao@16.7.1:
resolution: {integrity: sha512-oIjph3gm+FOB8mB2OTfCejQykpY+LGKdrGe5RpO3fBZzrkADHTdRWhaqaxktmGcRRt1AwMBofEv3mH4+VUOa/g==}
/@nrwl/tao@16.7.2:
resolution: {integrity: sha512-4Wc3ic5VtZL3t4qqCMJlEad/wWuFxNUX78U5ohEStN3UFFJIjwJJpKZYZDtxhaOLWUdXbk6CI3KfSIpWgwPdbQ==}
hasBin: true
dependencies:
nx: 16.7.1
nx: 16.7.2
tslib: 2.6.0
transitivePeerDependencies:
- '@swc-node/register'
......@@ -2866,23 +2866,23 @@ packages:
- debug
dev: true
/@nx/devkit@16.7.1(nx@16.7.1):
/@nx/devkit@16.7.1(nx@16.7.2):
resolution: {integrity: sha512-PASQGd1YhcAA/hpupCsSakP71Qh1pYle4dtF+wh3KDe2kdeM6BgccClapiGcXAI46JKLUGAbNYJ8pg7GEPY5Nw==}
peerDependencies:
nx: '>= 15 <= 17'
dependencies:
'@nrwl/devkit': 16.7.1(nx@16.7.1)
'@nrwl/devkit': 16.7.1(nx@16.7.2)
ejs: 3.1.9
enquirer: 2.3.6
ignore: 5.2.4
nx: 16.7.1
nx: 16.7.2
semver: 7.5.3
tmp: 0.2.1
tslib: 2.6.0
dev: true
/@nx/nx-darwin-arm64@16.7.1:
resolution: {integrity: sha512-g9N0eOYyirOnVZdpzsmby2VX2ovL/QBzjvT5OlLteKE4XmvksgSjQAhQeUUNY772AW6HoIK5MVxS2Jg3PECatQ==}
/@nx/nx-darwin-arm64@16.7.2:
resolution: {integrity: sha512-dkTHAzOTbqRHUQtnw7knEJq4ll6hew11u+9B0fThs9gC/X0iPK0eDXD4TqbIKEbcWAsxpuGiWPzGoNPo7Gwl9A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
......@@ -2890,8 +2890,8 @@ packages:
dev: true
optional: true
/@nx/nx-darwin-x64@16.7.1:
resolution: {integrity: sha512-ZoV4J4pR6z7YtBJoxrdNJTYJmjY653iA2M31PZL/WaS/3SHfzf4YYsnbLK5sF6GJI9n0XmOh3mPPHoJMYbQPIQ==}
/@nx/nx-darwin-x64@16.7.2:
resolution: {integrity: sha512-EKhjX7DCRIA5U8yAxIgGXeIFaq1dhgLJy8OAG4n1Ud8c21px+bBSrcZvv0ww5VoEulhggQ+c6fW1cjKtGgLknQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
......@@ -2899,8 +2899,8 @@ packages:
dev: true
optional: true
/@nx/nx-freebsd-x64@16.7.1:
resolution: {integrity: sha512-vpAi4FHtNwcBIjkRf86Oa98r09oN5OirCXT7cInvwCZWRMVUxT5WHs6gEMY1lvMlnTWqAVdWPcec5VipI9EhQA==}
/@nx/nx-freebsd-x64@16.7.2:
resolution: {integrity: sha512-3QhXZq0wxvi4lg1MJqwq72F7PE/d0Hcl3uwheenYQtwUvAFAmijC/Z4AVPSqbKJ+QaoqASnXRim9z3EIfeD+DQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [freebsd]
......@@ -2908,8 +2908,8 @@ packages:
dev: true
optional: true
/@nx/nx-linux-arm-gnueabihf@16.7.1:
resolution: {integrity: sha512-In9qaTpUPsle1jf20lBV/c0WrfSo4Qy64OleweZwIea3RW1TsQg4xxORoULtkU+6KB85XOb5Xd5G/zXpLRMykw==}
/@nx/nx-linux-arm-gnueabihf@16.7.2:
resolution: {integrity: sha512-7bny8NvE9iyfwRfq9/mOZjzMNWthT70Ce1N9suB2zdbgbLUEDPQQhBNbg969yT6/LbWMWuWZXeIbz/Fwndf9zA==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
......@@ -2917,8 +2917,8 @@ packages:
dev: true
optional: true
/@nx/nx-linux-arm64-gnu@16.7.1:
resolution: {integrity: sha512-+RXFQqGl5SLrcFl0zKAZOZ4pgA3yhXZnI2xYnuhlPOvuNT4Flc6cdPPz12uKhkWIg0nEBnbvsLDyD1PXDNxKJg==}
/@nx/nx-linux-arm64-gnu@16.7.2:
resolution: {integrity: sha512-+UdeFB1HY/3GU2+mflydFWpztghFRQiVzJV6MTcjtOzE3jfgXzz9TP580pDxozTvNSRPlblH07X+iB8DhVcB9w==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
......@@ -2926,8 +2926,8 @@ packages:
dev: true
optional: true
/@nx/nx-linux-arm64-musl@16.7.1:
resolution: {integrity: sha512-DiJ6Vpq9w2vaE9JgQs9M7K04QF75jAcqpuSlo25TYGU/GLiSZM6QpiAzsXhwZwFHfUjv0mL3iTmAcBmO1z9PBw==}
/@nx/nx-linux-arm64-musl@16.7.2:
resolution: {integrity: sha512-YfkWu+4GKXageuYiH5a77gIDAXnit5SIyfI+RWe/j04uFy171KnUt167DC417fv/fTGxeXY1tzOu112Y+x5ixw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
......@@ -2935,8 +2935,8 @@ packages:
dev: true
optional: true
/@nx/nx-linux-x64-gnu@16.7.1:
resolution: {integrity: sha512-fc/2whXm4ao91LFQ5++2rgYeTIitQKXkfTrHLKLuMynou2Qd+jMUZVcVk+avaHVPKKu6ALbCUQ0YSTGdEfEx3Q==}
/@nx/nx-linux-x64-gnu@16.7.2:
resolution: {integrity: sha512-/TtSa2rHR+1gNuALR1yafl4fzBK2/GAhosf+skn00OgwsJ0c8ie9tuuftlMo+2n3LcXY/IaPDaD7t6fln4qsQg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
......@@ -2944,8 +2944,8 @@ packages:
dev: true
optional: true
/@nx/nx-linux-x64-musl@16.7.1:
resolution: {integrity: sha512-3CzyUg5+/q83g/Pln71HPdkfjpU3dIBriiyuvJan8LwjKuhAdTFubAmu3CUp3ht1gZOdnwBQW1cdG1vx9EuBww==}
/@nx/nx-linux-x64-musl@16.7.2:
resolution: {integrity: sha512-VC638hxdWSA8VTDU9rAXjr60mmMP3ZyCUbSkJ+8ydEe83StMDY3PAXS5Hw3n/ouxDfCF9r1kWIGFe4g+emvfBw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
......@@ -2953,8 +2953,8 @@ packages:
dev: true
optional: true
/@nx/nx-win32-arm64-msvc@16.7.1:
resolution: {integrity: sha512-1uhQGwWEa76jQyEVohcB4g4H5Wn4YNLx49eJe1SHLwMgbPZZZ5PgnSzwECu+I9E/ZCRaCJk2sHiuRGxDa29Dzg==}
/@nx/nx-win32-arm64-msvc@16.7.2:
resolution: {integrity: sha512-sSUqgANLgQFFzKTvyMczh5D6xiqTQnB8daJTLX+QUCv5vO5+ZSwuVDyNfr6g/HV2+ak0M9/wVQUae11TgUIPYw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
......@@ -2962,8 +2962,8 @@ packages:
dev: true
optional: true
/@nx/nx-win32-x64-msvc@16.7.1:
resolution: {integrity: sha512-DLyME4yJKVhNTMgR3gDx7wVQ6ov6d9j2inGbTwoGoigMvzdaSqeoceMR5CSLOAeq9YBnH8FCbugTccg0iyZtvw==}
/@nx/nx-win32-x64-msvc@16.7.2:
resolution: {integrity: sha512-+n01cT9/P3o95x+FlRWYf9sFZ29ooxYD/WLcmxACeXN0V1bdbnZxKVSuJqrXZhmpHe7P+/+IRmniv9cdpkxz7g==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
......@@ -9861,8 +9861,9 @@ packages:
dependencies:
ms: 2.1.3
/husky@6.0.0:
resolution: {integrity: sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==}
/husky@8.0.3:
resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==}
engines: {node: '>=14'}
hasBin: true
dev: true
......@@ -10903,7 +10904,7 @@ packages:
'@lerna/child-process': 7.1.5
'@lerna/create': 7.1.5
'@npmcli/run-script': 6.0.2
'@nx/devkit': 16.7.1(nx@16.7.1)
'@nx/devkit': 16.7.1(nx@16.7.2)
'@octokit/plugin-enterprise-rest': 6.0.1
'@octokit/rest': 19.0.11
byte-size: 8.1.1
......@@ -10946,7 +10947,7 @@ packages:
npm-packlist: 5.1.1
npm-registry-fetch: 14.0.5
npmlog: 6.0.2
nx: 16.7.1
nx: 16.7.2
p-map: 4.0.0
p-map-series: 2.1.0
p-pipe: 3.1.0
......@@ -12574,8 +12575,8 @@ packages:
- debug
dev: true
/nx@16.7.1:
resolution: {integrity: sha512-WdzUpoyPMjYyIwYyxiNqGc76HTked/5DiAdVPEjL9MbjNZVwtFE+aMmyf+qS6GV64yNBlUrQphABfP3GiCbuSQ==}
/nx@16.7.2:
resolution: {integrity: sha512-T7cRC97qJ4H9fg498ZGwFQaTzJdLQaRp6DFUwzFo1B9qzR56A2tA3HBvT/huo85THaDX+/pcgLyeixJKEE5RPg==}
hasBin: true
requiresBuild: true
peerDependencies:
......@@ -12587,7 +12588,7 @@ packages:
'@swc/core':
optional: true
dependencies:
'@nrwl/tao': 16.7.1
'@nrwl/tao': 16.7.2
'@parcel/watcher': 2.0.4
'@yarnpkg/lockfile': 1.1.0
'@yarnpkg/parsers': 3.0.0-rc.46
......@@ -12623,16 +12624,16 @@ packages:
yargs: 17.7.2
yargs-parser: 21.1.1
optionalDependencies:
'@nx/nx-darwin-arm64': 16.7.1
'@nx/nx-darwin-x64': 16.7.1
'@nx/nx-freebsd-x64': 16.7.1
'@nx/nx-linux-arm-gnueabihf': 16.7.1
'@nx/nx-linux-arm64-gnu': 16.7.1
'@nx/nx-linux-arm64-musl': 16.7.1
'@nx/nx-linux-x64-gnu': 16.7.1
'@nx/nx-linux-x64-musl': 16.7.1
'@nx/nx-win32-arm64-msvc': 16.7.1
'@nx/nx-win32-x64-msvc': 16.7.1
'@nx/nx-darwin-arm64': 16.7.2
'@nx/nx-darwin-x64': 16.7.2
'@nx/nx-freebsd-x64': 16.7.2
'@nx/nx-linux-arm-gnueabihf': 16.7.2
'@nx/nx-linux-arm64-gnu': 16.7.2
'@nx/nx-linux-arm64-musl': 16.7.2
'@nx/nx-linux-x64-gnu': 16.7.2
'@nx/nx-linux-x64-musl': 16.7.2
'@nx/nx-win32-arm64-msvc': 16.7.2
'@nx/nx-win32-x64-msvc': 16.7.2
transitivePeerDependencies:
- debug
dev: true
......@@ -16585,7 +16586,7 @@ packages:
web3-utils: 4.0.4
web3-validator: 2.0.0
optionalDependencies:
web3-providers-ipc: 4.0.4
web3-providers-ipc: 4.0.5
transitivePeerDependencies:
- bufferutil
- encoding
......@@ -16599,6 +16600,15 @@ packages:
web3-types: 1.1.0
dev: false
/web3-errors@1.1.1:
resolution: {integrity: sha512-9IEhcympCJEK3Nmkz2oE/daKnOh+3CxHceuVWWRkHWKUfuIiJQgXAv9wRkPGk63JJTP/R9jtGmP+IbkScKoTBA==}
engines: {node: '>=14', npm: '>=6.12.0'}
requiresBuild: true
dependencies:
web3-types: 1.1.1
dev: false
optional: true
/web3-eth-abi@4.1.0:
resolution: {integrity: sha512-qd+zCGKi2YsL2KkbM5M8Qztles/WPOvFpw6Lg3a904DRIVxkIvWdQfoK0JbA6Vbt8DSVKCc4rpZ15D6I/wfBKQ==}
engines: {node: '>=14', npm: '>=6.12.0'}
......@@ -16766,14 +16776,14 @@ packages:
- encoding
dev: false
/web3-providers-ipc@4.0.4:
resolution: {integrity: sha512-mKzyPggFAw9t+SG0fwsMKoH2npfCzpeUeKfhqaTC/HLIquoI7djOyfV+MPe2p8w9QmstB+OGdRzirVWp2op11A==}
/web3-providers-ipc@4.0.5:
resolution: {integrity: sha512-1mJWqBnKbQ6UGHVxuXDJRpw4NwkpJ7NabyF2XBmzctzFHKvzE0X1dAocy3tih49J38d0vKrmubTOqxxkMpq49Q==}
engines: {node: '>=14', npm: '>=6.12.0'}
requiresBuild: true
dependencies:
web3-errors: 1.1.0
web3-types: 1.1.0
web3-utils: 4.0.4
web3-errors: 1.1.1
web3-types: 1.1.1
web3-utils: 4.0.5
dev: false
optional: true
......@@ -16810,6 +16820,13 @@ packages:
engines: {node: '>=14', npm: '>=6.12.0'}
dev: false
/web3-types@1.1.1:
resolution: {integrity: sha512-bXmIPJi/NPed43JBcya71gT+euZSMvfQx6NYv8G97PSNxR1HWwANYBKbamTZvzBbq10QCwQLh0hZw3tyOXuPFA==}
engines: {node: '>=14', npm: '>=6.12.0'}
requiresBuild: true
dev: false
optional: true
/web3-utils@1.10.1:
resolution: {integrity: sha512-r6iUUw/uMnNcWXjhRv33Nyrhxq3VGOPBXeSzxhOXIci4SvC/LPTpROY0uTrMX7ztKyODYrHp8WhTkEf+ZnHssw==}
engines: {node: '>=8.0.0'}
......@@ -16833,6 +16850,18 @@ packages:
web3-validator: 2.0.0
dev: false
/web3-utils@4.0.5:
resolution: {integrity: sha512-43xIM7rr3htYNzliVQLpWLQmEf4XX8IXgjvqLcEuC/xje14O5UQM4kamRCtz8v3JZN3X6QTfsV6Zgby67mVmCg==}
engines: {node: '>=14', npm: '>=6.12.0'}
requiresBuild: true
dependencies:
ethereum-cryptography: 2.1.2
web3-errors: 1.1.1
web3-types: 1.1.1
web3-validator: 2.0.1
dev: false
optional: true
/web3-validator@1.0.2:
resolution: {integrity: sha512-orx1CQAEnwJUnl/8iF2II2zSA4wiooNJvFmVE0Dbmt/kE370SugIDViQP76snhxtouG2AXzz4GyKbPCMlLGh/A==}
engines: {node: '>=14', npm: '>=6.12.0'}
......@@ -16855,6 +16884,19 @@ packages:
zod: 3.22.1
dev: false
/web3-validator@2.0.1:
resolution: {integrity: sha512-RIdZCNhceBEOQpmzcEk6K3qqLHRfDIMkg2PJe7yllpuEc0fa0cmUZgGUl1FEnioc5Rx9GBEE8eTllaneIAiiQQ==}
engines: {node: '>=14', npm: '>=6.12.0'}
requiresBuild: true
dependencies:
ethereum-cryptography: 2.1.2
util: 0.12.5
web3-errors: 1.1.1
web3-types: 1.1.1
zod: 3.22.1
dev: false
optional: true
/web3@4.0.3:
resolution: {integrity: sha512-rUMxui5f52yPWjiMRQV6xqIrTQSovYM2CNhl57y+xj/fGXNLbI1D5FsLPnUMZjMaFHJBTteaBxq/sTEaw/1jNA==}
engines: {node: '>=14.0.0', npm: '>=6.12.0'}
......
......@@ -17,14 +17,14 @@ import (
"sync"
"time"
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/websocket"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sync/semaphore"
sw "github.com/ethereum-optimism/optimism/proxyd/pkg/avg-sliding-window"
)
const (
......@@ -138,6 +138,7 @@ type Backend struct {
proxydIP string
skipPeerCountCheck bool
forcedCandidate bool
maxDegradedLatencyThreshold time.Duration
maxLatencyThreshold time.Duration
......@@ -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 {
return func(b *Backend) {
b.maxDegradedLatencyThreshold = maxDegradedLatencyThreshold
......@@ -678,6 +685,7 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch
latest: bg.Consensus.GetLatestBlockNumber(),
safe: bg.Consensus.GetSafeBlockNumber(),
finalized: bg.Consensus.GetFinalizedBlockNumber(),
maxBlockRange: bg.Consensus.maxBlockRange,
}
for i, req := range rpcReqs {
......@@ -692,6 +700,10 @@ func (bg *BackendGroup) Forward(ctx context.Context, rpcReqs []*RPCReq, isBatch
})
if errors.Is(err, ErrRewriteBlockOutOfRange) {
res.Error = ErrBlockOutOfRange
} else if errors.Is(err, ErrRewriteRangeTooLarge) {
res.Error = ErrInvalidParams(
fmt.Sprintf("block range greater than %d max", rctx.maxBlockRange),
)
} else {
res.Error = ErrParseErr
}
......
......@@ -93,6 +93,7 @@ type BackendConfig struct {
StripTrailingXFF bool `toml:"strip_trailing_xff"`
ConsensusSkipPeerCountCheck bool `toml:"consensus_skip_peer_count"`
ConsensusForcedCandidate bool `toml:"consensus_forced_candidate"`
ConsensusReceiptsTarget string `toml:"consensus_receipts_target"`
}
......@@ -107,6 +108,7 @@ type BackendGroupConfig struct {
ConsensusBanPeriod TOMLDuration `toml:"consensus_ban_period"`
ConsensusMaxUpdateThreshold TOMLDuration `toml:"consensus_max_update_threshold"`
ConsensusMaxBlockLag uint64 `toml:"consensus_max_block_lag"`
ConsensusMaxBlockRange uint64 `toml:"consensus_max_block_range"`
ConsensusMinPeerCount int `toml:"consensus_min_peer_count"`
}
......
......@@ -38,6 +38,7 @@ type ConsensusPoller struct {
banPeriod time.Duration
maxUpdateThreshold time.Duration
maxBlockLag uint64
maxBlockRange uint64
}
type backendState struct {
......@@ -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 {
return func(cp *ConsensusPoller) {
cp.minPeerCount = minPeerCount
......@@ -621,6 +628,10 @@ func (cp *ConsensusPoller) getConsensusCandidates() map[*Backend]*backendState {
for _, be := range cp.backendGroup.Backends {
bs := cp.getBackendState(be)
if be.forcedCandidate {
candidates[be] = bs
continue
}
if bs.IsBanned() {
continue
}
......
......@@ -9,7 +9,6 @@ require (
github.com/ethereum/go-ethereum v1.12.0
github.com/go-redis/redis/v8 v8.11.4
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/websocket v1.5.0
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
......@@ -17,6 +16,7 @@ require (
github.com/prometheus/client_golang v1.14.0
github.com/rs/cors v1.8.2
github.com/stretchr/testify v1.8.1
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
golang.org/x/sync v0.1.0
gopkg.in/yaml.v3 v3.0.1
)
......@@ -37,6 +37,8 @@ require (
github.com/deckarep/golang-set/v2 v2.1.0 // 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/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/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect
......@@ -44,8 +46,11 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // 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/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/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
......@@ -59,9 +64,10 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // 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/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/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.1.0 // indirect
......
......@@ -39,6 +39,7 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
......@@ -62,7 +63,9 @@ github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcju
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
......@@ -92,10 +95,14 @@ github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2
github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
......@@ -123,7 +130,9 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
......@@ -165,6 +174,7 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
......@@ -174,6 +184,9 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
......@@ -182,6 +195,8 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
......@@ -217,11 +232,13 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
......@@ -232,6 +249,8 @@ github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
......@@ -285,7 +304,9 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
......@@ -300,6 +321,8 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA=
github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
......@@ -318,10 +341,13 @@ github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03O
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
......@@ -332,6 +358,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
......@@ -432,6 +459,7 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
......@@ -498,6 +526,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
......
......@@ -142,6 +142,7 @@ func Start(config *Config) (*Server, func(), error) {
}
opts = append(opts, WithProxydIP(os.Getenv("PROXYD_IP")))
opts = append(opts, WithConsensusSkipPeerCountCheck(cfg.ConsensusSkipPeerCountCheck))
opts = append(opts, WithConsensusForcedCandidate(cfg.ConsensusForcedCandidate))
receiptsTarget, err := ReadFromEnvOrConfig(cfg.ConsensusReceiptsTarget)
if err != nil {
......@@ -308,6 +309,9 @@ func Start(config *Config) (*Server, func(), error) {
if bgcfg.ConsensusMinPeerCount > 0 {
copts = append(copts, WithMinPeerCount(uint64(bgcfg.ConsensusMinPeerCount)))
}
if bgcfg.ConsensusMaxBlockRange > 0 {
copts = append(copts, WithMaxBlockRange(bgcfg.ConsensusMaxBlockRange))
}
cp := NewConsensusPoller(bg, copts...)
bg.Consensus = cp
......
......@@ -12,6 +12,7 @@ type RewriteContext struct {
latest hexutil.Uint64
safe hexutil.Uint64
finalized hexutil.Uint64
maxBlockRange uint64
}
type RewriteResult uint8
......@@ -32,6 +33,7 @@ const (
var (
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
......@@ -121,6 +123,15 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
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")
if err != nil {
return RewriteOverrideError, err
......@@ -131,6 +142,20 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
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 modifiedFrom || modifiedTo {
paramsRaw, err := json.Marshal(p)
......@@ -144,6 +169,21 @@ func rewriteRange(rctx RewriteContext, req *RPCReq, res *RPCRes, pos int) (Rewri
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) {
if m[key] == nil || m[key] == "" {
return false, nil
......
......@@ -48,7 +48,7 @@ func TestRewriteRequest(t *testing.T) {
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"fromBlock": hexutil.Uint64(55).String()}})},
res: nil,
},
expected: RewriteNone,
expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) {
var p []map[string]interface{}
err := json.Unmarshal(args.req.Params, &p)
......@@ -88,7 +88,7 @@ func TestRewriteRequest(t *testing.T) {
req: &RPCReq{Method: "eth_getLogs", Params: mustMarshalJSON([]map[string]interface{}{{"toBlock": hexutil.Uint64(55).String()}})},
res: nil,
},
expected: RewriteNone,
expected: RewriteOverrideRequest,
check: func(t *testing.T, args args) {
var p []map[string]interface{}
err := json.Unmarshal(args.req.Params, &p)
......@@ -148,6 +148,62 @@ func TestRewriteRequest(t *testing.T) {
expected: RewriteOverrideError,
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 */
{
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