diff --git a/.dockerignore b/.dockerignore index 8e668a7a62..05cec369d9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,12 +15,8 @@ solgen/go target/**/* brotli/buildfiles/**/* -# these go to different docker images -testnode-scripts/node_modules -blockscout/**/* - # these are used by environment outside the docker: -test-node.bash +nitro-testnode/**/* # Arbitrator ignores diff --git a/.github/workflows/arbitrator-ci.yml b/.github/workflows/arbitrator-ci.yml index 4eac174d29..e11f5511a1 100644 --- a/.github/workflows/arbitrator-ci.yml +++ b/.github/workflows/arbitrator-ci.yml @@ -1,4 +1,5 @@ -name: CI +name: Arbitrator CI +run-name: Arbitrator CI triggered from @${{ github.actor }} of ${{ github.head_ref }} on: workflow_dispatch: @@ -37,7 +38,7 @@ jobs: - name: Install go uses: actions/setup-go@v2 with: - go-version: 1.19.x + go-version: 1.20.x - name: Setup nodejs uses: actions/setup-node@v2 @@ -109,12 +110,12 @@ jobs: target/lib/libbrotlicommon-static.a target/lib/libbrotlienc-static.a target/lib/libbrotlidec-static.a - key: ${{ runner.os }}-brotli-2-${{ hashFiles('build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }} + key: ${{ runner.os }}-brotli-3-${{ hashFiles('scripts/build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }} restore-keys: ${{ runner.os }}-brotli-2- - name: Build cbrotli-local if: steps.cache-cbrotli.outputs.cache-hit != 'true' - run: ./build-brotli.sh -l + run: ./scripts/build-brotli.sh -l - name: Setup emsdk if: steps.cache-cbrotli.outputs.cache-hit != 'true' @@ -130,7 +131,7 @@ jobs: - name: Build cbrotli-wasm if: steps.cache-cbrotli.outputs.cache-hit != 'true' - run: ./build-brotli.sh -w + run: ./scripts/build-brotli.sh -w - name: Add wabt to path run: echo "$HOME/wabt-prefix/bin" >> "$GITHUB_PATH" diff --git a/.github/workflows/arbitrator-skip-ci.yml b/.github/workflows/arbitrator-skip-ci.yml index 87978ca2f8..6dfd962ee6 100644 --- a/.github/workflows/arbitrator-skip-ci.yml +++ b/.github/workflows/arbitrator-skip-ci.yml @@ -1,4 +1,5 @@ -name: CI +name: Arbitrator skip CI +run-name: Arbitrator skip CI triggered from @${{ github.actor }} of ${{ github.head_ref }} on: pull_request: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b341d532e..e1a591b720 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,5 @@ -name: CI +name: Go tests CI +run-name: Go tests CI triggered from @${{ github.actor }} of ${{ github.head_ref }} on: workflow_dispatch: @@ -44,7 +45,7 @@ jobs: - name: Install go uses: actions/setup-go@v2 with: - go-version: 1.19.x + go-version: 1.20.x - name: Install wasm-ld run: | @@ -105,16 +106,16 @@ jobs: target/lib/libbrotlicommon-static.a target/lib/libbrotlienc-static.a target/lib/libbrotlidec-static.a - key: ${{ runner.os }}-brotli-${{ hashFiles('build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }}-${{ matrix.test-mode }} + key: ${{ runner.os }}-brotli-${{ hashFiles('scripts/build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }}-${{ matrix.test-mode }} restore-keys: ${{ runner.os }}-brotli- - name: Build cbrotli-local if: steps.cache-cbrotli.outputs.cache-hit != 'true' - run: ./build-brotli.sh -l + run: ./scripts/build-brotli.sh -l - name: Build cbrotli-wasm in docker if: steps.cache-cbrotli.outputs.cache-hit != 'true' - run: ./build-brotli.sh -w -d + run: ./scripts/build-brotli.sh -w -d - name: Build run: make build test-go-deps -j diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3e2c1214a3..92411d17e2 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -68,7 +68,7 @@ jobs: - name: Install go uses: actions/setup-go@v2 with: - go-version: 1.19.x + go-version: 1.20.x - name: Install rust stable uses: actions-rs/toolchain@v1 @@ -108,12 +108,12 @@ jobs: target/lib/libbrotlicommon-static.a target/lib/libbrotlienc-static.a target/lib/libbrotlidec-static.a - key: ${{ runner.os }}-brotli-${{ hashFiles('build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }} + key: ${{ runner.os }}-brotli-3a-${{ hashFiles('scripts/build-brotli.sh') }}-${{ hashFiles('.github/workflows/arbitrator-ci.yaml') }} restore-keys: ${{ runner.os }}-brotli- - name: Build cbrotli-local if: steps.cache-cbrotli.outputs.cache-hit != 'true' - run: ./build-brotli.sh -l + run: ./scripts/build-brotli.sh -l - name: Cache Build Products uses: actions/cache@v3 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index fb4d7466a4..cf5fdd5ca9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,5 @@ -name: CI +name: Docker build CI +run-name: Docker build CI triggered from @${{ github.actor }} of ${{ github.head_ref }} on: workflow_dispatch: diff --git a/.gitmodules b/.gitmodules index e1c15431c1..7c78791c78 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,9 +14,9 @@ path = contracts url = https://github.com/OffchainLabs/nitro-contracts.git branch = develop -[submodule "blockscout"] - path = blockscout - url = https://github.com/OffchainLabs/blockscout.git [submodule "arbitrator/wasm-testsuite/testsuite"] path = arbitrator/wasm-testsuite/testsuite url = https://github.com/WebAssembly/testsuite.git +[submodule "nitro-testnode"] + path = nitro-testnode + url = https://github.com/OffchainLabs/nitro-testnode.git diff --git a/Dockerfile b/Dockerfile index 4043313893..12010d5dac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,20 +6,20 @@ RUN apt-get update && \ cd emsdk && \ ./emsdk install 3.1.7 && \ ./emsdk activate 3.1.7 -COPY build-brotli.sh . +COPY scripts/build-brotli.sh scripts/ COPY brotli brotli -RUN cd emsdk && . ./emsdk_env.sh && cd .. && ./build-brotli.sh -w -t install/ +RUN cd emsdk && . ./emsdk_env.sh && cd .. && ./scripts/build-brotli.sh -w -t /workspace/install/ FROM scratch as brotli-wasm-export COPY --from=brotli-wasm-builder /workspace/install/ / FROM debian:bullseye-slim as brotli-library-builder WORKDIR /workspace -COPY build-brotli.sh . +COPY scripts/build-brotli.sh scripts/ COPY brotli brotli RUN apt-get update && \ apt-get install -y cmake make gcc git && \ - ./build-brotli.sh -l -t install/ + ./scripts/build-brotli.sh -l -t /workspace/install/ FROM scratch as brotli-library-export COPY --from=brotli-library-builder /workspace/install/ / @@ -53,7 +53,7 @@ COPY --from=wasm-libs-builder /workspace/ / FROM wasm-base as wasm-bin-builder # pinned go version -RUN curl -L https://golang.org/dl/go1.19.linux-`dpkg --print-architecture`.tar.gz | tar -C /usr/local -xzf - +RUN curl -L https://golang.org/dl/go1.20.linux-`dpkg --print-architecture`.tar.gz | tar -C /usr/local -xzf - COPY ./Makefile ./go.mod ./go.sum ./ COPY ./arbcompress ./arbcompress COPY ./arbos ./arbos @@ -146,7 +146,7 @@ FROM debian:bullseye-slim as machine-versions RUN apt-get update && apt-get install -y unzip wget curl WORKDIR /workspace/machines # Download WAVM machines -COPY ./testnode-scripts/download-machine.sh . +COPY ./scripts/download-machine.sh . #RUN ./download-machine.sh consensus-v1-rc1 0xbb9d58e9527566138b682f3a207c0976d5359837f6e330f4017434cca983ff41 #RUN ./download-machine.sh consensus-v2.1 0x9d68e40c47e3b87a8a7e6368cc52915720a6484bb2f47ceabad7e573e3a11232 #RUN ./download-machine.sh consensus-v3 0x53c288a0ca7100c0f2db8ab19508763a51c7fd1be125d376d940a65378acaee7 @@ -161,7 +161,7 @@ COPY ./testnode-scripts/download-machine.sh . RUN ./download-machine.sh consensus-v10 0x6b94a7fc388fd8ef3def759297828dc311761e88d8179c7ee8d3887dc554f3c3 RUN ./download-machine.sh consensus-v10.1 0xda4e3ad5e7feacb817c21c8d0220da7650fe9051ece68a3f0b1c5d38bbb27b21 -FROM golang:1.19-bullseye as node-builder +FROM golang:1.20-bullseye as node-builder WORKDIR /workspace ARG version="" ARG datetime="" @@ -188,11 +188,11 @@ RUN NITRO_BUILD_IGNORE_TIMESTAMPS=1 make build FROM node-builder as fuzz-builder RUN mkdir fuzzers/ -RUN ./fuzz.bash --build --binary-path /workspace/fuzzers/ +RUN ./scripts/fuzz.bash --build --binary-path /workspace/fuzzers/ FROM debian:bullseye-slim as nitro-fuzzer COPY --from=fuzz-builder /workspace/fuzzers/*.fuzz /usr/local/bin/ -COPY ./fuzz.bash /usr/local/bin +COPY ./scripts/fuzz.bash /usr/local/bin RUN mkdir /fuzzcache ENTRYPOINT [ "/usr/local/bin/fuzz.bash", "--binary-path", "/usr/local/bin/", "--fuzzcache-path", "/fuzzcache" ] @@ -215,7 +215,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ chown -R user:user /home/user && \ chmod -R 555 /home/user/target/machines && \ apt-get clean && \ - rm -rf /var/lib/apt/lists/* /usr/share/doc/* && \ + rm -rf /var/lib/apt/lists/* /usr/share/doc/* /var/cache/ldconfig/aux-cache /usr/lib/python3.9/__pycache__/ /usr/lib/python3.9/*/__pycache__/ /var/log/* && \ nitro --version USER user @@ -234,7 +234,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ node-ws vim-tiny python3 \ dnsutils && \ apt-get clean && \ - rm -rf /var/lib/apt/lists/* /usr/share/doc/* && \ + rm -rf /var/lib/apt/lists/* /usr/share/doc/* /var/cache/ldconfig/aux-cache /usr/lib/python3.9/__pycache__/ /usr/lib/python3.9/*/__pycache__/ /var/log/* && \ nitro --version USER user @@ -258,7 +258,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ adduser user sudo && \ echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ apt-get clean && \ - rm -rf /var/lib/apt/lists/* /usr/share/doc/* && \ + rm -rf /var/lib/apt/lists/* /usr/share/doc/* /var/cache/ldconfig/aux-cache /usr/lib/python3.9/__pycache__/ /usr/lib/python3.9/*/__pycache__/ /var/log/* && \ nitro --version USER user diff --git a/Makefile b/Makefile index af26256a9a..4b6928151f 100644 --- a/Makefile +++ b/Makefile @@ -332,23 +332,23 @@ contracts/test/prover/proofs/%.json: $(arbitrator_cases)/%.wasm $(arbitrator_pro @touch $@ .make/cbrotli-lib: $(DEP_PREDICATE) $(ORDER_ONLY_PREDICATE) .make - test -f target/include/brotli/encode.h || ./build-brotli.sh -l - test -f target/include/brotli/decode.h || ./build-brotli.sh -l - test -f target/lib/libbrotlicommon-static.a || ./build-brotli.sh -l - test -f target/lib/libbrotlienc-static.a || ./build-brotli.sh -l - test -f target/lib/libbrotlidec-static.a || ./build-brotli.sh -l + test -f target/include/brotli/encode.h || ./scripts/build-brotli.sh -l + test -f target/include/brotli/decode.h || ./scripts/build-brotli.sh -l + test -f target/lib/libbrotlicommon-static.a || ./scripts/build-brotli.sh -l + test -f target/lib/libbrotlienc-static.a || ./scripts/build-brotli.sh -l + test -f target/lib/libbrotlidec-static.a || ./scripts/build-brotli.sh -l @touch $@ .make/cbrotli-wasm: $(DEP_PREDICATE) $(ORDER_ONLY_PREDICATE) .make - test -f target/lib-wasm/libbrotlicommon-static.a || ./build-brotli.sh -w -d - test -f target/lib-wasm/libbrotlienc-static.a || ./build-brotli.sh -w -d - test -f target/lib-wasm/libbrotlidec-static.a || ./build-brotli.sh -w -d + test -f target/lib-wasm/libbrotlicommon-static.a || ./scripts/build-brotli.sh -w -d + test -f target/lib-wasm/libbrotlienc-static.a || ./scripts/build-brotli.sh -w -d + test -f target/lib-wasm/libbrotlidec-static.a || ./scripts/build-brotli.sh -w -d @touch $@ .make/wasm-lib: $(DEP_PREDICATE) $(ORDER_ONLY_PREDICATE) .make - test -f arbitrator/wasm-libraries/soft-float/bindings32.o || ./build-brotli.sh -f -d -t . - test -f arbitrator/wasm-libraries/soft-float/bindings64.o || ./build-brotli.sh -f -d -t . - test -f arbitrator/wasm-libraries/soft-float/SoftFloat/build/Wasm-Clang/softfloat.a || ./build-brotli.sh -f -d -t . + test -f arbitrator/wasm-libraries/soft-float/bindings32.o || ./scripts/build-brotli.sh -f -d -t . + test -f arbitrator/wasm-libraries/soft-float/bindings64.o || ./scripts/build-brotli.sh -f -d -t . + test -f arbitrator/wasm-libraries/soft-float/SoftFloat/build/Wasm-Clang/softfloat.a || ./scripts/build-brotli.sh -f -d -t . @touch $@ .make: diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 939b329d21..41522a82bb 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "addr2line" version = "0.17.0" @@ -175,7 +169,7 @@ checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -361,7 +355,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn", + "syn 1.0.76", ] [[package]] @@ -372,7 +366,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -407,7 +401,7 @@ checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -428,7 +422,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -518,6 +512,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -578,7 +578,7 @@ checksum = "3c7090af3d300424caa81976b8c97bca41cd70e861272c072e188ae082fb49f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -884,25 +884,26 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "ouroboros" -version = "0.15.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" +checksum = "e6a6d0919a92ba28d8109a103e0de08f89706be0eeaad1130fd1a34030dee84a" dependencies = [ "aliasable", "ouroboros_macro", + "static_assertions", ] [[package]] name = "ouroboros_macro" -version = "0.15.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" +checksum = "46bc2307dc3420554ae349230dac4969c66d7c2feead3a8cab05ea0c604daca6" dependencies = [ - "Inflector", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -978,7 +979,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.76", "version_check", ] @@ -995,11 +996,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1048,14 +1049,14 @@ checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1191,7 +1192,7 @@ checksum = "6eaedadc88b53e36dd32d940ed21ae4d850d5916f2581526921f553a72ac34c4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1285,7 +1286,7 @@ checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1319,7 +1320,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1390,11 +1391,11 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1408,6 +1409,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "target-lexicon" version = "0.12.4" @@ -1440,7 +1452,7 @@ checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1463,7 +1475,7 @@ checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1487,6 +1499,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + [[package]] name = "unicode-segmentation" version = "1.8.0" @@ -1544,7 +1562,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.76", "wasm-bindgen-shared", ] @@ -1568,7 +1586,7 @@ checksum = "c5020cfa87c7cecefef118055d44e3c1fc122c7ec25701d528ee458a0b45f38f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] @@ -1589,7 +1607,7 @@ checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1711,7 +1729,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.76", ] [[package]] diff --git a/arbitrator/jit/Cargo.toml b/arbitrator/jit/Cargo.toml index 23cc3becfe..75b3e3a74c 100644 --- a/arbitrator/jit/Cargo.toml +++ b/arbitrator/jit/Cargo.toml @@ -17,7 +17,7 @@ hex = "0.4.3" structopt = "0.3.26" sha3 = "0.9.1" libc = "0.2.132" -ouroboros = "0.15.5" +ouroboros = "0.16.0" [features] llvm = ["dep:wasmer-compiler-llvm"] diff --git a/arbitrator/jit/src/gostack.rs b/arbitrator/jit/src/gostack.rs index 45000ec034..80fccf179c 100644 --- a/arbitrator/jit/src/gostack.rs +++ b/arbitrator/jit/src/gostack.rs @@ -1,6 +1,8 @@ // Copyright 2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE +#![allow(clippy::useless_transmute)] + use crate::{ machine::{WasmEnv, WasmEnvMut}, syscall::JsValue, diff --git a/arbitrator/jit/src/test.rs b/arbitrator/jit/src/test.rs index e3b276f3f2..517c8596c0 100644 --- a/arbitrator/jit/src/test.rs +++ b/arbitrator/jit/src/test.rs @@ -12,7 +12,7 @@ fn test_crate() -> eyre::Result<()> { let source = std::fs::read("programs/pure/main.wat")?; let mut store = Store::default(); - let module = Module::new(&store, &source)?; + let module = Module::new(&store, source)?; let imports = imports! {}; let instance = Instance::new(&mut store, &module, &imports)?; diff --git a/arbnode/batch_poster.go b/arbnode/batch_poster.go index 51908b7524..3e5e6a738f 100644 --- a/arbnode/batch_poster.go +++ b/arbnode/batch_poster.go @@ -248,9 +248,10 @@ type batchSegments struct { } type buildingBatch struct { - segments *batchSegments - startMsgCount arbutil.MessageIndex - msgCount arbutil.MessageIndex + segments *batchSegments + startMsgCount arbutil.MessageIndex + msgCount arbutil.MessageIndex + haveUsefulMessage bool } func newBatchSegments(firstDelayed uint64, config *BatchPosterConfig, backlog uint64) *batchSegments { @@ -585,11 +586,10 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) if err != nil { return false, err } - nextMessageTime := time.Unix(int64(firstMsg.Message.Header.Timestamp), 0) + firstMsgTime := time.Unix(int64(firstMsg.Message.Header.Timestamp), 0) config := b.config() - forcePostBatch := time.Since(nextMessageTime) >= config.MaxBatchPostDelay - haveUsefulMessage := false + forcePostBatch := time.Since(firstMsgTime) >= config.MaxBatchPostDelay for b.building.msgCount < msgCount { msg, err := b.streamer.GetMessage(b.building.msgCount) @@ -608,16 +608,16 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) if !config.WaitForMaxBatchPostDelay { forcePostBatch = true } - haveUsefulMessage = true + b.building.haveUsefulMessage = true break } if msg.Message.Header.Kind != arbostypes.L1MessageType_BatchPostingReport { - haveUsefulMessage = true + b.building.haveUsefulMessage = true } b.building.msgCount++ } - if !forcePostBatch || !haveUsefulMessage { + if !forcePostBatch || !b.building.haveUsefulMessage { // the batch isn't full yet and we've posted a batch recently // don't post anything for now return false, nil @@ -659,7 +659,7 @@ func (b *BatchPoster) maybePostSequencerBatch(ctx context.Context) (bool, error) DelayedMessageCount: b.building.segments.delayedMsg, NextSeqNum: batchPosition.NextSeqNum + 1, } - err = b.dataPoster.PostTransaction(ctx, nextMessageTime, nonce, newMeta, b.seqInboxAddr, data, gasLimit) + err = b.dataPoster.PostTransaction(ctx, firstMsgTime, nonce, newMeta, b.seqInboxAddr, data, gasLimit) if err != nil { return false, err } diff --git a/arbnode/dataposter/data_poster.go b/arbnode/dataposter/data_poster.go index 17b6e75031..ff0dcfebcf 100644 --- a/arbnode/dataposter/data_poster.go +++ b/arbnode/dataposter/data_poster.go @@ -222,6 +222,9 @@ func (p *DataPoster[Meta]) getFeeAndTipCaps(ctx context.Context, gasLimit uint64 if err != nil { return nil, nil, err } + if latestHeader.BaseFee == nil { + return nil, nil, fmt.Errorf("latest parent chain block %v missing BaseFee (either the parent chain does not have EIP-1559 or the parent chain node is not synced)", latestHeader.Number) + } newFeeCap := new(big.Int).Mul(latestHeader.BaseFee, big.NewInt(2)) newFeeCap = arbmath.BigMax(newFeeCap, arbmath.FloatToBig(config.MinFeeCapGwei*params.GWei)) diff --git a/arbnode/delayed.go b/arbnode/delayed.go index 2995cc3d2f..f2c3d62004 100644 --- a/arbnode/delayed.go +++ b/arbnode/delayed.go @@ -195,7 +195,8 @@ func (b *DelayedBridge) logsToDeliveredMessages(ctx context.Context, logs []type } requestId := common.BigToHash(parsedLog.MessageIndex) - parentChainBlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, b.client, parsedLog.Raw.BlockNumber) + parentChainBlockNumber := parsedLog.Raw.BlockNumber + l1BlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, b.client, parentChainBlockNumber) if err != nil { return nil, err } @@ -206,14 +207,14 @@ func (b *DelayedBridge) logsToDeliveredMessages(ctx context.Context, logs []type Header: &arbostypes.L1IncomingMessageHeader{ Kind: parsedLog.Kind, Poster: parsedLog.Sender, - BlockNumber: parentChainBlockNumber, + BlockNumber: l1BlockNumber, Timestamp: parsedLog.Timestamp, RequestId: &requestId, L1BaseFee: parsedLog.BaseFeeL1, }, L2msg: data, }, - ParentChainBlockNumber: parentChainBlockNumber, + ParentChainBlockNumber: parsedLog.Raw.BlockNumber, } err = msg.Message.FillInBatchGasCost(batchFetcher) if err != nil { diff --git a/arbnode/delayed_seq_reorg_test.go b/arbnode/delayed_seq_reorg_test.go index a34b83369f..a28eebb5dc 100644 --- a/arbnode/delayed_seq_reorg_test.go +++ b/arbnode/delayed_seq_reorg_test.go @@ -54,48 +54,48 @@ func TestSequencerReorgFromDelayed(t *testing.T) { serializedInitMsgBatch := make([]byte, 40) binary.BigEndian.PutUint64(serializedInitMsgBatch[32:], 1) initMsgBatch := &SequencerInboxBatch{ - BlockHash: [32]byte{}, - BlockNumber: 0, - SequenceNumber: 0, - BeforeInboxAcc: [32]byte{}, - AfterInboxAcc: [32]byte{1}, - AfterDelayedAcc: initMsgDelayed.AfterInboxAcc(), - AfterDelayedCount: 1, - TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, - rawLog: types.Log{}, - dataLocation: 0, - bridgeAddress: [20]byte{}, - serialized: serializedInitMsgBatch, + BlockHash: [32]byte{}, + ParentChainBlockNumber: 0, + SequenceNumber: 0, + BeforeInboxAcc: [32]byte{}, + AfterInboxAcc: [32]byte{1}, + AfterDelayedAcc: initMsgDelayed.AfterInboxAcc(), + AfterDelayedCount: 1, + TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, + rawLog: types.Log{}, + dataLocation: 0, + bridgeAddress: [20]byte{}, + serialized: serializedInitMsgBatch, } serializedUserMsgBatch := make([]byte, 40) binary.BigEndian.PutUint64(serializedUserMsgBatch[32:], 2) userMsgBatch := &SequencerInboxBatch{ - BlockHash: [32]byte{}, - BlockNumber: 0, - SequenceNumber: 1, - BeforeInboxAcc: [32]byte{1}, - AfterInboxAcc: [32]byte{2}, - AfterDelayedAcc: userDelayed.AfterInboxAcc(), - AfterDelayedCount: 2, - TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, - rawLog: types.Log{}, - dataLocation: 0, - bridgeAddress: [20]byte{}, - serialized: serializedUserMsgBatch, + BlockHash: [32]byte{}, + ParentChainBlockNumber: 0, + SequenceNumber: 1, + BeforeInboxAcc: [32]byte{1}, + AfterInboxAcc: [32]byte{2}, + AfterDelayedAcc: userDelayed.AfterInboxAcc(), + AfterDelayedCount: 2, + TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, + rawLog: types.Log{}, + dataLocation: 0, + bridgeAddress: [20]byte{}, + serialized: serializedUserMsgBatch, } emptyBatch := &SequencerInboxBatch{ - BlockHash: [32]byte{}, - BlockNumber: 0, - SequenceNumber: 2, - BeforeInboxAcc: [32]byte{2}, - AfterInboxAcc: [32]byte{3}, - AfterDelayedAcc: userDelayed.AfterInboxAcc(), - AfterDelayedCount: 2, - TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, - rawLog: types.Log{}, - dataLocation: 0, - bridgeAddress: [20]byte{}, - serialized: serializedUserMsgBatch, + BlockHash: [32]byte{}, + ParentChainBlockNumber: 0, + SequenceNumber: 2, + BeforeInboxAcc: [32]byte{2}, + AfterInboxAcc: [32]byte{3}, + AfterDelayedAcc: userDelayed.AfterInboxAcc(), + AfterDelayedCount: 2, + TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, + rawLog: types.Log{}, + dataLocation: 0, + bridgeAddress: [20]byte{}, + serialized: serializedUserMsgBatch, } err = tracker.AddSequencerBatches(ctx, nil, []*SequencerInboxBatch{initMsgBatch, userMsgBatch, emptyBatch}) Require(t, err) @@ -123,18 +123,18 @@ func TestSequencerReorgFromDelayed(t *testing.T) { } emptyBatch = &SequencerInboxBatch{ - BlockHash: [32]byte{}, - BlockNumber: 0, - SequenceNumber: 1, - BeforeInboxAcc: [32]byte{1}, - AfterInboxAcc: [32]byte{2}, - AfterDelayedAcc: initMsgDelayed.AfterInboxAcc(), - AfterDelayedCount: 1, - TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, - rawLog: types.Log{}, - dataLocation: 0, - bridgeAddress: [20]byte{}, - serialized: serializedInitMsgBatch, + BlockHash: [32]byte{}, + ParentChainBlockNumber: 0, + SequenceNumber: 1, + BeforeInboxAcc: [32]byte{1}, + AfterInboxAcc: [32]byte{2}, + AfterDelayedAcc: initMsgDelayed.AfterInboxAcc(), + AfterDelayedCount: 1, + TimeBounds: bridgegen.ISequencerInboxTimeBounds{}, + rawLog: types.Log{}, + dataLocation: 0, + bridgeAddress: [20]byte{}, + serialized: serializedInitMsgBatch, } err = tracker.AddSequencerBatches(ctx, nil, []*SequencerInboxBatch{emptyBatch}) Require(t, err) diff --git a/arbnode/execution/blockchain.go b/arbnode/execution/blockchain.go index 2ed0221b04..a4de72588a 100644 --- a/arbnode/execution/blockchain.go +++ b/arbnode/execution/blockchain.go @@ -20,6 +20,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbos" "github.com/offchainlabs/nitro/arbos/arbosState" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/gethhook" "github.com/offchainlabs/nitro/statetransfer" ) @@ -82,7 +83,7 @@ func DefaultCacheConfigFor(stack *node.Node, cachingConfig *CachingConfig) *core } } -func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, accountsPerSync uint) error { +func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, accountsPerSync uint) error { EmptyHash := common.Hash{} prevHash := EmptyHash prevDifficulty := big.NewInt(0) @@ -103,7 +104,7 @@ func WriteOrTestGenblock(chainDb ethdb.Database, initData statetransfer.InitData } timestamp = prevHeader.Time } - stateRoot, err := arbosState.InitializeArbosInDatabase(chainDb, initData, chainConfig, serializedChainConfig, timestamp, accountsPerSync) + stateRoot, err := arbosState.InitializeArbosInDatabase(chainDb, initData, chainConfig, initMessage, timestamp, accountsPerSync) if err != nil { return err } @@ -170,8 +171,8 @@ func GetBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, chainC return core.NewBlockChain(chainDb, cacheConfig, chainConfig, nil, nil, engine, vmConfig, shouldPreserveFalse, &txLookupLimit) } -func WriteOrTestBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, txLookupLimit uint64, accountsPerSync uint) (*core.BlockChain, error) { - err := WriteOrTestGenblock(chainDb, initData, chainConfig, serializedChainConfig, accountsPerSync) +func WriteOrTestBlockChain(chainDb ethdb.Database, cacheConfig *core.CacheConfig, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, txLookupLimit uint64, accountsPerSync uint) (*core.BlockChain, error) { + err := WriteOrTestGenblock(chainDb, initData, chainConfig, initMessage, accountsPerSync) if err != nil { return nil, err } diff --git a/arbnode/execution/sequencer.go b/arbnode/execution/sequencer.go index 3bc3c90cb1..6266f4197f 100644 --- a/arbnode/execution/sequencer.go +++ b/arbnode/execution/sequencer.go @@ -15,6 +15,7 @@ import ( "sync/atomic" "time" + "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/containers" "github.com/offchainlabs/nitro/util/headerreader" @@ -926,12 +927,14 @@ func (s *Sequencer) createBlock(ctx context.Context) (returnValue bool) { return madeBlock } -func (s *Sequencer) updateLatestL1Block(header *types.Header) { +func (s *Sequencer) updateLatestParentChainBlock(header *types.Header) { s.L1BlockAndTimeMutex.Lock() defer s.L1BlockAndTimeMutex.Unlock() - if s.l1BlockNumber < header.Number.Uint64() { - s.l1BlockNumber = header.Number.Uint64() + + l1BlockNumber := arbutil.ParentHeaderToL1BlockNumber(header) + if header.Time > s.l1Timestamp || (header.Time == s.l1Timestamp && l1BlockNumber > s.l1BlockNumber) { s.l1Timestamp = header.Time + s.l1BlockNumber = l1BlockNumber } } @@ -944,7 +947,7 @@ func (s *Sequencer) Initialize(ctx context.Context) error { if err != nil { return err } - s.updateLatestL1Block(header) + s.updateLatestParentChainBlock(header) return nil } @@ -966,7 +969,7 @@ func (s *Sequencer) Start(ctxIn context.Context) error { if !ok { return } - s.updateLatestL1Block(header) + s.updateLatestParentChainBlock(header) case <-ctx.Done(): return } diff --git a/arbnode/inbox_reader.go b/arbnode/inbox_reader.go index 19fee7aa3d..6ce9fd7172 100644 --- a/arbnode/inbox_reader.go +++ b/arbnode/inbox_reader.go @@ -140,17 +140,17 @@ func (r *InboxReader) Start(ctxIn context.Context) error { if err != nil { return err } - initChainId, initChainConfig, _, err := message.ParseInitMessage() + initMessage, err := message.ParseInitMessage() if err != nil { return err } chainConfig := r.tracker.txStreamer.chainConfig configChainId := chainConfig.ChainID - if initChainId.Cmp(configChainId) != 0 { - return fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", configChainId, initChainId) + if initMessage.ChainId.Cmp(configChainId) != 0 { + return fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", configChainId, initMessage.ChainId) } - if initChainConfig != nil { - if err := initChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil { + if initMessage.ChainConfig != nil { + if err := initMessage.ChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil { return fmt.Errorf("incompatible chain config read from init message in L1 inbox: %w", err) } } @@ -166,7 +166,7 @@ func (r *InboxReader) Start(ctxIn context.Context) error { } // assumes l1block is recent so we could do a simple-search from the end -func (r *InboxReader) recentL1BlockToMsg(ctx context.Context, l1block uint64) (arbutil.MessageIndex, error) { +func (r *InboxReader) recentParentChainBlockToMsg(ctx context.Context, parentChainBlock uint64) (arbutil.MessageIndex, error) { batch, err := r.tracker.GetBatchCount() if err != nil { return 0, err @@ -183,7 +183,7 @@ func (r *InboxReader) recentL1BlockToMsg(ctx context.Context, l1block uint64) (a if err != nil { return 0, err } - if meta.L1Block <= l1block { + if meta.ParentChainBlock <= parentChainBlock { return meta.MessageCount, nil } } @@ -194,7 +194,7 @@ func (r *InboxReader) GetSafeMsgCount(ctx context.Context) (arbutil.MessageIndex if err != nil { return 0, err } - return r.recentL1BlockToMsg(ctx, l1block) + return r.recentParentChainBlockToMsg(ctx, l1block) } func (r *InboxReader) GetFinalizedMsgCount(ctx context.Context) (arbutil.MessageIndex, error) { @@ -202,7 +202,7 @@ func (r *InboxReader) GetFinalizedMsgCount(ctx context.Context) (arbutil.Message if err != nil { return 0, err } - return r.recentL1BlockToMsg(ctx, l1block) + return r.recentParentChainBlockToMsg(ctx, l1block) } func (r *InboxReader) Tracker() *InboxTracker { @@ -575,7 +575,7 @@ func (r *InboxReader) GetSequencerMessageBytes(ctx context.Context, seqNum uint6 if err != nil { return nil, err } - blockNum := arbmath.UintToBig(metadata.L1Block) + blockNum := arbmath.UintToBig(metadata.ParentChainBlock) seqBatches, err := r.sequencerInbox.LookupBatchesInRange(ctx, blockNum, blockNum) if err != nil { return nil, err @@ -587,7 +587,7 @@ func (r *InboxReader) GetSequencerMessageBytes(ctx context.Context, seqNum uint6 } seenBatches = append(seenBatches, batch.SequenceNumber) } - return nil, fmt.Errorf("sequencer batch %v not found in L1 block %v (found batches %v)", seqNum, metadata.L1Block, seenBatches) + return nil, fmt.Errorf("sequencer batch %v not found in L1 block %v (found batches %v)", seqNum, metadata.ParentChainBlock, seenBatches) } func (r *InboxReader) GetLastReadBlockAndBatchCount() (uint64, uint64) { diff --git a/arbnode/inbox_test.go b/arbnode/inbox_test.go index 0cede3bcdd..e68cee49ff 100644 --- a/arbnode/inbox_test.go +++ b/arbnode/inbox_test.go @@ -6,7 +6,6 @@ package arbnode import ( "context" "encoding/binary" - "encoding/json" "math/big" "math/rand" "testing" @@ -18,13 +17,14 @@ import ( "github.com/offchainlabs/nitro/arbutil" "github.com/offchainlabs/nitro/statetransfer" - nitroutil "github.com/offchainlabs/nitro/util" + "github.com/offchainlabs/nitro/util/arbmath" "github.com/offchainlabs/nitro/util/testhelpers" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbos" @@ -32,10 +32,6 @@ import ( func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (*execution.ExecutionEngine, *TransactionStreamer, ethdb.Database, *core.BlockChain) { chainConfig := params.ArbitrumDevTestChainConfig() - serializedChainConfig, err := json.Marshal(chainConfig) - if err != nil { - Fail(t, err) - } initData := statetransfer.ArbosInitializationInfo{ Accounts: []statetransfer.AccountInitializationInfo{ @@ -50,7 +46,7 @@ func NewTransactionStreamerForTest(t *testing.T, ownerAddress common.Address) (* arbDb := rawdb.NewMemoryDatabase() initReader := statetransfer.NewMemoryInitDataReader(&initData) - bc, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, serializedChainConfig, ConfigDefaultL2Test().TxLookupLimit, 0) + bc, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, arbostypes.TestInitMessage, ConfigDefaultL2Test().TxLookupLimit, 0) if err != nil { Fail(t, err) @@ -101,7 +97,7 @@ func TestTransactionStreamer(t *testing.T) { var blockStates []blockTestState blockStates = append(blockStates, blockTestState{ balances: map[common.Address]*big.Int{ - ownerAddress: new(big.Int).Mul(maxExpectedGasCost, big.NewInt(int64(nitroutil.NormalizeL2GasForL1GasInitial(1_000_000, params.GWei)))), + ownerAddress: new(big.Int).SetUint64(params.Ether), }, accounts: []common.Address{ownerAddress}, numMessages: 1, @@ -169,6 +165,7 @@ func TestTransactionStreamer(t *testing.T) { Require(t, inbox.AddMessages(state.numMessages, false, messages)) state.numMessages += arbutil.MessageIndex(len(messages)) + prevBlockNumber := state.blockNumber state.blockNumber += uint64(len(messages)) for i := 0; ; i++ { blockNumber := bc.CurrentHeader().Number.Uint64() @@ -181,6 +178,23 @@ func TestTransactionStreamer(t *testing.T) { } time.Sleep(10 * time.Millisecond) } + for blockNum := prevBlockNumber + 1; blockNum <= state.blockNumber; blockNum++ { + block := bc.GetBlockByNumber(blockNum) + txs := block.Transactions() + receipts := bc.GetReceiptsByHash(block.Hash()) + if len(txs) != len(receipts) { + Fail(t, "got", len(txs), "transactions but", len(receipts), "receipts in block", blockNum) + } + for i, receipt := range receipts { + sender, err := types.Sender(types.LatestSigner(bc.Config()), txs[i]) + Require(t, err) + balance, ok := state.balances[sender] + if !ok { + continue + } + balance.Sub(balance, arbmath.BigMulByUint(block.BaseFee(), receipt.GasUsed)) + } + } blockStates = append(blockStates, state) } @@ -202,7 +216,7 @@ func TestTransactionStreamer(t *testing.T) { Fail(t, "error getting block state", err) } haveBalance := state.GetBalance(acct) - if balance.Cmp(haveBalance) < 0 { + if balance.Cmp(haveBalance) != 0 { t.Error("unexpected balance for account", acct, "; expected", balance, "got", haveBalance) } } diff --git a/arbnode/inbox_tracker.go b/arbnode/inbox_tracker.go index ddb8d71e48..b6a1afd02b 100644 --- a/arbnode/inbox_tracker.go +++ b/arbnode/inbox_tracker.go @@ -97,6 +97,23 @@ func (t *InboxTracker) Initialize() error { var AccumulatorNotFoundErr = errors.New("accumulator not found") +func (t *InboxTracker) deleteBatchMetadataStartingAt(dbBatch ethdb.Batch, startIndex uint64) error { + t.batchMetaMutex.Lock() + defer t.batchMetaMutex.Unlock() + iter := t.db.NewIterator(sequencerBatchMetaPrefix, uint64ToKey(startIndex)) + defer iter.Release() + for iter.Next() { + curKey := iter.Key() + err := dbBatch.Delete(curKey) + if err != nil { + return err + } + curIndex := binary.BigEndian.Uint64(bytes.TrimPrefix(curKey, sequencerBatchMetaPrefix)) + t.batchMeta.Remove(curIndex) + } + return iter.Error() +} + func (t *InboxTracker) GetDelayedAcc(seqNum uint64) (common.Hash, error) { key := dbKey(rlpDelayedMessagePrefix, seqNum) hasKey, err := t.db.Has(key) @@ -142,7 +159,7 @@ type BatchMetadata struct { Accumulator common.Hash MessageCount arbutil.MessageIndex DelayedMessageCount uint64 - L1Block uint64 + ParentChainBlock uint64 } func (t *InboxTracker) GetBatchMetadata(seqNum uint64) (BatchMetadata, error) { @@ -384,12 +401,6 @@ func (t *InboxTracker) AddDelayedMessages(messages []*DelayedInboxMessage, hardR return t.setDelayedCountReorgAndWriteBatch(batch, pos, true) } -func (t *InboxTracker) clearBatchMetaCache() { - t.batchMetaMutex.Lock() - defer t.batchMetaMutex.Unlock() - t.batchMeta.Clear() -} - // All-in-one delayed message count adjuster. Can go forwards or backwards. // Requires the mutex is held. Sets the delayed count and performs any sequencer batch reorg necessary. // Also deletes any future delayed messages. @@ -447,8 +458,6 @@ func (t *InboxTracker) setDelayedCountReorgAndWriteBatch(batch ethdb.Batch, newD if reorgSeqBatchesToCount == nil { return batch.Write() } - // Clear the batchMeta cache after writing the reorg to disk - defer t.clearBatchMetaCache() count := *reorgSeqBatchesToCount if t.validator != nil { @@ -463,7 +472,7 @@ func (t *InboxTracker) setDelayedCountReorgAndWriteBatch(batch ethdb.Batch, newD } log.Warn("InboxTracker delayed message reorg is causing a sequencer batch reorg", "sequencerBatchCount", count, "delayedCount", newDelayedCount) - if err := deleteStartingAt(t.db, batch, sequencerBatchMetaPrefix, uint64ToKey(count)); err != nil { + if err := t.deleteBatchMetadataStartingAt(batch, count); err != nil { return err } var prevMesssageCount arbutil.MessageIndex @@ -610,7 +619,7 @@ func (t *InboxTracker) AddSequencerBatches(ctx context.Context, client arbutil.L Accumulator: batch.AfterInboxAcc, DelayedMessageCount: batch.AfterDelayedCount, MessageCount: batchMessageCounts[batch.SequenceNumber], - L1Block: batch.BlockNumber, + ParentChainBlock: batch.ParentChainBlockNumber, } batchMetas[batch.SequenceNumber] = meta metaBytes, err := rlp.EncodeToBytes(meta) @@ -638,7 +647,7 @@ func (t *InboxTracker) AddSequencerBatches(ctx context.Context, client arbutil.L lastBatchMeta = meta } - err = deleteStartingAt(t.db, dbBatch, sequencerBatchMetaPrefix, uint64ToKey(pos)) + err = t.deleteBatchMetadataStartingAt(dbBatch, pos) if err != nil { return err } @@ -654,7 +663,7 @@ func (t *InboxTracker) AddSequencerBatches(ctx context.Context, client arbutil.L newMessageCount := prevbatchmeta.MessageCount + arbutil.MessageIndex(len(messages)) var latestL1Block uint64 if len(batches) > 0 { - latestL1Block = batches[len(batches)-1].BlockNumber + latestL1Block = batches[len(batches)-1].ParentChainBlockNumber } var latestTimestamp uint64 if len(messages) > 0 { @@ -752,16 +761,13 @@ func (t *InboxTracker) ReorgBatchesTo(count uint64) error { t.validator.ReorgToBatchCount(count) } - // Clear the batchMeta cache after writing the reorg to disk - defer t.clearBatchMetaCache() - dbBatch := t.db.NewBatch() err := deleteStartingAt(t.db, dbBatch, delayedSequencedPrefix, uint64ToKey(prevBatchMeta.DelayedMessageCount+1)) if err != nil { return err } - err = deleteStartingAt(t.db, dbBatch, sequencerBatchMetaPrefix, uint64ToKey(count)) + err = t.deleteBatchMetadataStartingAt(dbBatch, count) if err != nil { return err } diff --git a/arbnode/inbox_tracker_test.go b/arbnode/inbox_tracker_test.go new file mode 100644 index 0000000000..582b334aee --- /dev/null +++ b/arbnode/inbox_tracker_test.go @@ -0,0 +1,58 @@ +package arbnode + +import ( + "testing" + + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/offchainlabs/nitro/util/containers" +) + +func TestDeleteBatchMetadata(t *testing.T) { + testBytes := []byte("bloop") + + tracker := &InboxTracker{ + db: rawdb.NewMemoryDatabase(), + batchMeta: containers.NewLruCache[uint64, BatchMetadata](100), + } + + for i := uint64(0); i < 30; i += 1 { + err := tracker.db.Put(dbKey(sequencerBatchMetaPrefix, i), testBytes) + Require(t, err) + if i%5 != 0 { + tracker.batchMeta.Add(i, BatchMetadata{}) + } + } + + batch := tracker.db.NewBatch() + err := tracker.deleteBatchMetadataStartingAt(batch, 15) + if err != nil { + Fail(t, "deleteBatchMetadataStartingAt returned error: ", err) + } + err = batch.Write() + Require(t, err) + + for i := uint64(0); i < 15; i += 1 { + has, err := tracker.db.Has(dbKey(sequencerBatchMetaPrefix, i)) + Require(t, err) + if !has { + Fail(t, "value removed from db: ", i) + } + if i%5 != 0 { + if !tracker.batchMeta.Contains(i) { + Fail(t, "value removed from cache: ", i) + } + } + } + + for i := uint64(15); i < 30; i += 1 { + has, err := tracker.db.Has(dbKey(sequencerBatchMetaPrefix, i)) + Require(t, err) + if has { + Fail(t, "value not removed from db: ", i) + } + if tracker.batchMeta.Contains(i) { + Fail(t, "value removed from cache: ", i) + } + } + +} diff --git a/arbnode/maintenance.go b/arbnode/maintenance.go index 1b059df48d..8b0c7811ea 100644 --- a/arbnode/maintenance.go +++ b/arbnode/maintenance.go @@ -20,14 +20,19 @@ import ( type MaintenanceRunner struct { stopwaiter.StopWaiter - config MaintenanceConfigFetcher - seqCoordinator *SeqCoordinator - dbs []ethdb.Database - lastCheck time.Time + config MaintenanceConfigFetcher + seqCoordinator *SeqCoordinator + dbs []ethdb.Database + lastMaintenance time.Time + + // lock is used to ensures that at any given time, only single node is on + // maintenance mode. + lock *SimpleRedisLock } type MaintenanceConfig struct { - TimeOfDay string `koanf:"time-of-day" reload:"hot"` + TimeOfDay string `koanf:"time-of-day" reload:"hot"` + Lock SimpleRedisLockConfig `koanf:"lock" reload:"hot"` // Generated: the minutes since start of UTC day to compact at minutesAfterMidnight int @@ -65,6 +70,7 @@ func (c *MaintenanceConfig) Validate() error { func MaintenanceConfigAddOptions(prefix string, f *flag.FlagSet) { f.String(prefix+".time-of-day", DefaultMaintenanceConfig.TimeOfDay, "UTC 24-hour time of day to run maintenance (currently only db compaction) at (e.g. 15:00)") + RedisLockConfigAddOptions(prefix+".lock", f) } var DefaultMaintenanceConfig = MaintenanceConfig{ @@ -76,21 +82,32 @@ var DefaultMaintenanceConfig = MaintenanceConfig{ type MaintenanceConfigFetcher func() *MaintenanceConfig func NewMaintenanceRunner(config MaintenanceConfigFetcher, seqCoordinator *SeqCoordinator, dbs []ethdb.Database) (*MaintenanceRunner, error) { - err := config().Validate() - if err != nil { - return nil, err - } - return &MaintenanceRunner{ - config: config, - seqCoordinator: seqCoordinator, - dbs: dbs, - lastCheck: time.Now().UTC(), - }, nil + cfg := config() + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("validating config: %w", err) + } + res := &MaintenanceRunner{ + config: config, + seqCoordinator: seqCoordinator, + dbs: dbs, + lastMaintenance: time.Now().UTC(), + } + + if seqCoordinator != nil { + c := func() *SimpleRedisLockConfig { return &cfg.Lock } + r := func() bool { return true } // always ready to lock + rl, err := NewSimpleRedisLock(seqCoordinator.Client, c, r) + if err != nil { + return nil, fmt.Errorf("creating new simple redis lock: %w", err) + } + res.lock = rl + } + return res, nil } -func (c *MaintenanceRunner) Start(ctxIn context.Context) { - c.StopWaiter.Start(ctxIn, c) - c.CallIteratively(c.maybeRunMaintenance) +func (mr *MaintenanceRunner) Start(ctxIn context.Context) { + mr.StopWaiter.Start(ctxIn, mr) + mr.CallIteratively(mr.maybeRunMaintenance) } func wentPastTimeOfDay(before time.Time, after time.Time, timeOfDay int) bool { @@ -112,47 +129,53 @@ func wentPastTimeOfDay(before time.Time, after time.Time, timeOfDay int) bool { return prevMinutes < dbCompactionMinutes && newMinutes >= dbCompactionMinutes } -func (c *MaintenanceRunner) maybeRunMaintenance(ctx context.Context) time.Duration { - config := c.config() +func (mr *MaintenanceRunner) maybeRunMaintenance(ctx context.Context) time.Duration { + config := mr.config() if !config.enabled { return time.Minute } + now := time.Now().UTC() - if wentPastTimeOfDay(c.lastCheck, now, config.minutesAfterMidnight) { - log.Info("attempting to release sequencer lockout to run database compaction", "targetTime", config.TimeOfDay) - if c.seqCoordinator == nil { - c.runMaintenance() - } else { - // We want to switch sequencers before running maintenance - success := c.seqCoordinator.AvoidLockout(ctx) - defer c.seqCoordinator.SeekLockout(ctx) // needs called even if c.Zombify returns false - if success { - // We've unset the wants lockout key, now wait for the handoff - success = c.seqCoordinator.TryToHandoffChosenOne(ctx) - if success { - c.runMaintenance() - } - } - } + + if !wentPastTimeOfDay(mr.lastMaintenance, now, config.minutesAfterMidnight) { + return time.Minute } - c.lastCheck = now + + if mr.seqCoordinator == nil { + mr.lastMaintenance = now + mr.runMaintenance() + return time.Minute + } + + if !mr.lock.AttemptLock(ctx) { + return time.Minute + } + defer mr.lock.Release(ctx) + + log.Info("Attempting avoiding lockout and handing off", "targetTime", config.TimeOfDay) + // Avoid lockout for the sequencer and try to handoff. + if mr.seqCoordinator.AvoidLockout(ctx) && mr.seqCoordinator.TryToHandoffChosenOne(ctx) { + mr.lastMaintenance = now + mr.runMaintenance() + } + defer mr.seqCoordinator.SeekLockout(ctx) // needs called even if c.Zombify returns false + return time.Minute } -func (c *MaintenanceRunner) runMaintenance() { - log.Info("compacting databases (this may take a while...)") - results := make(chan error, len(c.dbs)) - for _, db := range c.dbs { +func (mr *MaintenanceRunner) runMaintenance() { + log.Info("Compacting databases (this may take a while...)") + results := make(chan error, len(mr.dbs)) + for _, db := range mr.dbs { db := db go func() { results <- db.Compact(nil, nil) }() } - for range c.dbs { - err := <-results - if err != nil { - log.Warn("failed to compact database", "err", err) + for range mr.dbs { + if err := <-results; err != nil { + log.Warn("Failed to compact database", "err", err) } } - log.Info("done compacting databases") + log.Info("Done compacting databases") } diff --git a/arbnode/maintenance_test.go b/arbnode/maintenance_test.go index 1f0563ae56..6e1de326ec 100644 --- a/arbnode/maintenance_test.go +++ b/arbnode/maintenance_test.go @@ -4,39 +4,38 @@ package arbnode import ( - "fmt" "testing" "time" ) func TestWentPastTimeOfDay(t *testing.T) { - checkWentPastTimeOfDay := func(before time.Time, after time.Time, timeOfDay string, expected bool) { - config := MaintenanceConfig{ - TimeOfDay: timeOfDay, - } - Require(t, config.Validate(), "Failed to validate sample config") - have := wentPastTimeOfDay(before, after, config.minutesAfterMidnight) - if have != expected { - Fail(t, fmt.Sprintf("Expected wentPastTimeOfDay(%v, %v, \"%v\") to return %v but it returned %v", before, after, timeOfDay, expected, have)) - } - } - eleven_pm := time.Date(2000, 1, 1, 23, 0, 0, 0, time.UTC) midnight := time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC) one_am := time.Date(2000, 1, 2, 1, 0, 0, 0, time.UTC) - checkWentPastTimeOfDay(eleven_pm, eleven_pm, "23:00", false) - checkWentPastTimeOfDay(midnight, midnight, "00:00", false) - checkWentPastTimeOfDay(one_am, one_am, "1:00", false) - - checkWentPastTimeOfDay(eleven_pm, midnight, "23:30", true) - checkWentPastTimeOfDay(eleven_pm, midnight, "00:00", true) - checkWentPastTimeOfDay(eleven_pm, one_am, "00:00", true) - checkWentPastTimeOfDay(eleven_pm, one_am, "01:00", true) - checkWentPastTimeOfDay(eleven_pm, one_am, "02:00", false) - checkWentPastTimeOfDay(eleven_pm, one_am, "12:00", false) + for _, tc := range []struct { + before, after time.Time + timeOfDay string + want bool + }{ + {before: eleven_pm, after: eleven_pm, timeOfDay: "23:00"}, + {before: midnight, after: midnight, timeOfDay: "00:00"}, + {before: one_am, after: one_am, timeOfDay: "1:00"}, + {before: eleven_pm, after: midnight, timeOfDay: "23:30", want: true}, + {before: eleven_pm, after: midnight, timeOfDay: "00:00", want: true}, + {before: eleven_pm, after: one_am, timeOfDay: "00:00", want: true}, + {before: eleven_pm, after: one_am, timeOfDay: "01:00", want: true}, + {before: eleven_pm, after: one_am, timeOfDay: "02:00"}, + {before: eleven_pm, after: one_am, timeOfDay: "12:00"}, + {before: midnight, after: one_am, timeOfDay: "00:00"}, + {before: midnight, after: one_am, timeOfDay: "00:30", want: true}, + {before: midnight, after: one_am, timeOfDay: "01:00", want: true}, + } { + config := MaintenanceConfig{TimeOfDay: tc.timeOfDay} + Require(t, config.Validate(), "Failed to validate sample config") - checkWentPastTimeOfDay(midnight, one_am, "00:00", false) - checkWentPastTimeOfDay(midnight, one_am, "00:30", true) - checkWentPastTimeOfDay(midnight, one_am, "01:00", true) + if got := wentPastTimeOfDay(tc.before, tc.after, config.minutesAfterMidnight); got != tc.want { + t.Errorf("wentPastTimeOfDay(%v, %v, %q) = %T want %T", tc.before, tc.after, tc.timeOfDay, got, tc.want) + } + } } diff --git a/arbnode/message_pruner.go b/arbnode/message_pruner.go new file mode 100644 index 0000000000..1ba3886d8d --- /dev/null +++ b/arbnode/message_pruner.go @@ -0,0 +1,131 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE + +package arbnode + +import ( + "bytes" + "context" + "encoding/binary" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/offchainlabs/nitro/staker" + "github.com/offchainlabs/nitro/util/stopwaiter" + + flag "github.com/spf13/pflag" +) + +type MessagePruner struct { + stopwaiter.StopWaiter + transactionStreamer *TransactionStreamer + inboxTracker *InboxTracker + staker *staker.Staker + config MessagePrunerConfigFetcher +} + +type MessagePrunerConfig struct { + Enable bool `koanf:"enable"` + MessagePruneInterval time.Duration `koanf:"prune-interval" reload:"hot"` +} + +type MessagePrunerConfigFetcher func() *MessagePrunerConfig + +var DefaultMessagePrunerConfig = MessagePrunerConfig{ + Enable: true, + MessagePruneInterval: time.Minute, +} + +func MessagePrunerConfigAddOptions(prefix string, f *flag.FlagSet) { + f.Bool(prefix+".enable", DefaultMessagePrunerConfig.Enable, "enable message pruning") + f.Duration(prefix+".prune-interval", DefaultMessagePrunerConfig.MessagePruneInterval, "interval for running message pruner") +} + +func NewMessagePruner(transactionStreamer *TransactionStreamer, inboxTracker *InboxTracker, staker *staker.Staker, config MessagePrunerConfigFetcher) *MessagePruner { + return &MessagePruner{ + transactionStreamer: transactionStreamer, + inboxTracker: inboxTracker, + staker: staker, + config: config, + } +} + +func (m *MessagePruner) Start(ctxIn context.Context) { + m.StopWaiter.Start(ctxIn, m) + m.CallIteratively(m.prune) +} + +func (m *MessagePruner) prune(ctx context.Context) time.Duration { + latestConfirmedNode, err := m.staker.Rollup().LatestConfirmed( + &bind.CallOpts{ + Context: ctx, + BlockNumber: big.NewInt(int64(rpc.FinalizedBlockNumber)), + }) + if err != nil { + log.Error("error getting latest confirmed node", "err", err) + return m.config().MessagePruneInterval + } + nodeInfo, err := m.staker.Rollup().LookupNode(ctx, latestConfirmedNode) + if err != nil { + log.Error("error getting latest confirmed node info", "node", latestConfirmedNode, "err", err) + return m.config().MessagePruneInterval + } + endBatchCount := nodeInfo.Assertion.AfterState.GlobalState.Batch + if endBatchCount == 0 { + return m.config().MessagePruneInterval + } + endBatchMetadata, err := m.inboxTracker.GetBatchMetadata(endBatchCount - 1) + if err != nil { + log.Error("error getting last batch metadata", "batch", endBatchCount-1, "err", err) + return m.config().MessagePruneInterval + } + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, m.inboxTracker.db, m.transactionStreamer.db) + return m.config().MessagePruneInterval +} + +func deleteOldMessageFromDB(endBatchCount uint64, endBatchMetadata BatchMetadata, inboxTrackerDb ethdb.Database, transactionStreamerDb ethdb.Database) { + prunedKeysRange, err := deleteFromLastPrunedUptoEndKey(inboxTrackerDb, sequencerBatchMetaPrefix, endBatchCount) + if err != nil { + log.Error("error deleting batch metadata", "err", err) + return + } + if len(prunedKeysRange) > 0 { + log.Info("Pruned batches:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) + } + + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(transactionStreamerDb, messagePrefix, uint64(endBatchMetadata.MessageCount)) + if err != nil { + log.Error("error deleting last batch messages", "err", err) + return + } + if len(prunedKeysRange) > 0 { + log.Info("Pruned last batch messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) + } + + prunedKeysRange, err = deleteFromLastPrunedUptoEndKey(inboxTrackerDb, rlpDelayedMessagePrefix, endBatchMetadata.DelayedMessageCount) + if err != nil { + log.Error("error deleting last batch delayed messages", "err", err) + return + } + if len(prunedKeysRange) > 0 { + log.Info("Pruned last batch delayed messages:", "first pruned key", prunedKeysRange[0], "last pruned key", prunedKeysRange[len(prunedKeysRange)-1]) + } +} + +func deleteFromLastPrunedUptoEndKey(db ethdb.Database, prefix []byte, endMinKey uint64) ([][]byte, error) { + startIter := db.NewIterator(prefix, uint64ToKey(1)) + if !startIter.Next() { + return nil, nil + } + startMinKey := binary.BigEndian.Uint64(bytes.TrimPrefix(startIter.Key(), prefix)) + startIter.Release() + if endMinKey > startMinKey { + return deleteFromRange(db, prefix, startMinKey, endMinKey-1) + } + return nil, nil +} diff --git a/arbnode/message_pruner_test.go b/arbnode/message_pruner_test.go new file mode 100644 index 0000000000..16c1d6b71c --- /dev/null +++ b/arbnode/message_pruner_test.go @@ -0,0 +1,109 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE + +package arbnode + +import ( + "testing" + + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +func TestMessagePrunerWithPruningEligibleMessagePresent(t *testing.T) { + endBatchCount := uint64(2 * 100 * 1024) + endBatchMetadata := BatchMetadata{ + MessageCount: 2 * 100 * 1024, + DelayedMessageCount: 2 * 100 * 1024, + } + inboxTrackerDb, transactionStreamerDb := setupDatabase(t, endBatchCount, endBatchMetadata) + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, inboxTrackerDb, transactionStreamerDb) + + checkDbKeys(t, endBatchCount, inboxTrackerDb, sequencerBatchMetaPrefix) + checkDbKeys(t, uint64(endBatchMetadata.MessageCount), transactionStreamerDb, messagePrefix) + checkDbKeys(t, endBatchMetadata.DelayedMessageCount, inboxTrackerDb, rlpDelayedMessagePrefix) + +} + +func TestMessagePrunerTraverseEachMessageOnlyOnce(t *testing.T) { + endBatchCount := uint64(10) + endBatchMetadata := BatchMetadata{} + inboxTrackerDb, transactionStreamerDb := setupDatabase(t, endBatchCount, endBatchMetadata) + // In first iteration message till endBatchCount are tried to be deleted. + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, inboxTrackerDb, transactionStreamerDb) + // In first iteration all the message till endBatchCount are deleted. + checkDbKeys(t, endBatchCount, inboxTrackerDb, sequencerBatchMetaPrefix) + // After first iteration endBatchCount/2 is reinserted in inbox db + err := inboxTrackerDb.Put(dbKey(sequencerBatchMetaPrefix, endBatchCount/2), []byte{}) + Require(t, err) + // In second iteration message till endBatchCount are again tried to be deleted. + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, inboxTrackerDb, transactionStreamerDb) + // In second iteration all the message till endBatchCount are deleted again. + checkDbKeys(t, endBatchCount, inboxTrackerDb, sequencerBatchMetaPrefix) +} + +func TestMessagePrunerPruneTillLessThenEqualTo(t *testing.T) { + endBatchCount := uint64(10) + endBatchMetadata := BatchMetadata{} + inboxTrackerDb, transactionStreamerDb := setupDatabase(t, 2*endBatchCount, endBatchMetadata) + err := inboxTrackerDb.Delete(dbKey(sequencerBatchMetaPrefix, 9)) + Require(t, err) + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, inboxTrackerDb, transactionStreamerDb) + hasKey, err := inboxTrackerDb.Has(dbKey(sequencerBatchMetaPrefix, 10)) + Require(t, err) + if !hasKey { + Fail(t, "Key", 10, "with prefix", string(sequencerBatchMetaPrefix), "should be present after pruning") + } +} + +func TestMessagePrunerWithNoPruningEligibleMessagePresent(t *testing.T) { + endBatchCount := uint64(2) + endBatchMetadata := BatchMetadata{ + MessageCount: 2, + DelayedMessageCount: 2, + } + inboxTrackerDb, transactionStreamerDb := setupDatabase(t, endBatchCount, endBatchMetadata) + deleteOldMessageFromDB(endBatchCount, endBatchMetadata, inboxTrackerDb, transactionStreamerDb) + + checkDbKeys(t, endBatchCount, inboxTrackerDb, sequencerBatchMetaPrefix) + checkDbKeys(t, uint64(endBatchMetadata.MessageCount), transactionStreamerDb, messagePrefix) + checkDbKeys(t, endBatchMetadata.DelayedMessageCount, inboxTrackerDb, rlpDelayedMessagePrefix) + +} + +func setupDatabase(t *testing.T, endBatchCount uint64, endBatchMetadata BatchMetadata) (ethdb.Database, ethdb.Database) { + inboxTrackerDb := rawdb.NewMemoryDatabase() + for i := uint64(0); i < endBatchCount; i++ { + err := inboxTrackerDb.Put(dbKey(sequencerBatchMetaPrefix, i), []byte{}) + Require(t, err) + } + + transactionStreamerDb := rawdb.NewMemoryDatabase() + for i := uint64(0); i < uint64(endBatchMetadata.MessageCount); i++ { + err := transactionStreamerDb.Put(dbKey(messagePrefix, i), []byte{}) + Require(t, err) + } + + for i := uint64(0); i < endBatchMetadata.DelayedMessageCount; i++ { + err := inboxTrackerDb.Put(dbKey(rlpDelayedMessagePrefix, i), []byte{}) + Require(t, err) + } + + return inboxTrackerDb, transactionStreamerDb +} + +func checkDbKeys(t *testing.T, endCount uint64, db ethdb.Database, prefix []byte) { + for i := uint64(0); i < endCount; i++ { + hasKey, err := db.Has(dbKey(prefix, i)) + Require(t, err) + if i == 0 || i == endCount-1 { + if !hasKey { + Fail(t, "Key", i, "with prefix", string(prefix), "should be present after pruning") + } + } else { + if hasKey { + Fail(t, "Key", i, "with prefix", string(prefix), "should not be present after pruning") + } + } + } +} diff --git a/arbnode/node.go b/arbnode/node.go index 895de3a9a2..f1fc8e9e63 100644 --- a/arbnode/node.go +++ b/arbnode/node.go @@ -242,20 +242,14 @@ func DeployOnL1(ctx context.Context, l1client arbutil.L1Interface, deployAuth *b return nil, errors.New("no machine specified") } - rollupCreator, rollupCreatorAddress, validatorUtils, validatorWalletCreator, err := deployRollupCreator(ctx, l1Reader, deployAuth) + rollupCreator, _, validatorUtils, validatorWalletCreator, err := deployRollupCreator(ctx, l1Reader, deployAuth) if err != nil { return nil, fmt.Errorf("error deploying rollup creator: %w", err) } - nonce, err := l1client.PendingNonceAt(ctx, rollupCreatorAddress) - if err != nil { - return nil, fmt.Errorf("error getting pending nonce: %w", err) - } - expectedRollupAddr := crypto.CreateAddress(rollupCreatorAddress, nonce+2) tx, err := rollupCreator.CreateRollup( deployAuth, config, - expectedRollupAddr, ) if err != nil { return nil, fmt.Errorf("error submitting create rollup tx: %w", err) @@ -319,6 +313,7 @@ type Config struct { InboxReader InboxReaderConfig `koanf:"inbox-reader" reload:"hot"` DelayedSequencer DelayedSequencerConfig `koanf:"delayed-sequencer" reload:"hot"` BatchPoster BatchPosterConfig `koanf:"batch-poster" reload:"hot"` + MessagePruner MessagePrunerConfig `koanf:"message-pruner" reload:"hot"` ForwardingTargetImpl string `koanf:"forwarding-target"` Forwarder execution.ForwarderConfig `koanf:"forwarder"` TxPreChecker execution.TxPreCheckerConfig `koanf:"tx-pre-checker" reload:"hot"` @@ -392,6 +387,7 @@ func ConfigAddOptions(prefix string, f *flag.FlagSet, feedInputEnable bool, feed InboxReaderConfigAddOptions(prefix+".inbox-reader", f) DelayedSequencerConfigAddOptions(prefix+".delayed-sequencer", f) BatchPosterConfigAddOptions(prefix+".batch-poster", f) + MessagePrunerConfigAddOptions(prefix+".message-pruner", f) f.String(prefix+".forwarding-target", ConfigDefault.ForwardingTargetImpl, "transaction forwarding target URL, or \"null\" to disable forwarding (iff not sequencer)") execution.AddOptionsForNodeForwarderConfig(prefix+".forwarder", f) execution.TxPreCheckerConfigAddOptions(prefix+".tx-pre-checker", f) @@ -418,6 +414,7 @@ var ConfigDefault = Config{ InboxReader: DefaultInboxReaderConfig, DelayedSequencer: DefaultDelayedSequencerConfig, BatchPoster: DefaultBatchPosterConfig, + MessagePruner: DefaultMessagePrunerConfig, ForwardingTargetImpl: "", TxPreChecker: execution.DefaultTxPreCheckerConfig, BlockValidator: staker.DefaultBlockValidatorConfig, @@ -502,6 +499,7 @@ type Node struct { InboxTracker *InboxTracker DelayedSequencer *DelayedSequencer BatchPoster *BatchPoster + MessagePruner *MessagePruner BlockValidator *staker.BlockValidator StatelessBlockValidator *staker.StatelessBlockValidator Staker *staker.Staker @@ -703,6 +701,7 @@ func createNodeImpl( nil, nil, nil, + nil, broadcastServer, broadcastClients, coordinator, @@ -863,6 +862,10 @@ func createNodeImpl( return nil, err } } + var messagePruner *MessagePruner + if config.MessagePruner.Enable && !config.Caching.Archive && stakerObj != nil { + messagePruner = NewMessagePruner(txStreamer, inboxTracker, stakerObj, func() *MessagePrunerConfig { return &configFetcher.Get().MessagePruner }) + } // always create DelayedSequencer, it won't do anything if it is disabled delayedSequencer, err = NewDelayedSequencer(l1Reader, inboxReader, exec.ExecEngine, coordinator, func() *DelayedSequencerConfig { return &configFetcher.Get().DelayedSequencer }) if err != nil { @@ -880,6 +883,7 @@ func createNodeImpl( inboxTracker, delayedSequencer, batchPoster, + messagePruner, blockValidator, statelessBlockValidator, stakerObj, @@ -1023,6 +1027,12 @@ func (n *Node) Start(ctx context.Context) error { return fmt.Errorf("error starting inbox reader: %w", err) } } + if n.DelayedSequencer != nil && n.SeqCoordinator == nil { + err = n.DelayedSequencer.ForceSequenceDelayed(ctx) + if err != nil { + return fmt.Errorf("error performing initial delayed sequencing: %w", err) + } + } err = n.Execution.TxPublisher.Start(ctx) if err != nil { return fmt.Errorf("error starting transaction puiblisher: %w", err) @@ -1039,6 +1049,9 @@ func (n *Node) Start(ctx context.Context) error { if n.BatchPoster != nil { n.BatchPoster.Start(ctx) } + if n.MessagePruner != nil { + n.MessagePruner.Start(ctx) + } if n.Staker != nil { err = n.Staker.Initialize(ctx) if err != nil { @@ -1118,6 +1131,9 @@ func (n *Node) StopAndWait() { if n.BatchPoster != nil && n.BatchPoster.Started() { n.BatchPoster.StopAndWait() } + if n.MessagePruner != nil && n.MessagePruner.Started() { + n.MessagePruner.StopAndWait() + } if n.BroadcastServer != nil && n.BroadcastServer.Started() { n.BroadcastServer.StopAndWait() } diff --git a/arbnode/sequencer_inbox.go b/arbnode/sequencer_inbox.go index a08e5b5c5a..2adfcb60b3 100644 --- a/arbnode/sequencer_inbox.go +++ b/arbnode/sequencer_inbox.go @@ -95,18 +95,18 @@ func (i *SequencerInbox) GetAccumulator(ctx context.Context, sequenceNumber uint } type SequencerInboxBatch struct { - BlockHash common.Hash - BlockNumber uint64 - SequenceNumber uint64 - BeforeInboxAcc common.Hash - AfterInboxAcc common.Hash - AfterDelayedAcc common.Hash - AfterDelayedCount uint64 - TimeBounds bridgegen.ISequencerInboxTimeBounds - rawLog types.Log - dataLocation batchDataLocation - bridgeAddress common.Address - serialized []byte // nil if serialization isn't cached yet + BlockHash common.Hash + ParentChainBlockNumber uint64 + SequenceNumber uint64 + BeforeInboxAcc common.Hash + AfterInboxAcc common.Hash + AfterDelayedAcc common.Hash + AfterDelayedCount uint64 + TimeBounds bridgegen.ISequencerInboxTimeBounds + rawLog types.Log + dataLocation batchDataLocation + bridgeAddress common.Address + serialized []byte // nil if serialization isn't cached yet } func (m *SequencerInboxBatch) getSequencerData(ctx context.Context, client arbutil.L1Interface) ([]byte, error) { @@ -222,17 +222,17 @@ func (i *SequencerInbox) LookupBatchesInRange(ctx context.Context, from, to *big } lastSeqNum = &seqNum batch := &SequencerInboxBatch{ - BlockHash: log.BlockHash, - BlockNumber: log.BlockNumber, - SequenceNumber: seqNum, - BeforeInboxAcc: parsedLog.BeforeAcc, - AfterInboxAcc: parsedLog.AfterAcc, - AfterDelayedAcc: parsedLog.DelayedAcc, - AfterDelayedCount: parsedLog.AfterDelayedMessagesRead.Uint64(), - rawLog: log, - TimeBounds: parsedLog.TimeBounds, - dataLocation: batchDataLocation(parsedLog.DataLocation), - bridgeAddress: log.Address, + BlockHash: log.BlockHash, + ParentChainBlockNumber: log.BlockNumber, + SequenceNumber: seqNum, + BeforeInboxAcc: parsedLog.BeforeAcc, + AfterInboxAcc: parsedLog.AfterAcc, + AfterDelayedAcc: parsedLog.DelayedAcc, + AfterDelayedCount: parsedLog.AfterDelayedMessagesRead.Uint64(), + rawLog: log, + TimeBounds: parsedLog.TimeBounds, + dataLocation: batchDataLocation(parsedLog.DataLocation), + bridgeAddress: log.Address, } messages = append(messages, batch) } diff --git a/arbnode/transaction_streamer.go b/arbnode/transaction_streamer.go index a7bea2e57f..a6a11b0b84 100644 --- a/arbnode/transaction_streamer.go +++ b/arbnode/transaction_streamer.go @@ -198,6 +198,40 @@ func deleteStartingAt(db ethdb.Database, batch ethdb.Batch, prefix []byte, minKe return iter.Error() } +// deleteFromRange deletes key ranging from startMinKey(inclusive) to endMinKey(exclusive) +func deleteFromRange(db ethdb.Database, prefix []byte, startMinKey uint64, endMinKey uint64) ([][]byte, error) { + batch := db.NewBatch() + startIter := db.NewIterator(prefix, uint64ToKey(startMinKey)) + defer startIter.Release() + var prunedKeysRange [][]byte + for startIter.Next() { + if binary.BigEndian.Uint64(bytes.TrimPrefix(startIter.Key(), prefix)) >= endMinKey { + break + } + if len(prunedKeysRange) == 0 || len(prunedKeysRange) == 1 { + prunedKeysRange = append(prunedKeysRange, startIter.Key()) + } else { + prunedKeysRange[1] = startIter.Key() + } + err := batch.Delete(startIter.Key()) + if err != nil { + return nil, err + } + if batch.ValueSize() >= ethdb.IdealBatchSize { + if err := batch.Write(); err != nil { + return nil, err + } + batch.Reset() + } + } + if batch.ValueSize() > 0 { + if err := batch.Write(); err != nil { + return nil, err + } + } + return prunedKeysRange, nil +} + // The insertion mutex must be held. This acquires the reorg mutex. // Note: oldMessages will be empty if reorgHook is nil func (s *TransactionStreamer) reorg(batch ethdb.Batch, count arbutil.MessageIndex, newMessages []arbostypes.MessageWithMetadata) error { diff --git a/arbos/arbosState/arbosstate.go b/arbos/arbosState/arbosstate.go index 333ad464ac..2bea8f7c54 100644 --- a/arbos/arbosState/arbosstate.go +++ b/arbos/arbosState/arbosstate.go @@ -4,7 +4,6 @@ package arbosState import ( - "encoding/json" "errors" "fmt" "math/big" @@ -19,6 +18,7 @@ import ( "github.com/offchainlabs/nitro/arbos/addressSet" "github.com/offchainlabs/nitro/arbos/addressTable" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/blockhash" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/arbos/l1pricing" @@ -112,11 +112,7 @@ func NewArbosMemoryBackedArbOSState() (*ArbosState, *state.StateDB) { } burner := burn.NewSystemBurner(nil, false) chainConfig := params.ArbitrumDevTestChainConfig() - serializedChainConfig, err := json.Marshal(chainConfig) - if err != nil { - log.Crit("failed to serialize chain config", "error", err) - } - newState, err := InitializeArbosState(statedb, burner, chainConfig, serializedChainConfig) + newState, err := InitializeArbosState(statedb, burner, chainConfig, arbostypes.TestInitMessage) if err != nil { log.Crit("failed to open the ArbOS state", "error", err) } @@ -183,7 +179,7 @@ func getArbitrumOnlyGenesisPrecompiles(chainConfig *params.ChainConfig) []common // start running long-lived chains, every change to the storage format will require defining a new version and // providing upgrade code. -func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *params.ChainConfig, serializedChainConfig []byte) (*ArbosState, error) { +func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage) (*ArbosState, error) { sto := storage.NewGeth(stateDB, burner) arbosVersion, err := sto.GetUint64ByUint64(uint64(versionOffset)) if err != nil { @@ -217,14 +213,14 @@ func InitializeArbosState(stateDB vm.StateDB, burner burn.Burner, chainConfig *p } _ = sto.SetByUint64(uint64(chainIdOffset), common.BigToHash(chainConfig.ChainID)) chainConfigStorage := sto.OpenStorageBackedBytes(chainConfigSubspace) - _ = chainConfigStorage.Set(serializedChainConfig) + _ = chainConfigStorage.Set(initMessage.SerializedChainConfig) _ = sto.SetUint64ByUint64(uint64(genesisBlockNumOffset), chainConfig.ArbitrumChainParams.GenesisBlockNum) initialRewardsRecipient := l1pricing.BatchPosterAddress if desiredArbosVersion >= 2 { initialRewardsRecipient = initialChainOwner } - _ = l1pricing.InitializeL1PricingState(sto.OpenSubStorage(l1PricingSubspace), initialRewardsRecipient) + _ = l1pricing.InitializeL1PricingState(sto.OpenSubStorage(l1PricingSubspace), initialRewardsRecipient, initMessage.InitialL1BaseFee) _ = l2pricing.InitializeL2PricingState(sto.OpenSubStorage(l2PricingSubspace)) _ = retryables.InitializeRetryableState(sto.OpenSubStorage(retryablesSubspace)) addressTable.Initialize(sto.OpenSubStorage(addressTableSubspace)) diff --git a/arbos/arbosState/initialization_test.go b/arbos/arbosState/initialization_test.go index 14ac8afa99..968f533e3e 100644 --- a/arbos/arbosState/initialization_test.go +++ b/arbos/arbosState/initialization_test.go @@ -12,8 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/statetransfer" "github.com/offchainlabs/nitro/util/testhelpers" @@ -60,11 +60,7 @@ func tryMarshalUnmarshal(input *statetransfer.ArbosInitializationInfo, t *testin initReader := statetransfer.NewMemoryInitDataReader(&initData) chainConfig := params.ArbitrumDevTestChainConfig() - serializedChainConfig, err := json.Marshal(chainConfig) - if err != nil { - log.Crit("failed to serialize chain config", "error", err) - } - stateroot, err := InitializeArbosInDatabase(raw, initReader, chainConfig, serializedChainConfig, 0, 0) + stateroot, err := InitializeArbosInDatabase(raw, initReader, chainConfig, arbostypes.TestInitMessage, 0, 0) Require(t, err) stateDb, err := state.New(stateroot, state.NewDatabase(raw), nil) diff --git a/arbos/arbosState/initialize.go b/arbos/arbosState/initialize.go index d30507ee81..e98ab08485 100644 --- a/arbos/arbosState/initialize.go +++ b/arbos/arbosState/initialize.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/arbos/l2pricing" "github.com/offchainlabs/nitro/arbos/retryables" @@ -49,7 +50,7 @@ func MakeGenesisBlock(parentHash common.Hash, blockNumber uint64, timestamp uint return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)) } -func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, serializedChainConfig []byte, timestamp uint64, accountsPerSync uint) (common.Hash, error) { +func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDataReader, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, timestamp uint64, accountsPerSync uint) (common.Hash, error) { stateDatabase := state.NewDatabase(db) statedb, err := state.New(common.Hash{}, stateDatabase, nil) if err != nil { @@ -73,7 +74,7 @@ func InitializeArbosInDatabase(db ethdb.Database, initData statetransfer.InitDat } burner := burn.NewSystemBurner(nil, false) - arbosState, err := InitializeArbosState(statedb, burner, chainConfig, serializedChainConfig) + arbosState, err := InitializeArbosState(statedb, burner, chainConfig, initMessage) if err != nil { log.Crit("failed to open the ArbOS state", "error", err) } diff --git a/arbos/arbostypes/incomingmessage.go b/arbos/arbostypes/incomingmessage.go index 9636bb095a..e9a5466d46 100644 --- a/arbos/arbostypes/incomingmessage.go +++ b/arbos/arbostypes/incomingmessage.go @@ -158,7 +158,7 @@ func (msg *L1IncomingMessage) FillInBatchGasCost(batchFetcher FallibleBatchFetch if batchFetcher == nil || msg.Header.Kind != L1MessageType_BatchPostingReport || msg.BatchGasCost != nil { return nil } - _, _, batchHash, batchNum, _, err := ParseBatchPostingReportMessageFields(bytes.NewReader(msg.L2msg)) + _, _, batchHash, batchNum, _, _, err := ParseBatchPostingReportMessageFields(bytes.NewReader(msg.L2msg)) if err != nil { return fmt.Errorf("failed to parse batch posting report: %w", err) } @@ -234,56 +234,95 @@ func ParseIncomingL1Message(rd io.Reader, batchFetcher FallibleBatchFetcher) (*L type FallibleBatchFetcher func(batchNum uint64) ([]byte, error) +type ParsedInitMessage struct { + ChainId *big.Int + InitialL1BaseFee *big.Int + + // These may be nil + ChainConfig *params.ChainConfig + SerializedChainConfig []byte +} + +// The initial L1 pricing basefee starts at 50 GWei unless set in the init message +var DefaultInitialL1BaseFee = big.NewInt(50 * params.GWei) + +var TestInitMessage = &ParsedInitMessage{ + ChainId: params.ArbitrumDevTestChainConfig().ChainID, + InitialL1BaseFee: DefaultInitialL1BaseFee, +} + // ParseInitMessage returns the chain id on success -func (msg *L1IncomingMessage) ParseInitMessage() (*big.Int, *params.ChainConfig, []byte, error) { +func (msg *L1IncomingMessage) ParseInitMessage() (*ParsedInitMessage, error) { if msg.Header.Kind != L1MessageType_Initialize { - return nil, nil, nil, fmt.Errorf("invalid init message kind %v", msg.Header.Kind) + return nil, fmt.Errorf("invalid init message kind %v", msg.Header.Kind) } + basefee := new(big.Int).Set(DefaultInitialL1BaseFee) var chainConfig params.ChainConfig var chainId *big.Int if len(msg.L2msg) == 32 { chainId = new(big.Int).SetBytes(msg.L2msg[:32]) - return chainId, nil, nil, nil + return &ParsedInitMessage{chainId, basefee, nil, nil}, nil } if len(msg.L2msg) > 32 { chainId = new(big.Int).SetBytes(msg.L2msg[:32]) version := msg.L2msg[32] - if version == 0 && len(msg.L2msg) > 33 { - serializedChainConfig := msg.L2msg[33:] - err := json.Unmarshal(serializedChainConfig, &chainConfig) + reader := bytes.NewReader(msg.L2msg[33:]) + switch version { + case 1: + var err error + basefee, err = util.Uint256FromReader(reader) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to parse init message, err: %w, message data: %v", err, string(msg.L2msg)) + return nil, err } - return chainId, &chainConfig, serializedChainConfig, nil + fallthrough + case 0: + serializedChainConfig, err := io.ReadAll(reader) + if err != nil { + return nil, err + } + err = json.Unmarshal(serializedChainConfig, &chainConfig) + if err != nil { + return nil, fmt.Errorf("failed to parse init message, err: %w, message data: %v", err, string(msg.L2msg)) + } + return &ParsedInitMessage{chainId, basefee, &chainConfig, serializedChainConfig}, nil } } - return nil, nil, nil, fmt.Errorf("invalid init message data %v", string(msg.L2msg)) + return nil, fmt.Errorf("invalid init message data %v", string(msg.L2msg)) } -func ParseBatchPostingReportMessageFields(rd io.Reader) (*big.Int, common.Address, common.Hash, uint64, *big.Int, error) { +func ParseBatchPostingReportMessageFields(rd io.Reader) (*big.Int, common.Address, common.Hash, uint64, *big.Int, uint64, error) { batchTimestamp, err := util.HashFromReader(rd) if err != nil { - return nil, common.Address{}, common.Hash{}, 0, nil, err + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err } batchPosterAddr, err := util.AddressFromReader(rd) if err != nil { - return nil, common.Address{}, common.Hash{}, 0, nil, err + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err } dataHash, err := util.HashFromReader(rd) if err != nil { - return nil, common.Address{}, common.Hash{}, 0, nil, err + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err } batchNum, err := util.HashFromReader(rd) if err != nil { - return nil, common.Address{}, common.Hash{}, 0, nil, err + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err } l1BaseFee, err := util.HashFromReader(rd) if err != nil { - return nil, common.Address{}, common.Hash{}, 0, nil, err + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err + } + extraGas, err := util.Uint64FromReader(rd) + if errors.Is(err, io.EOF) { + // This field isn't always present + extraGas = 0 + err = nil + } + if err != nil { + return nil, common.Address{}, common.Hash{}, 0, nil, 0, err } batchNumBig := batchNum.Big() if !batchNumBig.IsUint64() { - return nil, common.Address{}, common.Hash{}, 0, nil, fmt.Errorf("batch number %v is not a uint64", batchNumBig) + return nil, common.Address{}, common.Hash{}, 0, nil, 0, fmt.Errorf("batch number %v is not a uint64", batchNumBig) } - return batchTimestamp.Big(), batchPosterAddr, dataHash, batchNumBig.Uint64(), l1BaseFee.Big(), nil + return batchTimestamp.Big(), batchPosterAddr, dataHash, batchNumBig.Uint64(), l1BaseFee.Big(), extraGas, nil } diff --git a/arbos/block_processor.go b/arbos/block_processor.go index c5270e49ef..9f208c4404 100644 --- a/arbos/block_processor.go +++ b/arbos/block_processor.go @@ -78,7 +78,7 @@ func createNewHeader(prevHeader *types.Header, l1info *L1Info, state *arbosState copy(extra, prevHeader.Extra) mixDigest = prevHeader.MixDigest } - return &types.Header{ + header := &types.Header{ ParentHash: lastBlockHash, UncleHash: types.EmptyUncleHash, // Post-merge Ethereum will require this to be types.EmptyUncleHash Coinbase: coinbase, @@ -96,6 +96,7 @@ func createNewHeader(prevHeader *types.Header, l1info *L1Info, state *arbosState Nonce: [8]byte{}, // Filled in later; post-merge Ethereum will require this to be zero BaseFee: baseFee, } + return header } type ConditionalOptionsForTx []*arbitrum_types.ConditionalOptions @@ -323,6 +324,18 @@ func ProduceBlockAdvanced( return receipt, result, nil })() + if tx.Type() == types.ArbitrumInternalTxType { + // ArbOS might have upgraded to a new version, so we need to refresh our state + state, err = arbosState.OpenSystemArbosState(statedb, nil, true) + if err != nil { + return nil, nil, err + } + // Update the ArbOS version in the header (if it changed) + extraInfo := types.DeserializeHeaderExtraInformation(header) + extraInfo.ArbOSFormatVersion = state.ArbOSVersion() + extraInfo.UpdateHeaderWithInfo(header) + } + // append the err, even if it is nil hooks.TxErrors = append(hooks.TxErrors, err) diff --git a/arbos/l1pricing/l1pricing.go b/arbos/l1pricing/l1pricing.go index 059d56858e..9772ac028b 100644 --- a/arbos/l1pricing/l1pricing.go +++ b/arbos/l1pricing/l1pricing.go @@ -74,7 +74,6 @@ const ( const ( InitialInertia = 10 InitialPerUnitReward = 10 - InitialPricePerUnitWei = 50 * params.GWei InitialPerBatchGasCostV6 = 100000 ) @@ -82,7 +81,7 @@ const ( var InitialEquilibrationUnitsV0 = arbmath.UintToBig(60 * params.TxDataNonZeroGasEIP2028 * 100000) var InitialEquilibrationUnitsV6 = arbmath.UintToBig(params.TxDataNonZeroGasEIP2028 * 10000000) -func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient common.Address) error { +func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient common.Address, initialL1BaseFee *big.Int) error { bptStorage := sto.OpenSubStorage(BatchPosterTableKey) if err := InitializeBatchPostersTable(bptStorage); err != nil { return err @@ -109,7 +108,7 @@ func InitializeL1PricingState(sto *storage.Storage, initialRewardsRecipient comm return err } pricePerUnit := sto.OpenStorageBackedBigInt(pricePerUnitOffset) - if err := pricePerUnit.SetByUint(InitialPricePerUnitWei); err != nil { + if err := pricePerUnit.SetSaturatingWithWarning(initialL1BaseFee, "initial L1 base fee (storing in price per unit)"); err != nil { return err } return nil diff --git a/arbos/l1pricing/l1pricing_test.go b/arbos/l1pricing/l1pricing_test.go index ec0ecc275e..b301c94257 100644 --- a/arbos/l1pricing/l1pricing_test.go +++ b/arbos/l1pricing/l1pricing_test.go @@ -4,18 +4,19 @@ package l1pricing import ( + "math/big" "testing" - am "github.com/offchainlabs/nitro/util/arbmath" - "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/arbos/storage" ) func TestL1PriceUpdate(t *testing.T) { sto := storage.NewMemoryBacked(burn.NewSystemBurner(nil, false)) - err := InitializeL1PricingState(sto, common.Address{}) + initialPriceEstimate := big.NewInt(123 * params.GWei) + err := InitializeL1PricingState(sto, common.Address{}, initialPriceEstimate) Require(t, err) ps := OpenL1PricingState(sto) @@ -25,7 +26,6 @@ func TestL1PriceUpdate(t *testing.T) { Fail(t) } - initialPriceEstimate := am.UintToBig(InitialPricePerUnitWei) priceEstimate, err := ps.PricePerUnit() Require(t, err) if priceEstimate.Cmp(initialPriceEstimate) != 0 { diff --git a/arbos/parse_l2.go b/arbos/parse_l2.go index 5e8a9a5fc4..88018fdfcf 100644 --- a/arbos/parse_l2.go +++ b/arbos/parse_l2.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/util" + "github.com/offchainlabs/nitro/util/arbmath" ) type InfallibleBatchFetcher func(batchNum uint64, batchHash common.Hash) []byte @@ -370,7 +371,7 @@ func parseSubmitRetryableMessage(rd io.Reader, header *arbostypes.L1IncomingMess } func parseBatchPostingReportMessage(rd io.Reader, chainId *big.Int, msgBatchGasCost *uint64, batchFetcher InfallibleBatchFetcher) (*types.Transaction, error) { - batchTimestamp, batchPosterAddr, batchHash, batchNum, l1BaseFee, err := arbostypes.ParseBatchPostingReportMessageFields(rd) + batchTimestamp, batchPosterAddr, batchHash, batchNum, l1BaseFee, extraGas, err := arbostypes.ParseBatchPostingReportMessageFields(rd) if err != nil { return nil, err } @@ -381,6 +382,7 @@ func parseBatchPostingReportMessage(rd io.Reader, chainId *big.Int, msgBatchGasC batchData := batchFetcher(batchNum, batchHash) batchDataGas = arbostypes.ComputeBatchGasCost(batchData) } + batchDataGas = arbmath.SaturatingUAdd(batchDataGas, extraGas) data, err := util.PackInternalTxDataBatchPostingReport( batchTimestamp, batchPosterAddr, batchNum, batchDataGas, l1BaseFee, diff --git a/arbos/util/util.go b/arbos/util/util.go index 1514d6d10d..4c0142aeb9 100644 --- a/arbos/util/util.go +++ b/arbos/util/util.go @@ -108,6 +108,14 @@ func HashFromReader(rd io.Reader) (common.Hash, error) { return common.BytesToHash(buf), nil } +func Uint256FromReader(rd io.Reader) (*big.Int, error) { + asHash, err := HashFromReader(rd) + if err != nil { + return nil, err + } + return asHash.Big(), nil +} + func HashToWriter(val common.Hash, wr io.Writer) error { _, err := wr.Write(val.Bytes()) return err diff --git a/arbutil/correspondingl1blocknumber.go b/arbutil/correspondingl1blocknumber.go index 7f21cf6169..136eb8e4c9 100644 --- a/arbutil/correspondingl1blocknumber.go +++ b/arbutil/correspondingl1blocknumber.go @@ -11,14 +11,18 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) -func CorrespondingL1BlockNumber(ctx context.Context, client L1Interface, blockNumber uint64) (uint64, error) { - header, err := client.HeaderByNumber(ctx, big.NewInt(int64(blockNumber))) - if err != nil { - return 0, fmt.Errorf("error getting L1 block number %d header : %w", blockNumber, err) - } +func ParentHeaderToL1BlockNumber(header *types.Header) uint64 { headerInfo := types.DeserializeHeaderExtraInformation(header) - if headerInfo.L1BlockNumber != 0 { - return headerInfo.L1BlockNumber, nil + if headerInfo.ArbOSFormatVersion > 0 { + return headerInfo.L1BlockNumber + } + return header.Number.Uint64() +} + +func CorrespondingL1BlockNumber(ctx context.Context, client L1Interface, parentBlockNumber uint64) (uint64, error) { + header, err := client.HeaderByNumber(ctx, big.NewInt(int64(parentBlockNumber))) + if err != nil { + return 0, fmt.Errorf("error getting L1 block number %d header : %w", parentBlockNumber, err) } - return blockNumber, nil + return ParentHeaderToL1BlockNumber(header), nil } diff --git a/blockscout b/blockscout deleted file mode 160000 index c8db5b1bb9..0000000000 --- a/blockscout +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c8db5b1bb99b31f7348e6f760ba6dd22643c725a diff --git a/cmd/ipfshelper/ipfshelper.go b/cmd/ipfshelper/ipfshelper.go index 08c26b5d68..82e726dbf3 100644 --- a/cmd/ipfshelper/ipfshelper.go +++ b/cmd/ipfshelper/ipfshelper.go @@ -9,7 +9,6 @@ import ( "path/filepath" "strings" "sync" - "time" "github.com/ethereum/go-ethereum/log" "github.com/ipfs/go-libipfs/files" @@ -177,7 +176,6 @@ func (h *IpfsHelper) DownloadFile(ctx context.Context, cidString string, destina } fmt.Printf("\033[2K\rPinned %d / %d subtrees (%.2f%%)", done, all, float32(done)/float32(all)*100) } - rand.Seed(time.Now().UnixNano()) permutation := rand.Perm(len(links)) printProgress(0, len(links)) for i, j := range permutation { diff --git a/cmd/nitro/init.go b/cmd/nitro/init.go index 114514b53a..2284695961 100644 --- a/cmd/nitro/init.go +++ b/cmd/nitro/init.go @@ -389,7 +389,7 @@ func findImportantRoots(ctx context.Context, chainDb ethdb.Database, stack *node if err != nil { return nil, err } - if meta.L1Block <= l1BlockNum { + if meta.ParentChainBlock <= l1BlockNum { signedBlockNum := arbutil.MessageCountToBlockNumber(meta.MessageCount, genesisNum) blockNum := uint64(signedBlockNum) l2Hash := rawdb.ReadCanonicalHash(chainDb, blockNum) @@ -575,7 +575,7 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if config.Init.ThenQuit { cacheConfig.SnapshotWait = true } - var serializedChainConfig []byte + var parsedInitMessage *arbostypes.ParsedInitMessage if config.Node.L1Reader.Enable { delayedBridge, err := arbnode.NewDelayedBridge(l1Client, rollupAddrs.Bridge, rollupAddrs.DeployedAt) if err != nil { @@ -596,30 +596,34 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo if initMessage == nil { return chainDb, nil, fmt.Errorf("failed to get init message while attempting to get serialized chain config") } - var initChainConfig *params.ChainConfig - var initChainId *big.Int - initChainId, initChainConfig, serializedChainConfig, err = initMessage.ParseInitMessage() + parsedInitMessage, err = initMessage.ParseInitMessage() if err != nil { return chainDb, nil, err } - if initChainId.Cmp(chainId) != 0 { - return chainDb, nil, fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", chainId, initChainId) + if parsedInitMessage.ChainId.Cmp(chainId) != 0 { + return chainDb, nil, fmt.Errorf("expected L2 chain ID %v but read L2 chain ID %v from init message in L1 inbox", chainId, parsedInitMessage.ChainId) } - if initChainConfig != nil { - if err := initChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil { + if parsedInitMessage.ChainConfig != nil { + if err := parsedInitMessage.ChainConfig.CheckCompatible(chainConfig, chainConfig.ArbitrumChainParams.GenesisBlockNum, 0); err != nil { return chainDb, nil, fmt.Errorf("incompatible chain config read from init message in L1 inbox: %w", err) } } - log.Info("Read serialized chain config from init message", "json", string(serializedChainConfig)) + log.Info("Read serialized chain config from init message", "json", string(parsedInitMessage.SerializedChainConfig)) } else { - serializedChainConfig, err = json.Marshal(chainConfig) + serializedChainConfig, err := json.Marshal(chainConfig) if err != nil { return chainDb, nil, err } - log.Warn("Serialized chain config as L1Reader is disabled and serialized chain config from init message is not available", "json", string(serializedChainConfig)) + parsedInitMessage = &arbostypes.ParsedInitMessage{ + ChainId: chainConfig.ChainID, + InitialL1BaseFee: arbostypes.DefaultInitialL1BaseFee, + ChainConfig: chainConfig, + SerializedChainConfig: serializedChainConfig, + } + log.Warn("Created fake init message as L1Reader is disabled and serialized chain config from init message is not available", "json", string(serializedChainConfig)) } - l2BlockChain, err = execution.WriteOrTestBlockChain(chainDb, cacheConfig, initDataReader, chainConfig, serializedChainConfig, config.Node.TxLookupLimit, config.Init.AccountsPerSync) + l2BlockChain, err = execution.WriteOrTestBlockChain(chainDb, cacheConfig, initDataReader, chainConfig, parsedInitMessage, config.Node.TxLookupLimit, config.Init.AccountsPerSync) if err != nil { return chainDb, nil, err } diff --git a/cmd/replay/main.go b/cmd/replay/main.go index 32e30cc892..501562d265 100644 --- a/cmd/replay/main.go +++ b/cmd/replay/main.go @@ -244,19 +244,20 @@ func main() { message := readMessage(false) - chainId, chainConfig, serializedChainConfig, err := message.Message.ParseInitMessage() + initMessage, err := message.Message.ParseInitMessage() if err != nil { panic(err) } + chainConfig := initMessage.ChainConfig if chainConfig == nil { log.Info("No chain config in the init message. Falling back to hardcoded chain config.") - chainConfig, err = chaininfo.GetChainConfig(chainId, "", 0, []string{}, "") + chainConfig, err = chaininfo.GetChainConfig(initMessage.ChainId, "", 0, []string{}, "") if err != nil { panic(err) } } - _, err = arbosState.InitializeArbosState(statedb, burn.NewSystemBurner(nil, false), chainConfig, serializedChainConfig) + _, err = arbosState.InitializeArbosState(statedb, burn.NewSystemBurner(nil, false), chainConfig, initMessage) if err != nil { panic(fmt.Sprintf("Error initializing ArbOS: %v", err.Error())) } diff --git a/contracts b/contracts index f48ce451e4..1b10711dc5 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit f48ce451e4bc2dbea9024cdc08fd0eb410fa61b5 +Subproject commit 1b10711dc5f2eeefebc8c9f07d5c5f580534f703 diff --git a/das/ipfs_storage_service.go b/das/ipfs_storage_service.go index 4d92e85c73..4f73242c22 100644 --- a/das/ipfs_storage_service.go +++ b/das/ipfs_storage_service.go @@ -79,11 +79,6 @@ func NewIpfsStorageService(ctx context.Context, config IpfsStorageServiceConfig) } log.Info("IPFS node started up", "hostAddresses", addrs) - if config.PinAfterGet { - if config.PinPercentage != 100.0 { - rand.Seed(time.Now().UnixNano()) - } - } return &IpfsStorageService{ config: config, ipfsHelper: ipfsHelper, diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 6b23f898a3..0000000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,340 +0,0 @@ -version: "3.9" -services: - blockscout: - depends_on: - - postgres - - sequencer - image: blockscout-testnode - restart: always - container_name: 'blockscout' - links: - - postgres:database - command: - - /bin/sh - - -c - - | - bin/blockscout eval "Elixir.Explorer.ReleaseTasks.create_and_migrate()" - node init/install.js postgres 5432 - bin/blockscout start - extra_hosts: - - 'host.docker.internal:host-gateway' - env_file: - - ./blockscout/nitro.env - environment: - ETHEREUM_JSONRPC_VARIANT: 'geth' - ETHEREUM_JSONRPC_HTTP_URL: http://sequencer:8547/ - INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: "true" - DATABASE_URL: postgresql://postgres:@postgres:5432/blockscout - ECTO_USE_SSL: "false" - ports: - - "127.0.0.1:4000:4000" - - postgres: - image: postgres:13.6 - restart: always - container_name: 'postgres' - environment: - POSTGRES_PASSWORD: '' - POSTGRES_USER: 'postgres' - POSTGRES_HOST_AUTH_METHOD: 'trust' - volumes: - - "postgres-data:/var/lib/postgresql/data" - ports: - - "127.0.0.1:7432:5432" - - redis: - image: redis:6.2.6 - ports: - - "127.0.0.1:6379:6379" - - geth: - image: ethereum/client-go:v1.10.23 - ports: - - "127.0.0.1:8545:8545" - - "127.0.0.1:8551:8551" - - "127.0.0.1:8546:8546" - - "127.0.0.1:30303:30303" - volumes: - - "l1data:/datadir" - - "l1keystore:/keystore" - - "config:/config" - command: - - --keystore=/keystore - - --http - - --datadir=/datadir - - --http.addr=0.0.0.0 - - --authrpc.vhosts=* - - --authrpc.port=8551 - - --authrpc.addr=0.0.0.0 - - --http.vhosts=* - - --http.api=engine,personal,eth,net,web3 - - --http.corsdomain=* - - --ws - - --ws.addr=0.0.0.0 - - --ws.api=personal,eth,net,web3,debug,txpool - - --allow-insecure-unlock - - --unlock=0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E - - --password=/datadir/passphrase - - --authrpc.jwtsecret=/config/jwt.hex - - --nodiscover - - --syncmode=full - - --dev - - --dev.period=1 - - --mine - - --miner.etherbase=0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E - - --gcmode=archive - - # Creates a genesis state for the beacon chain using a YAML configuration file and - # a deterministic set of validators - # TODO: Make num validators customizable - create_beacon_chain_genesis: - image: "gcr.io/prysmaticlabs/prysm/cmd/prysmctl:latest" - command: - - testnet - - generate-genesis - - --num-validators=64 - - --output-ssz=/consensus/genesis.ssz - - --chain-config-file=/config/prysm.yaml - volumes: - - "consensus:/consensus" - - "config:/config" - - # Runs a Prysm beacon chain from a specified genesis state created in the previous step - # and connects to go-ethereum in the same network as the execution client. - # The account used in go-ethereum is set as the suggested fee recipient for transactions - # proposed via the validators attached to the beacon node. - prysm_beacon_chain: - image: "gcr.io/prysmaticlabs/prysm/beacon-chain:stable" - command: - - --datadir=/consensus/beacondata - - --rpc-port=5000 - - --min-sync-peers=0 - - --interop-genesis-state=/consensus/genesis.ssz - - --interop-eth1data-votes - - --bootstrap-node= - - --chain-config-file=/config/prysm.yaml - - --rpc-host=0.0.0.0 - - --grpc-gateway-host=0.0.0.0 - - --chain-id=32382 - - --execution-endpoint=http://geth:8551 - - --accept-terms-of-use - - --jwt-secret=/config/jwt.hex - depends_on: - geth: - condition: service_started - create_beacon_chain_genesis: - condition: service_completed_successfully - ports: - - "127.0.0.1:5000:5000" - - "127.0.0.1:3500:3500" - volumes: - - "consensus:/consensus" - - "config:/config" - - # We run a validator client with 64, deterministically-generated keys that match - # The validator keys present in the beacon chain genesis state generated a few steps above. - prysm_validator: - image: "gcr.io/prysmaticlabs/prysm/validator:stable" - command: - - --beacon-rpc-provider=prysm_beacon_chain:5000 - - --datadir=/consensus/validatordata - - --accept-terms-of-use - - --interop-num-validators=64 - - --interop-start-index=0 - - --chain-config-file=/config/prysm.yaml - depends_on: - prysm_beacon_chain: - condition: service_started - volumes: - - "consensus:/consensus" - - "config:/config" - - sequencer: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8547:8547" - - "127.0.0.1:8548:8548" - - "127.0.0.1:9642:9642" - volumes: - - "seqdata:/home/user/.arbitrum/local/nitro" - - "config:/config" - command: --conf.file /config/sequencer_config.json --node.feed.output.enable --node.feed.output.port 9642 --http.api net,web3,eth,txpool,debug --node.seq-coordinator.my-url ws://sequencer:8548 --graphql.enable --graphql.vhosts * --graphql.corsdomain * - depends_on: - - geth - - redis - - - sequencer_b: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8647:8547" - - "127.0.0.1:8648:8548" - volumes: - - "seqdata_b:/home/user/.arbitrum/local/nitro" - - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_b:8548 - depends_on: - - geth - - redis - - sequencer_c: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8747:8547" - - "127.0.0.1:8748:8548" - volumes: - - "seqdata_c:/home/user/.arbitrum/local/nitro" - - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_c:8548 - depends_on: - - geth - - redis - - sequencer_d: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8847:8547" - - "127.0.0.1:8848:8548" - volumes: - - "seqdata_d:/home/user/.arbitrum/local/nitro" - - "config:/config" - command: --conf.file /config/sequencer_config.json --node.seq-coordinator.my-url ws://sequencer_d:8548 - depends_on: - - geth - - redis - - staker-unsafe: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8047:8547" - - "127.0.0.1:8048:8548" - volumes: - - "unsafestaker-data:/home/user/.arbitrum/local/nitro" - - "l1keystore:/home/user/l1keystore" - - "config:/config" - command: --conf.file /config/unsafe_staker_config.json - depends_on: - - sequencer - - redis - - validation_node - - poster: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8147:8547" - - "127.0.0.1:8148:8548" - volumes: - - "poster-data:/home/user/.arbitrum/local/nitro" - - "l1keystore:/home/user/l1keystore" - - "config:/config" - command: --conf.file /config/poster_config.json - depends_on: - - geth - - redis - - poster_b: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:9147:8547" - - "127.0.0.1:9148:8548" - volumes: - - "poster-data-b:/home/user/.arbitrum/local/nitro" - - "l1keystore:/home/user/l1keystore" - - "config:/config" - command: --conf.file /config/poster_config.json - depends_on: - - geth - - redis - - poster_c: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:9247:8547" - - "127.0.0.1:9248:8548" - volumes: - - "poster-data-c:/home/user/.arbitrum/local/nitro" - - "l1keystore:/home/user/l1keystore" - - "config:/config" - command: --conf.file /config/poster_config.json - depends_on: - - geth - - redis - - validator: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8247:8547" - - "127.0.0.1:8248:8548" - volumes: - - "validator-data:/home/user/.arbitrum/local/nitro" - - "l1keystore:/home/user/l1keystore" - - "config:/config" - command: --conf.file /config/validator_config.json --http.port 8547 --http.api net,web3,arb,debug --ws.port 8548 - depends_on: - - sequencer - - validation_node - - validation_node: - pid: host # allow debugging - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:8949:8549" - volumes: - - "config:/config" - command: --conf.file /config/validation_node_config.json - entrypoint: /usr/local/bin/nitro-val - - testnode-scripts: - build: testnode-scripts/ - volumes: - - "l1keystore:/home/user/l1keystore" - - "config:/config" - depends_on: - - redis - - relay: - pid: host - image: nitro-node-dev-testnode - ports: - - "127.0.0.1:9652:9652" - entrypoint: bin/relay - command: --node.feed.output.port 9652 --node.feed.input.url ws://sequencer:9652 - - testnode-tokenbridge: - depends_on: - - geth - - sequencer - pid: host - build: testnode-tokenbridge/ - environment: - - ARB_URL=http://sequencer:8547 - - ETH_URL=http://geth:8545 - volumes: - - "sdk-data:/workspace" - - /var/run/docker.sock:/var/run/docker.sock - -volumes: - l1data: - consensus: - l1keystore: - seqdata: - seqdata_b: - seqdata_c: - seqdata_d: - unsafestaker-data: - validator-data: - poster-data: - poster-data-b: - poster-data-c: - config: - postgres-data: - sdk-data: diff --git a/go-ethereum b/go-ethereum index ff6d43316c..8e6a8ad494 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit ff6d43316c4b8186e2a7c80cf4bcfaf8e87075d4 +Subproject commit 8e6a8ad4942591011e833e6ebceca6bd668f3db0 diff --git a/go.mod b/go.mod index 907fe6e2b0..fc52f1f763 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/offchainlabs/nitro -go 1.19 +go 1.20 replace github.com/VictoriaMetrics/fastcache => ./fastcache diff --git a/nitro-testnode b/nitro-testnode new file mode 160000 index 0000000000..14f24a1bad --- /dev/null +++ b/nitro-testnode @@ -0,0 +1 @@ +Subproject commit 14f24a1bad2625412602d06156156c380bd589d2 diff --git a/nodeInterface/NodeInterface.go b/nodeInterface/NodeInterface.go index 41475b167d..fd1e224b0f 100644 --- a/nodeInterface/NodeInterface.go +++ b/nodeInterface/NodeInterface.go @@ -106,14 +106,14 @@ func (n NodeInterface) GetL1Confirmations(c ctx, evm mech, blockHash bytes32) (u if err != nil { return 0, err } - if latestL1Block < meta.L1Block || arbutil.BlockNumberToMessageCount(blockNum, genesis) > meta.MessageCount { + if latestL1Block < meta.ParentChainBlock || arbutil.BlockNumberToMessageCount(blockNum, genesis) > meta.MessageCount { return 0, nil } canonicalHash := bc.GetCanonicalHash(header.Number.Uint64()) if canonicalHash != header.Hash() { return 0, errors.New("block hash is non-canonical") } - confs := (latestL1Block - meta.L1Block) + 1 + node.InboxReader.GetDelayBlocks() + confs := (latestL1Block - meta.ParentChainBlock) + 1 + node.InboxReader.GetDelayBlocks() return confs, nil } diff --git a/build-brotli.sh b/scripts/build-brotli.sh similarity index 86% rename from build-brotli.sh rename to scripts/build-brotli.sh index e09ce6a315..7160936baa 100755 --- a/build-brotli.sh +++ b/scripts/build-brotli.sh @@ -9,8 +9,9 @@ BUILD_WASM=false BUILD_LOCAL=false BUILD_SOFTFLOAT=false USE_DOCKER=false -TARGET_DIR=target/ -SOURCE_DIR=brotli +TARGET_DIR=../target/ +SOURCE_DIR=../brotli +NITRO_DIR=../ usage(){ echo "brotli builder for arbitrum" @@ -28,12 +29,13 @@ usage(){ echo "Other options:" echo " -s source dir default: $SOURCE_DIR" echo " -t target dir default: $TARGET_DIR" + echo " -n nitro dir default: $NITRO_DIR" echo " -h help" echo echo "all relative paths are relative to script location" } -while getopts "s:t:c:wldhf" option; do +while getopts "s:t:c:D:wldhf" option; do case $option in h) usage @@ -54,6 +56,9 @@ while getopts "s:t:c:wldhf" option; do t) TARGET_DIR="$OPTARG" ;; + n) + NITRO_DIR="$OPTARG" + ;; s) SOURCE_DIR="$OPTARG" ;; @@ -74,13 +79,13 @@ TARGET_DIR_ABS=`cd -P "$TARGET_DIR"; pwd` if $USE_DOCKER; then if $BUILD_WASM; then - DOCKER_BUILDKIT=1 docker build --target brotli-wasm-export -o type=local,dest="$TARGET_DIR_ABS" . + DOCKER_BUILDKIT=1 docker build --target brotli-wasm-export -o type=local,dest="$TARGET_DIR_ABS" "${NITRO_DIR}" fi if $BUILD_LOCAL; then - DOCKER_BUILDKIT=1 docker build --target brotli-library-export -o type=local,dest="$TARGET_DIR_ABS" . + DOCKER_BUILDKIT=1 docker build --target brotli-library-export -o type=local,dest="$TARGET_DIR_ABS" "${NITRO_DIR}" fi if $BUILD_SOFTFLOAT; then - DOCKER_BUILDKIT=1 docker build --target wasm-libs-export -o type=local,dest="$TARGET_DIR_ABS" . + DOCKER_BUILDKIT=1 docker build --target wasm-libs-export -o type=local,dest="$TARGET_DIR_ABS" "${NITRO_DIR}" fi exit 0 fi diff --git a/testnode-scripts/download-machine.sh b/scripts/download-machine.sh similarity index 100% rename from testnode-scripts/download-machine.sh rename to scripts/download-machine.sh diff --git a/fuzz.bash b/scripts/fuzz.bash similarity index 78% rename from fuzz.bash rename to scripts/fuzz.bash index 5dd29c17e6..d236f90ce8 100755 --- a/fuzz.bash +++ b/scripts/fuzz.bash @@ -7,7 +7,7 @@ cd "$mydir" function printusage { echo Usage: $0 --build \[--binary-path PATH\] - echo " " $0 \ \[--binary-path PATH\] \[--fuzzcache-path PATH\] + echo " " $0 \ \[--binary-path PATH\] \[--fuzzcache-path PATH\] \[--nitro-path PATH\] echo echo fuzzer names: echo " " FuzzPrecompiles @@ -20,13 +20,23 @@ if [[ $# -eq 0 ]]; then exit fi -fuzz_executable=./target/bin/system_test.fuzz -binpath=./target/bin/ -fuzzcachepath=./target/var/fuzz-cache +fuzz_executable=../target/bin/system_test.fuzz +binpath=../target/bin/ +fuzzcachepath=../target/var/fuzz-cache +nitropath=../ run_build=false test_group="" while [[ $# -gt 0 ]]; do case $1 in + --nitro-path) + nitropath="$2"/ + if [[ ! -d "$nitropath" ]]; then + echo must supply valid path for nitro-path + exit 1 + fi + shift + shift + ;; --binary-path) binpath="$2"/ if [[ ! -d "$binpath" ]]; then @@ -75,7 +85,7 @@ done if $run_build; then for build_group in system_tests arbstate; do - go test -c ./$build_group -fuzz Fuzz -o "$binpath"/${build_group}.fuzz + go test -c ${nitropath}/${build_group} -fuzz Fuzz -o "$binpath"/${build_group}.fuzz done fi diff --git a/solgen/gen.go b/solgen/gen.go index 6b044e8c85..c29db93039 100644 --- a/solgen/gen.go +++ b/solgen/gen.go @@ -131,7 +131,7 @@ func main() { fmt.Println("successfully generated go abi files") - blockscout := filepath.Join(parent, "blockscout", "init", "data") + blockscout := filepath.Join(parent, "nitro-testnode", "blockscout", "init", "data") if _, err := os.Stat(blockscout); err != nil { fmt.Println("skipping abi export since blockscout is not present") } else { diff --git a/staker/assertion.go b/staker/assertion.go index 5ba2b274cf..8d09abf866 100644 --- a/staker/assertion.go +++ b/staker/assertion.go @@ -13,7 +13,7 @@ import ( "github.com/offchainlabs/nitro/validator" ) -func NewAssertionFromSolidity(assertion rollupgen.RollupLibAssertion) *Assertion { +func NewAssertionFromSolidity(assertion rollupgen.Assertion) *Assertion { return &Assertion{ BeforeState: validator.NewExecutionStateFromSolidity(assertion.BeforeState), AfterState: validator.NewExecutionStateFromSolidity(assertion.AfterState), @@ -21,8 +21,8 @@ func NewAssertionFromSolidity(assertion rollupgen.RollupLibAssertion) *Assertion } } -func (a *Assertion) AsSolidityStruct() rollupgen.RollupLibAssertion { - return rollupgen.RollupLibAssertion{ +func (a *Assertion) AsSolidityStruct() rollupgen.Assertion { + return rollupgen.Assertion{ BeforeState: a.BeforeState.AsSolidityStruct(), AfterState: a.AfterState.AsSolidityStruct(), NumBlocks: a.NumBlocks, @@ -63,13 +63,14 @@ type Assertion struct { } type NodeInfo struct { - NodeNum uint64 - BlockProposed uint64 - Assertion *Assertion - InboxMaxCount *big.Int - AfterInboxBatchAcc common.Hash - NodeHash common.Hash - WasmModuleRoot common.Hash + NodeNum uint64 + L1BlockProposed uint64 + ParentChainBlockProposed uint64 + Assertion *Assertion + InboxMaxCount *big.Int + AfterInboxBatchAcc common.Hash + NodeHash common.Hash + WasmModuleRoot common.Hash } func (n *NodeInfo) AfterState() *validator.ExecutionState { diff --git a/staker/block_validator.go b/staker/block_validator.go index f186ee6cb1..56bb2729c7 100644 --- a/staker/block_validator.go +++ b/staker/block_validator.go @@ -603,15 +603,19 @@ func (v *BlockValidator) sendValidations(ctx context.Context) { defer cancel() validationStatus.Cancel = cancel err := v.ValidationEntryAddSeqMessage(ctx, validationStatus.Entry, startPos, endPos, seqMsg) - if err != nil && validationCtx.Err() == nil { + if err != nil { validationStatus.replaceStatus(Prepared, RecordFailed) - log.Error("error preparing validation", "err", err) + if validationCtx.Err() == nil { + log.Error("error preparing validation", "err", err) + } return } input, err := validationStatus.Entry.ToInput() - if err != nil && validationCtx.Err() == nil { + if err != nil { validationStatus.replaceStatus(Prepared, RecordFailed) - log.Error("error preparing validation", "err", err) + if validationCtx.Err() == nil { + log.Error("error preparing validation", "err", err) + } return } for _, moduleRoot := range wasmRoots { diff --git a/staker/builder_backend.go b/staker/builder_backend.go index 77b6e2db88..1bf15ff027 100644 --- a/staker/builder_backend.go +++ b/staker/builder_backend.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/offchainlabs/nitro/arbutil" @@ -76,18 +77,27 @@ func (b *ValidatorTxBuilder) SendTransaction(ctx context.Context, tx *types.Tran return nil } -func (b *ValidatorTxBuilder) AuthWithAmount(ctx context.Context, amount *big.Int) *bind.TransactOpts { +// While this is not currently required, it's recommended not to reuse the returned auth for multiple transactions, +// as for an EOA this has the nonce in it. However, the EOA wwallet currently will only publish the first created tx, +// which is why that doesn't really matter. +func (b *ValidatorTxBuilder) AuthWithAmount(ctx context.Context, amount *big.Int) (*bind.TransactOpts, error) { + nonce, err := b.NonceAt(ctx, b.builderAuth.From, nil) + if err != nil { + return nil, err + } return &bind.TransactOpts{ From: b.builderAuth.From, - Nonce: b.builderAuth.Nonce, + Nonce: new(big.Int).SetUint64(nonce), Signer: b.builderAuth.Signer, Value: amount, GasPrice: b.builderAuth.GasPrice, GasLimit: b.builderAuth.GasLimit, Context: ctx, - } + }, nil } -func (b *ValidatorTxBuilder) Auth(ctx context.Context) *bind.TransactOpts { - return b.AuthWithAmount(ctx, big.NewInt(0)) +// Auth is the same as AuthWithAmount with a 0 amount specified. +// See AuthWithAmount docs for important details. +func (b *ValidatorTxBuilder) Auth(ctx context.Context) (*bind.TransactOpts, error) { + return b.AuthWithAmount(ctx, common.Big0) } diff --git a/staker/l1_validator.go b/staker/l1_validator.go index b21ee655e9..f16d4c9538 100644 --- a/staker/l1_validator.go +++ b/staker/l1_validator.go @@ -169,7 +169,11 @@ func (v *L1Validator) resolveNextNode(ctx context.Context, info *StakerInfo, lat return false, nil } log.Warn("rejecting node", "node", unresolvedNodeIndex) - _, err = v.rollup.RejectNextNode(v.builder.Auth(ctx), *addr) + auth, err := v.builder.Auth(ctx) + if err != nil { + return false, err + } + _, err = v.rollup.RejectNextNode(auth, *addr) return true, err case CONFIRM_TYPE_VALID: nodeInfo, err := v.rollup.LookupNode(ctx, unresolvedNodeIndex) @@ -178,7 +182,11 @@ func (v *L1Validator) resolveNextNode(ctx context.Context, info *StakerInfo, lat } afterGs := nodeInfo.AfterState().GlobalState log.Info("confirming node", "node", unresolvedNodeIndex) - _, err = v.rollup.ConfirmNextNode(v.builder.Auth(ctx), afterGs.BlockHash, afterGs.SendRoot) + auth, err := v.builder.Auth(ctx) + if err != nil { + return false, err + } + _, err = v.rollup.ConfirmNextNode(auth, afterGs.BlockHash, afterGs.SendRoot) if err != nil { return false, err } @@ -253,14 +261,14 @@ func (v *L1Validator) blockNumberFromGlobalState(gs validator.GoGlobalState) (in } func (v *L1Validator) generateNodeAction(ctx context.Context, stakerInfo *OurStakerInfo, strategy StakerStrategy, makeAssertionInterval time.Duration) (nodeAction, bool, error) { - startState, prevInboxMaxCount, startStateProposed, err := lookupNodeStartState(ctx, v.rollup, stakerInfo.LatestStakedNode, stakerInfo.LatestStakedNodeHash) + startState, prevInboxMaxCount, startStateProposedL1, startStateProposedParentChain, err := lookupNodeStartState(ctx, v.rollup, stakerInfo.LatestStakedNode, stakerInfo.LatestStakedNodeHash) if err != nil { return nil, false, fmt.Errorf("error looking up node %v (hash %v) start state: %w", stakerInfo.LatestStakedNode, stakerInfo.LatestStakedNodeHash, err) } - startStateProposedHeader, err := v.client.HeaderByNumber(ctx, new(big.Int).SetUint64(startStateProposed)) + startStateProposedHeader, err := v.client.HeaderByNumber(ctx, new(big.Int).SetUint64(startStateProposedParentChain)) if err != nil { - return nil, false, fmt.Errorf("error looking up L1 header of block %v of node start state: %w", startStateProposed, err) + return nil, false, fmt.Errorf("error looking up L1 header of block %v of node start state: %w", startStateProposedParentChain, err) } startStateProposedTime := time.Unix(int64(startStateProposedHeader.Time), 0) @@ -340,7 +348,7 @@ func (v *L1Validator) generateNodeAction(ctx context.Context, stakerInfo *OurSta return nil, false, fmt.Errorf("error getting latest L1 block number: %w", err) } - parentChainBlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, v.client, currentL1BlockNum) + l1BlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, v.client, currentL1BlockNum) if err != nil { return nil, false, err } @@ -350,7 +358,7 @@ func (v *L1Validator) generateNodeAction(ctx context.Context, stakerInfo *OurSta return nil, false, fmt.Errorf("error getting rollup minimum assertion period: %w", err) } - timeSinceProposed := big.NewInt(int64(parentChainBlockNumber) - int64(startStateProposed)) + timeSinceProposed := big.NewInt(int64(l1BlockNumber) - int64(startStateProposedL1)) if timeSinceProposed.Cmp(minAssertionPeriod) < 0 { // Too soon to assert return nil, false, nil @@ -594,28 +602,28 @@ func (v *L1Validator) createNewNodeAction( return action, nil } -// Returns (execution state, inbox max count, L1 block proposed, error) -func lookupNodeStartState(ctx context.Context, rollup *RollupWatcher, nodeNum uint64, nodeHash [32]byte) (*validator.ExecutionState, *big.Int, uint64, error) { +// Returns (execution state, inbox max count, L1 block proposed, parent chain block proposed, error) +func lookupNodeStartState(ctx context.Context, rollup *RollupWatcher, nodeNum uint64, nodeHash common.Hash) (*validator.ExecutionState, *big.Int, uint64, uint64, error) { if nodeNum == 0 { creationEvent, err := rollup.LookupCreation(ctx) if err != nil { - return nil, nil, 0, fmt.Errorf("error looking up rollup creation event: %w", err) + return nil, nil, 0, 0, fmt.Errorf("error looking up rollup creation event: %w", err) } - parentChainBlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, rollup.client, creationEvent.Raw.BlockNumber) + l1BlockNumber, err := arbutil.CorrespondingL1BlockNumber(ctx, rollup.client, creationEvent.Raw.BlockNumber) if err != nil { - return nil, nil, 0, err + return nil, nil, 0, 0, err } return &validator.ExecutionState{ GlobalState: validator.GoGlobalState{}, MachineStatus: validator.MachineStatusFinished, - }, big.NewInt(1), parentChainBlockNumber, nil + }, big.NewInt(1), l1BlockNumber, creationEvent.Raw.BlockNumber, nil } node, err := rollup.LookupNode(ctx, nodeNum) if err != nil { - return nil, nil, 0, err + return nil, nil, 0, 0, err } if node.NodeHash != nodeHash { - return nil, nil, 0, errors.New("looked up starting node but found wrong hash") + return nil, nil, 0, 0, errors.New("looked up starting node but found wrong hash") } - return node.AfterState(), node.InboxMaxCount, node.BlockProposed, nil + return node.AfterState(), node.InboxMaxCount, node.L1BlockProposed, node.ParentChainBlockProposed, nil } diff --git a/staker/rollup_watcher.go b/staker/rollup_watcher.go index e26dae9eca..aaaa30ce32 100644 --- a/staker/rollup_watcher.go +++ b/staker/rollup_watcher.go @@ -128,24 +128,29 @@ func (r *RollupWatcher) LookupNode(ctx context.Context, number uint64) (*NodeInf return nil, err } if len(logs) == 0 { - return nil, errors.New("Couldn't find requested node") + return nil, fmt.Errorf("couldn't find requested node %v", number) } if len(logs) > 1 { - return nil, errors.New("Found multiple instances of requested node") + return nil, fmt.Errorf("found multiple instances of requested node %v", number) } ethLog := logs[0] parsedLog, err := r.ParseNodeCreated(ethLog) if err != nil { return nil, err } + l1BlockProposed, err := arbutil.CorrespondingL1BlockNumber(ctx, r.client, ethLog.BlockNumber) + if err != nil { + return nil, err + } return &NodeInfo{ - NodeNum: parsedLog.NodeNum, - BlockProposed: ethLog.BlockNumber, - Assertion: NewAssertionFromSolidity(parsedLog.Assertion), - InboxMaxCount: parsedLog.InboxMaxCount, - AfterInboxBatchAcc: parsedLog.AfterInboxBatchAcc, - NodeHash: parsedLog.NodeHash, - WasmModuleRoot: parsedLog.WasmModuleRoot, + NodeNum: parsedLog.NodeNum, + L1BlockProposed: l1BlockProposed, + ParentChainBlockProposed: ethLog.BlockNumber, + Assertion: NewAssertionFromSolidity(parsedLog.Assertion), + InboxMaxCount: parsedLog.InboxMaxCount, + AfterInboxBatchAcc: parsedLog.AfterInboxBatchAcc, + NodeHash: parsedLog.NodeHash, + WasmModuleRoot: parsedLog.WasmModuleRoot, }, nil } @@ -186,14 +191,19 @@ func (r *RollupWatcher) LookupNodeChildren(ctx context.Context, nodeNum uint64, lastHashIsSibling[0] = 1 } lastHash = crypto.Keccak256Hash(lastHashIsSibling[:], lastHash[:], parsedLog.ExecutionHash[:], parsedLog.AfterInboxBatchAcc[:], parsedLog.WasmModuleRoot[:]) + l1BlockProposed, err := arbutil.CorrespondingL1BlockNumber(ctx, r.client, ethLog.BlockNumber) + if err != nil { + return nil, err + } infos = append(infos, &NodeInfo{ - NodeNum: parsedLog.NodeNum, - BlockProposed: ethLog.BlockNumber, - Assertion: NewAssertionFromSolidity(parsedLog.Assertion), - InboxMaxCount: parsedLog.InboxMaxCount, - AfterInboxBatchAcc: parsedLog.AfterInboxBatchAcc, - NodeHash: lastHash, - WasmModuleRoot: parsedLog.WasmModuleRoot, + NodeNum: parsedLog.NodeNum, + L1BlockProposed: l1BlockProposed, + ParentChainBlockProposed: ethLog.BlockNumber, + Assertion: NewAssertionFromSolidity(parsedLog.Assertion), + InboxMaxCount: parsedLog.InboxMaxCount, + AfterInboxBatchAcc: parsedLog.AfterInboxBatchAcc, + NodeHash: lastHash, + WasmModuleRoot: parsedLog.WasmModuleRoot, }) } return infos, nil diff --git a/staker/staker.go b/staker/staker.go index aa464d574c..baaf81f9a2 100644 --- a/staker/staker.go +++ b/staker/staker.go @@ -291,9 +291,10 @@ func (s *Staker) Start(ctxIn context.Context) { arbTx, err := s.Act(ctx) if err == nil && arbTx != nil { _, err = s.l1Reader.WaitForTxApproval(ctx, arbTx) - err = fmt.Errorf("error waiting for tx receipt: %w", err) if err == nil { log.Info("successfully executed staker transaction", "hash", arbTx.Hash()) + } else { + err = fmt.Errorf("error waiting for tx receipt: %w", err) } } if err == nil { @@ -513,11 +514,19 @@ func (s *Staker) Act(ctx context.Context) (*types.Transaction, error) { stakeIsUnwanted := effectiveStrategy < StakeLatestStrategy if stakeIsTooOutdated || stakeIsUnwanted { // Note: we must have an address if rawInfo != nil - _, err = s.rollup.ReturnOldDeposit(s.builder.Auth(ctx), walletAddressOrZero) + auth, err := s.builder.Auth(ctx) + if err != nil { + return nil, err + } + _, err = s.rollup.ReturnOldDeposit(auth, walletAddressOrZero) if err != nil { return nil, fmt.Errorf("error returning old deposit (from our staker %v): %w", walletAddressOrZero, err) } - _, err = s.rollup.WithdrawStakerFunds(s.builder.Auth(ctx)) + auth, err = s.builder.Auth(ctx) + if err != nil { + return nil, err + } + _, err = s.rollup.WithdrawStakerFunds(auth) if err != nil { return nil, fmt.Errorf("error withdrawing staker funds from our staker %v: %w", walletAddressOrZero, err) } @@ -532,7 +541,11 @@ func (s *Staker) Act(ctx context.Context) (*types.Transaction, error) { return nil, fmt.Errorf("error checking withdrawable funds of our staker %v: %w", walletAddressOrZero, err) } if withdrawable.Sign() > 0 { - _, err = s.rollup.WithdrawStakerFunds(s.builder.Auth(ctx)) + auth, err := s.builder.Auth(ctx) + if err != nil { + return nil, err + } + _, err = s.rollup.WithdrawStakerFunds(auth) if err != nil { return nil, fmt.Errorf("error withdrawing our staker %v funds: %w", walletAddressOrZero, err) } @@ -650,7 +663,11 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv // We'll return early if we already have a stake if info.StakeExists { - _, err = s.rollup.StakeOnNewNode(s.builder.Auth(ctx), action.assertion.AsSolidityStruct(), action.hash, action.prevInboxMaxCount) + auth, err := s.builder.Auth(ctx) + if err != nil { + return err + } + _, err = s.rollup.StakeOnNewNode(auth, action.assertion.AsSolidityStruct(), action.hash, action.prevInboxMaxCount) if err != nil { return fmt.Errorf("error staking on new node: %w", err) } @@ -662,8 +679,12 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv if err != nil { return fmt.Errorf("error getting current required stake: %w", err) } + auth, err := s.builder.AuthWithAmount(ctx, stakeAmount) + if err != nil { + return err + } _, err = s.rollup.NewStakeOnNewNode( - s.builder.AuthWithAmount(ctx, stakeAmount), + auth, action.assertion.AsSolidityStruct(), action.hash, action.prevInboxMaxCount, @@ -692,7 +713,11 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv log.Info("staking on existing node", "node", action.number) // We'll return early if we already havea stake if info.StakeExists { - _, err = s.rollup.StakeOnExistingNode(s.builder.Auth(ctx), action.number, action.hash) + auth, err := s.builder.Auth(ctx) + if err != nil { + return err + } + _, err = s.rollup.StakeOnExistingNode(auth, action.number, action.hash) if err != nil { return fmt.Errorf("error staking on existing node: %w", err) } @@ -704,8 +729,12 @@ func (s *Staker) advanceStake(ctx context.Context, info *OurStakerInfo, effectiv if err != nil { return fmt.Errorf("error getting current required stake: %w", err) } + auth, err := s.builder.AuthWithAmount(ctx, stakeAmount) + if err != nil { + return err + } _, err = s.rollup.NewStakeOnExistingNode( - s.builder.AuthWithAmount(ctx, stakeAmount), + auth, action.number, action.hash, ) @@ -781,15 +810,19 @@ func (s *Staker) createConflict(ctx context.Context, info *StakerInfo) error { return fmt.Errorf("error looking up node %v: %w", conflictInfo.Node2, err) } log.Warn("creating challenge", "node1", conflictInfo.Node1, "node2", conflictInfo.Node2, "otherStaker", staker) + auth, err := s.builder.Auth(ctx) + if err != nil { + return err + } _, err = s.rollup.CreateChallenge( - s.builder.Auth(ctx), + auth, [2]common.Address{staker1, staker2}, [2]uint64{conflictInfo.Node1, conflictInfo.Node2}, node1Info.MachineStatuses(), node1Info.GlobalStates(), node1Info.Assertion.NumBlocks, node2Info.Assertion.ExecutionHash(), - [2]*big.Int{new(big.Int).SetUint64(node1Info.BlockProposed), new(big.Int).SetUint64(node2Info.BlockProposed)}, + [2]*big.Int{new(big.Int).SetUint64(node1Info.L1BlockProposed), new(big.Int).SetUint64(node2Info.L1BlockProposed)}, [2][32]byte{node1Info.WasmModuleRoot, node2Info.WasmModuleRoot}, ) if err != nil { @@ -804,6 +837,10 @@ func (s *Staker) Strategy() StakerStrategy { return s.config.strategy } +func (s *Staker) Rollup() *RollupWatcher { + return s.rollup +} + func (s *Staker) updateStakerBalanceMetric(ctx context.Context) { txSenderAddress := s.wallet.TxSenderAddress() if txSenderAddress == nil { diff --git a/staker/validator_wallet.go b/staker/validator_wallet.go index ebecaaf979..c36efa7b61 100644 --- a/staker/validator_wallet.go +++ b/staker/validator_wallet.go @@ -152,12 +152,25 @@ func (v *ContractValidatorWallet) From() common.Address { return v.auth.From } -func (v *ContractValidatorWallet) executeTransaction(ctx context.Context, tx *types.Transaction, gasRefunder common.Address) (*types.Transaction, error) { - oldAuthValue := v.auth.Value - v.auth.Value = tx.Value() - defer (func() { v.auth.Value = oldAuthValue })() +// nil value == 0 value +func (v *ContractValidatorWallet) getAuth(ctx context.Context, value *big.Int) (*bind.TransactOpts, error) { + newAuth := *v.auth + newAuth.Context = ctx + newAuth.Value = value + nonce, err := v.L1Client().NonceAt(ctx, v.auth.From, nil) + if err != nil { + return nil, err + } + newAuth.Nonce = new(big.Int).SetUint64(nonce) + return &newAuth, nil +} - return v.con.ExecuteTransactionWithGasRefunder(v.auth, gasRefunder, tx.Data(), *tx.To(), tx.Value()) +func (v *ContractValidatorWallet) executeTransaction(ctx context.Context, tx *types.Transaction, gasRefunder common.Address) (*types.Transaction, error) { + auth, err := v.getAuth(ctx, tx.Value()) + if err != nil { + return nil, err + } + return v.con.ExecuteTransactionWithGasRefunder(auth, gasRefunder, tx.Data(), *tx.To(), tx.Value()) } func (v *ContractValidatorWallet) populateWallet(ctx context.Context, createIfMissing bool) error { @@ -171,7 +184,11 @@ func (v *ContractValidatorWallet) populateWallet(ctx context.Context, createIfMi return nil } if v.address == nil { - addr, err := GetValidatorWalletContract(ctx, v.walletFactoryAddr, v.rollupFromBlock, v.auth, v.l1Reader, createIfMissing) + auth, err := v.getAuth(ctx, nil) + if err != nil { + return err + } + addr, err := GetValidatorWalletContract(ctx, v.walletFactoryAddr, v.rollupFromBlock, auth, v.l1Reader, createIfMissing) if err != nil { return err } @@ -248,14 +265,15 @@ func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, build return nil, err } - oldAuthValue := v.auth.Value - v.auth.Value = new(big.Int).Sub(totalAmount, balanceInContract) - if v.auth.Value.Sign() < 0 { - v.auth.Value.SetInt64(0) + callValue := new(big.Int).Sub(totalAmount, balanceInContract) + if callValue.Sign() < 0 { + callValue.SetInt64(0) } - defer (func() { v.auth.Value = oldAuthValue })() - - arbTx, err := v.con.ExecuteTransactionsWithGasRefunder(v.auth, gasRefunder, data, dest, amount) + auth, err := v.getAuth(ctx, callValue) + if err != nil { + return nil, err + } + arbTx, err := v.con.ExecuteTransactionsWithGasRefunder(auth, gasRefunder, data, dest, amount) if err != nil { return nil, err } @@ -264,7 +282,11 @@ func (v *ContractValidatorWallet) ExecuteTransactions(ctx context.Context, build } func (v *ContractValidatorWallet) TimeoutChallenges(ctx context.Context, challenges []uint64) (*types.Transaction, error) { - return v.con.TimeoutChallenges(v.auth, v.challengeManagerAddress, challenges) + auth, err := v.getAuth(ctx, nil) + if err != nil { + return nil, err + } + return v.con.TimeoutChallenges(auth, v.challengeManagerAddress, challenges) } func (v *ContractValidatorWallet) L1Client() arbutil.L1Interface { diff --git a/system_tests/aliasing_test.go b/system_tests/aliasing_test.go index 716cb6fef8..5e4e65a2ca 100644 --- a/system_tests/aliasing_test.go +++ b/system_tests/aliasing_test.go @@ -44,10 +44,10 @@ func TestAliasing(t *testing.T) { alias, err := arbsys.MyCallersAddressWithoutAliasing(nil) Require(t, err) if !top { - Fail(t, "direct call is not top level") + Fatal(t, "direct call is not top level") } if was || alias != (common.Address{}) { - Fail(t, "direct call has an alias", was, alias) + Fatal(t, "direct call has an alias", was, alias) } testL2Signed := func(top, direct, static, delegate, callcode, call bool) { diff --git a/system_tests/batch_poster_test.go b/system_tests/batch_poster_test.go index fcf04c98f0..8c656cb2d3 100644 --- a/system_tests/batch_poster_test.go +++ b/system_tests/batch_poster_test.go @@ -118,14 +118,14 @@ func testBatchPosterParallel(t *testing.T, useRedis bool) { if i == 0 { continue } - if batches[i-1].BlockNumber == batches[i].BlockNumber { + if batches[i-1].ParentChainBlockNumber == batches[i].ParentChainBlockNumber { foundMultipleInBlock = true break } } if !foundMultipleInBlock { - Fail(t, "only found one batch per block") + Fatal(t, "only found one batch per block") } } @@ -133,7 +133,7 @@ func testBatchPosterParallel(t *testing.T, useRedis bool) { Require(t, err) if l2balance.Sign() == 0 { - Fail(t, "Unexpected zero balance") + Fatal(t, "Unexpected zero balance") } } @@ -164,7 +164,7 @@ func TestBatchPosterLargeTx(t *testing.T) { receiptB, err := EnsureTxSucceededWithTimeout(ctx, l2clientB, tx, time.Second*30) Require(t, err) if receiptA.BlockHash != receiptB.BlockHash { - Fail(t, "receipt A block hash", receiptA.BlockHash, "does not equal receipt B block hash", receiptB.BlockHash) + Fatal(t, "receipt A block hash", receiptA.BlockHash, "does not equal receipt B block hash", receiptB.BlockHash) } } diff --git a/system_tests/block_validator_test.go b/system_tests/block_validator_test.go index c5279a03ed..b3fd8ddb6c 100644 --- a/system_tests/block_validator_test.go +++ b/system_tests/block_validator_test.go @@ -17,8 +17,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/offchainlabs/nitro/arbnode" "github.com/offchainlabs/nitro/arbos/l2pricing" + "github.com/offchainlabs/nitro/solgen/go/precompilesgen" ) type workloadType uint @@ -27,6 +29,7 @@ const ( ethSend workloadType = iota smallContract depleteGas + upgradeArbOs ) func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops int, workload workloadType, arbitrator bool) { @@ -36,6 +39,9 @@ func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops chainConfig, l1NodeConfigA, lifecycleManager, _, dasSignerKey := setupConfigWithDAS(t, ctx, dasModeString) defer lifecycleManager.StopAndWaitUntil(time.Second) + if workload == upgradeArbOs { + chainConfig.ArbitrumChainParams.InitialArbOSVersion = 10 + } l2info, nodeA, l2client, l1info, _, l1client, l1stack := createTestNodeOnL1WithConfig(t, ctx, true, l1NodeConfigA, chainConfig, nil) defer requireClose(t, l1stack) @@ -54,50 +60,73 @@ func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops perTransfer := big.NewInt(1e12) - for i := 0; i < workloadLoops; i++ { - var tx *types.Transaction - - if workload == ethSend { - tx = l2info.PrepareTx("Owner", "User2", l2info.TransferGas, perTransfer, nil) - } else { - var contractCode []byte - var gas uint64 - - if workload == smallContract { - contractCode = []byte{byte(vm.PUSH0)} - contractCode = append(contractCode, byte(vm.PUSH0)) - contractCode = append(contractCode, byte(vm.PUSH1)) - contractCode = append(contractCode, 8) // the prelude length - contractCode = append(contractCode, byte(vm.PUSH0)) - contractCode = append(contractCode, byte(vm.CODECOPY)) - contractCode = append(contractCode, byte(vm.PUSH0)) - contractCode = append(contractCode, byte(vm.RETURN)) - basefee := GetBaseFee(t, l2client, ctx) - var err error - gas, err = l2client.EstimateGas(ctx, ethereum.CallMsg{ - From: l2info.GetAddress("Owner"), - GasPrice: basefee, - Value: big.NewInt(0), - Data: contractCode, - }) - Require(t, err) + if workload != upgradeArbOs { + for i := 0; i < workloadLoops; i++ { + var tx *types.Transaction + + if workload == ethSend { + tx = l2info.PrepareTx("Owner", "User2", l2info.TransferGas, perTransfer, nil) } else { - contractCode = []byte{0x5b} // JUMPDEST - for i := 0; i < 20; i++ { - contractCode = append(contractCode, 0x60, 0x00, 0x60, 0x00, 0x52) // PUSH1 0 MSTORE + var contractCode []byte + var gas uint64 + + if workload == smallContract { + contractCode = []byte{byte(vm.PUSH0)} + contractCode = append(contractCode, byte(vm.PUSH0)) + contractCode = append(contractCode, byte(vm.PUSH1)) + contractCode = append(contractCode, 8) // the prelude length + contractCode = append(contractCode, byte(vm.PUSH0)) + contractCode = append(contractCode, byte(vm.CODECOPY)) + contractCode = append(contractCode, byte(vm.PUSH0)) + contractCode = append(contractCode, byte(vm.RETURN)) + basefee := GetBaseFee(t, l2client, ctx) + var err error + gas, err = l2client.EstimateGas(ctx, ethereum.CallMsg{ + From: l2info.GetAddress("Owner"), + GasPrice: basefee, + Value: big.NewInt(0), + Data: contractCode, + }) + Require(t, err) + } else { + contractCode = []byte{0x5b} // JUMPDEST + for i := 0; i < 20; i++ { + contractCode = append(contractCode, 0x60, 0x00, 0x60, 0x00, 0x52) // PUSH1 0 MSTORE + } + contractCode = append(contractCode, 0x60, 0x00, 0x56) // JUMP + gas = l2info.TransferGas*2 + l2pricing.InitialPerBlockGasLimitV6 } - contractCode = append(contractCode, 0x60, 0x00, 0x56) // JUMP - gas = l2info.TransferGas*2 + l2pricing.InitialPerBlockGasLimitV6 + tx = l2info.PrepareTxTo("Owner", nil, gas, common.Big0, contractCode) + } + + err := l2client.SendTransaction(ctx, tx) + Require(t, err) + _, err = EnsureTxSucceededWithTimeout(ctx, l2client, tx, time.Second*5) + if workload != depleteGas { + Require(t, err) } - tx = l2info.PrepareTxTo("Owner", nil, gas, common.Big0, contractCode) } + } else { + auth := l2info.GetDefaultTransactOpts("Owner", ctx) + // make auth a chain owner + arbDebug, err := precompilesgen.NewArbDebug(common.HexToAddress("0xff"), l2client) + Require(t, err) + tx, err := arbDebug.BecomeChainOwner(&auth) + Require(t, err) + _, err = EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) + arbOwner, err := precompilesgen.NewArbOwner(common.HexToAddress("0x70"), l2client) + Require(t, err) + tx, err = arbOwner.ScheduleArbOSUpgrade(&auth, 11, 0) + Require(t, err) + _, err = EnsureTxSucceeded(ctx, l2client, tx) + Require(t, err) - err := l2client.SendTransaction(ctx, tx) + tx = l2info.PrepareTxTo("Owner", nil, l2info.TransferGas, perTransfer, []byte{byte(vm.PUSH0)}) + err = l2client.SendTransaction(ctx, tx) Require(t, err) _, err = EnsureTxSucceededWithTimeout(ctx, l2client, tx, time.Second*5) - if workload != depleteGas { - Require(t, err) - } + Require(t, err) } if workload != depleteGas { @@ -125,7 +154,7 @@ func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops expectedBalance := new(big.Int).Mul(perTransfer, big.NewInt(int64(workloadLoops+1))) if l2balance.Cmp(expectedBalance) != 0 { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } } @@ -148,7 +177,7 @@ func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops t.Log("waiting for block: ", lastBlock.NumberU64()) timeout := getDeadlineTimeout(t, time.Minute*10) if !nodeB.BlockValidator.WaitForBlock(ctx, lastBlock.NumberU64(), timeout) { - Fail(t, "did not validate all blocks") + Fatal(t, "did not validate all blocks") } finalRefCount := nodeB.BlockValidator.RecordDBReferenceCount() lastBlockNow, err := l2clientB.BlockByNumber(ctx, nil) @@ -156,10 +185,14 @@ func testBlockValidatorSimple(t *testing.T, dasModeString string, workloadLoops // up to 3 extra references: awaiting validation, recently valid, lastValidatedHeader largestRefCount := lastBlockNow.NumberU64() - lastBlock.NumberU64() + 3 if finalRefCount < 0 || finalRefCount > int64(largestRefCount) { - Fail(t, "unexpected refcount:", finalRefCount) + Fatal(t, "unexpected refcount:", finalRefCount) } } +func TestBlockValidatorSimpleOnchainUpgradeArbOs(t *testing.T) { + testBlockValidatorSimple(t, "onchain", 1, upgradeArbOs, true) +} + func TestBlockValidatorSimpleOnchain(t *testing.T) { testBlockValidatorSimple(t, "onchain", 1, ethSend, true) } diff --git a/system_tests/bloom_test.go b/system_tests/bloom_test.go index c932e0f185..9ad3253d4a 100644 --- a/system_tests/bloom_test.go +++ b/system_tests/bloom_test.go @@ -84,7 +84,7 @@ func TestBloom(t *testing.T) { for { sectionSize, sectionNum := node.Execution.Backend.APIBackend().BloomStatus() if sectionSize != 256 { - Fail(t, "unexpected section size: ", sectionSize) + Fatal(t, "unexpected section size: ", sectionSize) } t.Log("sections: ", sectionNum, "/", uint64(countsNum)/sectionSize) if sectionSize*(sectionNum+1) > uint64(countsNum) && sectionNum > 1 { @@ -102,7 +102,7 @@ func TestBloom(t *testing.T) { logs, err := client.FilterLogs(ctx, nullEventQuery) Require(t, err) if len(logs) != len(nullEventCounts) { - Fail(t, "expected ", len(nullEventCounts), " logs, got ", len(logs)) + Fatal(t, "expected ", len(nullEventCounts), " logs, got ", len(logs)) } incrementEventQuery := ethereum.FilterQuery{ Topics: [][]common.Hash{{simpleABI.Events["CounterEvent"].ID}}, @@ -110,14 +110,14 @@ func TestBloom(t *testing.T) { logs, err = client.FilterLogs(ctx, incrementEventQuery) Require(t, err) if len(logs) != len(eventCounts) { - Fail(t, "expected ", len(eventCounts), " logs, got ", len(logs)) + Fatal(t, "expected ", len(eventCounts), " logs, got ", len(logs)) } for _, log := range logs { parsedLog, err := simple.ParseCounterEvent(log) Require(t, err) _, expected := eventCounts[parsedLog.Count-1] if !expected { - Fail(t, "unxpected count in logs: ", parsedLog.Count) + Fatal(t, "unxpected count in logs: ", parsedLog.Count) } } } diff --git a/system_tests/common_test.go b/system_tests/common_test.go index e471899ff9..7c9b6b1191 100644 --- a/system_tests/common_test.go +++ b/system_tests/common_test.go @@ -18,6 +18,7 @@ import ( "github.com/offchainlabs/nitro/validator/server_api" "github.com/offchainlabs/nitro/validator/valnode" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/util" "github.com/offchainlabs/nitro/arbstate" "github.com/offchainlabs/nitro/blsSignatures" @@ -105,7 +106,7 @@ func BridgeBalance( l2acct := l2info.GetInfoWithPrivKey(account) if l2acct.PrivateKey.X.Cmp(l1acct.PrivateKey.X) != 0 || l2acct.PrivateKey.Y.Cmp(l1acct.PrivateKey.Y) != 0 { - Fail(t, "l2 account already exists and not compatible to l1") + Fatal(t, "l2 account already exists and not compatible to l1") } } @@ -137,7 +138,7 @@ func BridgeBalance( } TransferBalance(t, "Faucet", "User", big.NewInt(1), l1info, l1client, ctx) if i > 20 { - Fail(t, "bridging failed") + Fatal(t, "bridging failed") } <-time.After(time.Millisecond * 100) } @@ -281,7 +282,7 @@ func createTestL1BlockChain(t *testing.T, l1info info) (info, *ethclient.Client, return createTestL1BlockChainWithConfig(t, l1info, nil) } -func getTestStackConfig(t *testing.T) *node.Config { +func stackConfigForTest(t *testing.T) *node.Config { stackConfig := node.DefaultConfig stackConfig.HTTPPort = 0 stackConfig.WSPort = 0 @@ -345,16 +346,17 @@ type validated interface { Validate() error } -func StaticFetcherFrom[T any](t *testing.T, config T) func() T { +func StaticFetcherFrom[T any](t *testing.T, config *T) func() *T { t.Helper() - asEmptyIf := interface{}(config) + tCopy := *config + asEmptyIf := interface{}(&tCopy) if asValidtedIf, ok := asEmptyIf.(validated); ok { err := asValidtedIf.Validate() if err != nil { - Fail(t, err) + Fatal(t, err) } } - return func() T { return config } + return func() *T { return &tCopy } } func configByValidationNode(t *testing.T, clientConfig *arbnode.Config, valStack *node.Node) { @@ -380,7 +382,7 @@ func createTestL1BlockChainWithConfig(t *testing.T, l1info info, stackConfig *no l1info = NewL1TestInfo(t) } if stackConfig == nil { - stackConfig = getTestStackConfig(t) + stackConfig = stackConfigForTest(t) } l1info.GenerateAccount("Faucet") @@ -431,9 +433,24 @@ func createTestL1BlockChainWithConfig(t *testing.T, l1info info, stackConfig *no return l1info, l1Client, l1backend, stack } +func getInitMessage(ctx context.Context, t *testing.T, l1client client, addresses *chaininfo.RollupAddresses) *arbostypes.ParsedInitMessage { + bridge, err := arbnode.NewDelayedBridge(l1client, addresses.Bridge, addresses.DeployedAt) + Require(t, err) + deployedAtBig := arbmath.UintToBig(addresses.DeployedAt) + messages, err := bridge.LookupMessagesInRange(ctx, deployedAtBig, deployedAtBig, nil) + Require(t, err) + if len(messages) == 0 { + Fatal(t, "No delayed messages found at rollup creation block") + } + initMessage, err := messages[0].Message.ParseInitMessage() + Require(t, err, "Failed to parse rollup init message") + + return initMessage +} + func DeployOnTestL1( t *testing.T, ctx context.Context, l1info info, l1client client, chainConfig *params.ChainConfig, -) *chaininfo.RollupAddresses { +) (*chaininfo.RollupAddresses, *arbostypes.ParsedInitMessage) { l1info.GenerateAccount("RollupOwner") l1info.GenerateAccount("Sequencer") l1info.GenerateAccount("User") @@ -461,17 +478,18 @@ func DeployOnTestL1( l1info.SetContract("Bridge", addresses.Bridge) l1info.SetContract("SequencerInbox", addresses.SequencerInbox) l1info.SetContract("Inbox", addresses.Inbox) - return addresses + initMessage := getInitMessage(ctx, t, l1client, addresses) + return addresses, initMessage } func createL2BlockChain( t *testing.T, l2info *BlockchainTestInfo, dataDir string, chainConfig *params.ChainConfig, ) (*BlockchainTestInfo, *node.Node, ethdb.Database, ethdb.Database, *core.BlockChain) { - return createL2BlockChainWithStackConfig(t, l2info, dataDir, chainConfig, nil) + return createL2BlockChainWithStackConfig(t, l2info, dataDir, chainConfig, nil, nil) } func createL2BlockChainWithStackConfig( - t *testing.T, l2info *BlockchainTestInfo, dataDir string, chainConfig *params.ChainConfig, stackConfig *node.Config, + t *testing.T, l2info *BlockchainTestInfo, dataDir string, chainConfig *params.ChainConfig, initMessage *arbostypes.ParsedInitMessage, stackConfig *node.Config, ) (*BlockchainTestInfo, *node.Node, ethdb.Database, ethdb.Database, *core.BlockChain) { if l2info == nil { l2info = NewArbTestInfo(t, chainConfig.ChainID) @@ -492,9 +510,17 @@ func createL2BlockChainWithStackConfig( Require(t, err) initReader := statetransfer.NewMemoryInitDataReader(&l2info.ArbInitData) - serializedChainConfig, err := json.Marshal(chainConfig) - Require(t, err) - blockchain, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, serializedChainConfig, arbnode.ConfigDefaultL2Test().TxLookupLimit, 0) + if initMessage == nil { + serializedChainConfig, err := json.Marshal(chainConfig) + Require(t, err) + initMessage = &arbostypes.ParsedInitMessage{ + ChainId: chainConfig.ChainID, + InitialL1BaseFee: arbostypes.DefaultInitialL1BaseFee, + ChainConfig: chainConfig, + SerializedChainConfig: serializedChainConfig, + } + } + blockchain, err := execution.WriteOrTestBlockChain(chainDb, nil, initReader, chainConfig, initMessage, arbnode.ConfigDefaultL2Test().TxLookupLimit, 0) Require(t, err) return l2info, stack, chainDb, arbDb, blockchain @@ -560,8 +586,8 @@ func createTestNodeOnL1WithConfigImpl( if l2info == nil { l2info = NewArbTestInfo(t, chainConfig.ChainID) } - _, l2stack, l2chainDb, l2arbDb, l2blockchain = createL2BlockChainWithStackConfig(t, l2info, "", chainConfig, stackConfig) - addresses := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) + addresses, initMessage := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) + _, l2stack, l2chainDb, l2arbDb, l2blockchain = createL2BlockChainWithStackConfig(t, l2info, "", chainConfig, initMessage, stackConfig) var sequencerTxOptsPtr *bind.TransactOpts var dataSigner signature.DataSignerFunc if isSequencer { @@ -656,7 +682,7 @@ func Require(t *testing.T, err error, text ...interface{}) { testhelpers.RequireImpl(t, err, text...) } -func Fail(t *testing.T, printables ...interface{}) { +func Fatal(t *testing.T, printables ...interface{}) { t.Helper() testhelpers.FailImpl(t, printables...) } @@ -692,12 +718,12 @@ func Create2ndNodeWithConfig( feedErrChan := make(chan error, 10) l1rpcClient, err := l1stack.Attach() if err != nil { - Fail(t, err) + Fatal(t, err) } l1client := ethclient.NewClient(l1rpcClient) if stackConfig == nil { - stackConfig = getTestStackConfig(t) + stackConfig = stackConfigForTest(t) } l2stack, err := node.New(stackConfig) Require(t, err) @@ -711,11 +737,8 @@ func Create2ndNodeWithConfig( dataSigner := signature.DataSignerFromPrivateKey(l1info.GetInfoWithPrivKey("Sequencer").PrivateKey) txOpts := l1info.GetDefaultTransactOpts("Sequencer", ctx) chainConfig := first.Execution.ArbInterface.BlockChain().Config() - serializedChainConfig, err := json.Marshal(chainConfig) - if err != nil { - Fail(t, err) - } - l2blockchain, err := execution.WriteOrTestBlockChain(l2chainDb, nil, initReader, chainConfig, serializedChainConfig, arbnode.ConfigDefaultL2Test().TxLookupLimit, 0) + initMessage := getInitMessage(ctx, t, l1client, first.DeployInfo) + l2blockchain, err := execution.WriteOrTestBlockChain(l2chainDb, nil, initReader, chainConfig, initMessage, arbnode.ConfigDefaultL2Test().TxLookupLimit, 0) Require(t, err) AddDefaultValNode(t, ctx, nodeConfig, true) @@ -790,7 +813,7 @@ func setupConfigWithDAS( case "onchain": enableDas = false default: - Fail(t, "unknown storage type") + Fatal(t, "unknown storage type") } dbPath = t.TempDir() dasSignerKey, _, err := das.GenerateAndStoreKeys(dbPath) diff --git a/system_tests/conditionaltx_test.go b/system_tests/conditionaltx_test.go index 950938a756..c65103694a 100644 --- a/system_tests/conditionaltx_test.go +++ b/system_tests/conditionaltx_test.go @@ -53,7 +53,7 @@ func testConditionalTxThatShouldSucceed(t *testing.T, ctx context.Context, idx i tx := l2info.PrepareTx("Owner", "User2", l2info.TransferGas, big.NewInt(1e12), nil) err := arbitrum.SendConditionalTransactionRPC(ctx, rpcClient, tx, options) if err != nil { - Fail(t, "SendConditionalTransactionRPC failed, idx:", idx, "err:", err) + Fatal(t, "SendConditionalTransactionRPC failed, idx:", idx, "err:", err) } } @@ -65,18 +65,18 @@ func testConditionalTxThatShouldFail(t *testing.T, ctx context.Context, idx int, err := arbitrum.SendConditionalTransactionRPC(ctx, rpcClient, tx, options) if err == nil { if options == nil { - Fail(t, "SendConditionalTransactionRPC didn't fail as expected, idx:", idx, "options:", options) + Fatal(t, "SendConditionalTransactionRPC didn't fail as expected, idx:", idx, "options:", options) } else { - Fail(t, "SendConditionalTransactionRPC didn't fail as expected, idx:", idx, "options:", *options) + Fatal(t, "SendConditionalTransactionRPC didn't fail as expected, idx:", idx, "options:", *options) } } else { var rErr rpc.Error if errors.As(err, &rErr) { if rErr.ErrorCode() != expectedErrorCode { - Fail(t, "unexpected error code, have:", rErr.ErrorCode(), "want:", expectedErrorCode) + Fatal(t, "unexpected error code, have:", rErr.ErrorCode(), "want:", expectedErrorCode) } } else { - Fail(t, "unexpected error type, err:", err) + Fatal(t, "unexpected error type, err:", err) } } accountInfo.Nonce = nonce // revert nonce as the tx failed @@ -264,14 +264,14 @@ func TestSendRawTransactionConditionalBasic(t *testing.T) { previousStorageRootHash1 := currentRootHash1 currentRootHash1 = getStorageRootHash(t, node, contractAddress1) if bytes.Equal(previousStorageRootHash1.Bytes(), currentRootHash1.Bytes()) { - Fail(t, "storage root hash didn't change as expected") + Fatal(t, "storage root hash didn't change as expected") } currentSlotValueMap1 = getStorageSlotValue(t, node, contractAddress1) previousStorageRootHash2 := currentRootHash2 currentRootHash2 = getStorageRootHash(t, node, contractAddress2) if bytes.Equal(previousStorageRootHash2.Bytes(), currentRootHash2.Bytes()) { - Fail(t, "storage root hash didn't change as expected") + Fatal(t, "storage root hash didn't change as expected") } currentSlotValueMap2 = getStorageSlotValue(t, node, contractAddress2) @@ -362,7 +362,7 @@ func TestSendRawTransactionConditionalMultiRoutine(t *testing.T) { select { case <-success: case <-ctxWithTimeout.Done(): - Fail(t, "test timeouted") + Fatal(t, "test timeouted") } } cancelCtxWithTimeout() @@ -375,7 +375,7 @@ func TestSendRawTransactionConditionalMultiRoutine(t *testing.T) { for i := genesis + 1; header != nil; i++ { blockReceipts := bc.GetReceiptsByHash(header.Hash()) if blockReceipts == nil { - Fail(t, "Failed to get block receipts, block number:", header.Number) + Fatal(t, "Failed to get block receipts, block number:", header.Number) } receipts = append(receipts, blockReceipts...) header = bc.GetHeaderByNumber(i) @@ -387,14 +387,14 @@ func TestSendRawTransactionConditionalMultiRoutine(t *testing.T) { parsed, err := simple.ParseLogAndIncrementCalled(*receipt.Logs[0]) Require(t, err) if parsed.Expected.Int64() != parsed.Have.Int64() { - Fail(t, "Got invalid log, log.Expected:", parsed.Expected, "log.Have:", parsed.Have) + Fatal(t, "Got invalid log, log.Expected:", parsed.Expected, "log.Have:", parsed.Have) } else { succeeded++ } } } if succeeded != expectedSuccesses { - Fail(t, "Unexpected number of successful txes, want:", numTxes, "have:", succeeded) + Fatal(t, "Unexpected number of successful txes, want:", numTxes, "have:", succeeded) } } diff --git a/system_tests/contract_tx_test.go b/system_tests/contract_tx_test.go index 9214884c26..e671dcc6ac 100644 --- a/system_tests/contract_tx_test.go +++ b/system_tests/contract_tx_test.go @@ -94,12 +94,12 @@ func TestContractTxDeploy(t *testing.T) { receipt, err := WaitForTx(ctx, client, txHash, time.Second*10) Require(t, err) if receipt.Status != types.ReceiptStatusSuccessful { - Fail(t, "Receipt has non-successful status", receipt.Status) + Fatal(t, "Receipt has non-successful status", receipt.Status) } expectedAddr := crypto.CreateAddress(from, stateNonce) if receipt.ContractAddress != expectedAddr { - Fail(t, "expected address", from, "nonce", stateNonce, "to deploy to", expectedAddr, "but got", receipt.ContractAddress) + Fatal(t, "expected address", from, "nonce", stateNonce, "to deploy to", expectedAddr, "but got", receipt.ContractAddress) } t.Log("deployed contract", receipt.ContractAddress, "from address", from, "with nonce", stateNonce) stateNonce++ @@ -107,7 +107,7 @@ func TestContractTxDeploy(t *testing.T) { code, err := client.CodeAt(ctx, receipt.ContractAddress, nil) Require(t, err) if !bytes.Equal(code, []byte{0xFE}) { - Fail(t, "expected contract", receipt.ContractAddress, "code of 0xFE but got", hex.EncodeToString(code)) + Fatal(t, "expected contract", receipt.ContractAddress, "code of 0xFE but got", hex.EncodeToString(code)) } } } diff --git a/system_tests/das_test.go b/system_tests/das_test.go index bce4da1f34..d813253670 100644 --- a/system_tests/das_test.go +++ b/system_tests/das_test.go @@ -110,7 +110,7 @@ func TestDASRekey(t *testing.T) { l1info, l1client, _, l1stack := createTestL1BlockChain(t, nil) defer requireClose(t, l1stack) feedErrChan := make(chan error, 10) - addresses := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) + addresses, initMessage := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) // Setup DAS servers dasDataDir := t.TempDir() @@ -126,7 +126,7 @@ func TestDASRekey(t *testing.T) { authorizeDASKeyset(t, ctx, pubkeyA, l1info, l1client) // Setup L2 chain - _, l2stackA, l2chainDb, l2arbDb, l2blockchain := createL2BlockChain(t, l2info, nodeDir, chainConfig) + _, l2stackA, l2chainDb, l2arbDb, l2blockchain := createL2BlockChainWithStackConfig(t, l2info, nodeDir, chainConfig, initMessage, nil) l2info.GenerateAccount("User2") // Setup DAS config @@ -218,7 +218,7 @@ func checkBatchPosting(t *testing.T, ctx context.Context, l1client, l2clientA *e Require(t, err) if l2balance.Cmp(expectedBalance) != 0 { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } } @@ -238,7 +238,7 @@ func TestDASComplexConfigAndRestMirror(t *testing.T) { l1Reader.Start(ctx) defer l1Reader.StopAndWait() feedErrChan := make(chan error, 10) - addresses := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) + addresses, initMessage := DeployOnTestL1(t, ctx, l1info, l1client, chainConfig) keyDir, fileDataDir, dbDataDir := t.TempDir(), t.TempDir(), t.TempDir() pubkey, _, err := das.GenerateAndStoreKeys(keyDir) @@ -304,7 +304,7 @@ func TestDASComplexConfigAndRestMirror(t *testing.T) { Require(t, err) // Setup L2 chain - l2info, l2stackA, l2chainDb, l2arbDb, l2blockchain := createL2BlockChain(t, nil, "", chainConfig) + l2info, l2stackA, l2chainDb, l2arbDb, l2blockchain := createL2BlockChainWithStackConfig(t, nil, "", chainConfig, initMessage, nil) l2info.GenerateAccount("User2") sequencerTxOpts := l1info.GetDefaultTransactOpts("Sequencer", ctx) diff --git a/system_tests/delayedinbox_test.go b/system_tests/delayedinbox_test.go index f83ddab184..e48cb37028 100644 --- a/system_tests/delayedinbox_test.go +++ b/system_tests/delayedinbox_test.go @@ -50,6 +50,6 @@ func TestDelayInboxSimple(t *testing.T) { l2balance, err := l2client.BalanceAt(ctx, l2info.GetAddress("User2"), nil) Require(t, err) if l2balance.Cmp(big.NewInt(1e6)) != 0 { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } } diff --git a/system_tests/delayedinboxlong_test.go b/system_tests/delayedinboxlong_test.go index 9424660406..b1c8ea361b 100644 --- a/system_tests/delayedinboxlong_test.go +++ b/system_tests/delayedinboxlong_test.go @@ -63,7 +63,7 @@ func TestDelayInboxLong(t *testing.T) { t.Log("Done sending", delayedMessages, "delayedMessages") if delayedMessages == 0 { - Fail(t, "No delayed messages sent!") + Fatal(t, "No delayed messages sent!") } // sending l1 messages creates l1 blocks.. make enough to get that delayed inbox message in @@ -78,6 +78,6 @@ func TestDelayInboxLong(t *testing.T) { l2balance, err := l2client.BalanceAt(ctx, l2info.GetAddress("User2"), nil) Require(t, err) if l2balance.Cmp(big.NewInt(fundsPerDelayed*delayedMessages)) != 0 { - Fail(t, "Unexpected balance:", "balance", l2balance, "expected", fundsPerDelayed*delayedMessages) + Fatal(t, "Unexpected balance:", "balance", l2balance, "expected", fundsPerDelayed*delayedMessages) } } diff --git a/system_tests/estimation_test.go b/system_tests/estimation_test.go index c80492326c..2a416ad179 100644 --- a/system_tests/estimation_test.go +++ b/system_tests/estimation_test.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - "github.com/offchainlabs/nitro/arbos/l1pricing" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/solgen/go/mocksgen" "github.com/offchainlabs/nitro/solgen/go/node_interfacegen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" @@ -43,7 +43,7 @@ func TestDeploy(t *testing.T) { Require(t, err, "failed to get counter") if counter != 1 { - Fail(t, "Unexpected counter value", counter) + Fatal(t, "Unexpected counter value", counter) } } @@ -88,7 +88,7 @@ func TestEstimate(t *testing.T) { numTriesLeft-- } if !equilibrated { - Fail(t, "L2 gas price did not converge", gasPrice) + Fatal(t, "L2 gas price did not converge", gasPrice) } initialBalance, err := client.BalanceAt(ctx, auth.From, nil) @@ -103,7 +103,7 @@ func TestEstimate(t *testing.T) { header, err := client.HeaderByNumber(ctx, receipt.BlockNumber) Require(t, err, "could not get header") if header.BaseFee.Cmp(gasPrice) != 0 { - Fail(t, "Header has wrong basefee", header.BaseFee, gasPrice) + Fatal(t, "Header has wrong basefee", header.BaseFee, gasPrice) } balance, err := client.BalanceAt(ctx, auth.From, nil) @@ -111,7 +111,7 @@ func TestEstimate(t *testing.T) { expectedCost := receipt.GasUsed * gasPrice.Uint64() observedCost := initialBalance.Uint64() - balance.Uint64() if expectedCost != observedCost { - Fail(t, "Expected deployment to cost", expectedCost, "instead of", observedCost) + Fatal(t, "Expected deployment to cost", expectedCost, "instead of", observedCost) } tx, err = simple.Increment(&auth) @@ -123,7 +123,7 @@ func TestEstimate(t *testing.T) { Require(t, err, "failed to get counter") if counter != 1 { - Fail(t, "Unexpected counter value", counter) + Fatal(t, "Unexpected counter value", counter) } } @@ -134,7 +134,7 @@ func TestComponentEstimate(t *testing.T) { l2info, node, client := CreateTestL2(t, ctx) defer node.StopAndWait() - l1BaseFee := big.NewInt(l1pricing.InitialPricePerUnitWei) + l1BaseFee := new(big.Int).Set(arbostypes.DefaultInitialL1BaseFee) l2BaseFee := GetBaseFee(t, client, ctx) colors.PrintGrey("l1 basefee ", l1BaseFee) @@ -177,7 +177,7 @@ func TestComponentEstimate(t *testing.T) { outputs, err := nodeMethod.Outputs.Unpack(returnData) Require(t, err) if len(outputs) != 4 { - Fail(t, "expected 4 outputs from gasEstimateComponents, got", len(outputs)) + Fatal(t, "expected 4 outputs from gasEstimateComponents, got", len(outputs)) } gasEstimate, _ := outputs[0].(uint64) @@ -201,10 +201,10 @@ func TestComponentEstimate(t *testing.T) { colors.PrintBlue("Est. ", gasEstimate, " - ", gasEstimateForL1, " = ", l2Estimate) if !arbmath.BigEquals(l1BaseFeeEstimate, l1BaseFee) { - Fail(t, l1BaseFeeEstimate, l1BaseFee) + Fatal(t, l1BaseFeeEstimate, l1BaseFee) } if !arbmath.BigEquals(baseFee, l2BaseFee) { - Fail(t, baseFee, l2BaseFee.Uint64()) + Fatal(t, baseFee, l2BaseFee.Uint64()) } Require(t, client.SendTransaction(ctx, tx)) @@ -215,6 +215,6 @@ func TestComponentEstimate(t *testing.T) { colors.PrintMint("True ", receipt.GasUsed, " - ", receipt.GasUsedForL1, " = ", l2Used) if l2Estimate != l2Used { - Fail(t, l2Estimate, l2Used) + Fatal(t, l2Estimate, l2Used) } } diff --git a/system_tests/fees_test.go b/system_tests/fees_test.go index 734ccc7529..bdd998357e 100644 --- a/system_tests/fees_test.go +++ b/system_tests/fees_test.go @@ -82,20 +82,22 @@ func TestSequencerFeePaid(t *testing.T) { tipPaidToNet := arbmath.BigMulByUint(tipCap, receipt.GasUsedForL1) gotTip := arbmath.BigEquals(networkRevenue, arbmath.BigAdd(feePaidForL2, tipPaidToNet)) if !gotTip && version == 9 { - Fail(t, "network didn't receive expected payment", networkRevenue, feePaidForL2, tipPaidToNet) + Fatal(t, "network didn't receive expected payment", networkRevenue, feePaidForL2, tipPaidToNet) } if gotTip && version != 9 { - Fail(t, "tips are somehow enabled") + Fatal(t, "tips are somehow enabled") } txSize := compressedTxSize(t, tx) l1GasBought := arbmath.BigDiv(l1Charge, l1Estimate).Uint64() - l1GasActual := txSize * params.TxDataNonZeroGasEIP2028 + l1ChargeExpected := arbmath.BigMulByUint(l1Estimate, txSize*params.TxDataNonZeroGasEIP2028) + // L1 gas can only be charged in terms of L2 gas, so subtract off any rounding error from the expected value + l1ChargeExpected.Sub(l1ChargeExpected, new(big.Int).Mod(l1ChargeExpected, l2info.GasPrice)) colors.PrintBlue("bytes ", l1GasBought/params.TxDataNonZeroGasEIP2028, txSize) - if l1GasBought != l1GasActual { - Fail(t, "the sequencer's future revenue does not match its costs", l1GasBought, l1GasActual) + if !arbmath.BigEquals(l1Charge, l1ChargeExpected) { + Fatal(t, "the sequencer's future revenue does not match its costs", l1Charge, l1ChargeExpected) } return networkRevenue, tipPaidToNet } @@ -109,10 +111,10 @@ func TestSequencerFeePaid(t *testing.T) { net2, tip2 := testFees(2) if tip0.Sign() != 0 { - Fail(t, "nonzero tip") + Fatal(t, "nonzero tip") } if arbmath.BigEquals(arbmath.BigSub(net2, tip2), net0) { - Fail(t, "a tip of 2 should yield a total of 3") + Fatal(t, "a tip of 2 should yield a total of 3") } } @@ -211,7 +213,7 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { if numRetrogradeMoves > 1 { colors.PrintRed(timesPriceAdjusted, newDiff, oldDiff, lastEstimate, surplus) colors.PrintRed(estimatedL1FeePerUnit, l1Header.BaseFee, actualL1FeePerUnit) - Fail(t, "L1 gas price estimate should tend toward the basefee") + Fatal(t, "L1 gas price estimate should tend toward the basefee") } } else { numRetrogradeMoves = 0 @@ -219,10 +221,10 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { diff := arbmath.BigAbs(arbmath.BigSub(actualL1FeePerUnit, estimatedL1FeePerUnit)) maxDiffToAllow := arbmath.BigDivByUint(actualL1FeePerUnit, 100) if arbmath.BigLessThan(maxDiffToAllow, diff) { // verify that estimates is within 1% of actual - Fail(t, "New L1 estimate differs too much from receipt") + Fatal(t, "New L1 estimate differs too much from receipt") } if arbmath.BigEquals(actualL1FeePerUnit, common.Big0) { - Fail(t, "Estimate is zero", i) + Fatal(t, "Estimate is zero", i) } lastEstimate = actualL1FeePerUnit timesPriceAdjusted++ @@ -240,7 +242,7 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { break } if j == 1 { - Fail(t, "batch count didn't update in time") + Fatal(t, "batch count didn't update in time") } time.Sleep(time.Millisecond * 100) } @@ -252,10 +254,10 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { colors.PrintMint("price changes ", timesPriceAdjusted) if timesPriceAdjusted == 0 { - Fail(t, "L1 gas price estimate never adjusted") + Fatal(t, "L1 gas price estimate never adjusted") } if !arbmath.BigGreaterThan(rewardRecipientBalanceAfter, rewardRecipientBalanceBefore) { - Fail(t, "reward recipient didn't get paid") + Fatal(t, "reward recipient didn't get paid") } arbAggregator, err := precompilesgen.NewArbAggregator(common.HexToAddress("0x6d"), l2client) @@ -269,12 +271,12 @@ func testSequencerPriceAdjustsFrom(t *testing.T, initialEstimate uint64) { bal, err := l1client.BalanceAt(ctx, bpAddr, nil) Require(t, err) if bal.Sign() == 0 { - Fail(t, "Batch poster balance is zero for", bpAddr) + Fatal(t, "Batch poster balance is zero for", bpAddr) } } } if numReimbursed != 1 { - Fail(t, "Wrong number of batch posters were reimbursed", numReimbursed) + Fatal(t, "Wrong number of batch posters were reimbursed", numReimbursed) } } diff --git a/system_tests/forwarder_test.go b/system_tests/forwarder_test.go index 5ec897604e..3691caf5d2 100644 --- a/system_tests/forwarder_test.go +++ b/system_tests/forwarder_test.go @@ -8,6 +8,7 @@ import ( "fmt" "math/big" "path/filepath" + "strings" "sync" "testing" "time" @@ -21,16 +22,19 @@ import ( "github.com/offchainlabs/nitro/cmd/genericconf" "github.com/offchainlabs/nitro/statetransfer" "github.com/offchainlabs/nitro/util/redisutil" - "github.com/offchainlabs/nitro/util/testhelpers" ) +var transferAmount = big.NewInt(1e12) // amount of ether to use for transactions in tests + +const nodesCount = 5 // number of testnodes to create in tests + func TestStaticForwarder(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ipcPath := filepath.Join(t.TempDir(), "test.ipc") ipcConfig := genericconf.IPCConfigDefault ipcConfig.Path = ipcPath - stackConfig := getTestStackConfig(t) + stackConfig := stackConfigForTest(t) ipcConfig.Apply(stackConfig) nodeConfigA := arbnode.ConfigDefaultL1Test() nodeConfigA.BatchPoster.Enable = false @@ -50,54 +54,61 @@ func TestStaticForwarder(t *testing.T) { defer nodeB.StopAndWait() l2info.GenerateAccount("User2") - tx := l2info.PrepareTx("Owner", "User2", l2info.TransferGas, big.NewInt(1e12), nil) + tx := l2info.PrepareTx("Owner", "User2", l2info.TransferGas, transferAmount, nil) err := clientB.SendTransaction(ctx, tx) - testhelpers.RequireImpl(t, err) + Require(t, err) _, err = EnsureTxSucceeded(ctx, clientA, tx) - testhelpers.RequireImpl(t, err) + Require(t, err) + l2balance, err := clientA.BalanceAt(ctx, l2info.GetAddress("User2"), nil) - testhelpers.RequireImpl(t, err) - if l2balance.Cmp(big.NewInt(1e12)) != 0 { - testhelpers.FailImpl(t, "Unexpected balance:", l2balance) + Require(t, err) + + if l2balance.Cmp(transferAmount) != 0 { + Fatal(t, "Unexpected balance:", l2balance) } } -func initMiniRedisForTest(t *testing.T, ctx context.Context, nodeNames []string) (*miniredis.Miniredis, string) { - var priorities string +func initRedis(ctx context.Context, t *testing.T, nodeNames []string) (*miniredis.Miniredis, string) { + t.Helper() + redisServer, err := miniredis.Run() - testhelpers.RequireImpl(t, err) + Require(t, err) redisUrl := fmt.Sprintf("redis://%s/0", redisServer.Addr()) redisClient, err := redisutil.RedisClientFromURL(redisUrl) - testhelpers.RequireImpl(t, err) + Require(t, err) defer redisClient.Close() - for _, name := range nodeNames { - priorities = priorities + name + "," - } - priorities = priorities[:len(priorities)-1] // remove last "," - testhelpers.RequireImpl(t, redisClient.Set(ctx, redisutil.PRIORITIES_KEY, priorities, time.Duration(0)).Err()) + priorities := strings.Join(nodeNames, ",") + + Require(t, redisClient.Set(ctx, redisutil.PRIORITIES_KEY, priorities, time.Duration(0)).Err()) return redisServer, redisUrl } -func createFallbackSequencer( - t *testing.T, ctx context.Context, ipcPath string, redisUrl string, +type fallbackSequencerOpts struct { + ipcPath string + redisUrl string + enableSecCoordinator bool +} + +func fallbackSequencer( + ctx context.Context, t *testing.T, opts *fallbackSequencerOpts, ) (l2info info, currentNode *arbnode.Node, l2client *ethclient.Client, l1info info, l1backend *eth.Ethereum, l1client *ethclient.Client, l1stack *node.Node) { - stackConfig := getTestStackConfig(t) + stackConfig := stackConfigForTest(t) ipcConfig := genericconf.IPCConfigDefault - ipcConfig.Path = ipcPath + ipcConfig.Path = opts.ipcPath ipcConfig.Apply(stackConfig) nodeConfig := arbnode.ConfigDefaultL1Test() - nodeConfig.SeqCoordinator.Enable = false - nodeConfig.SeqCoordinator.RedisUrl = redisUrl - nodeConfig.SeqCoordinator.MyUrlImpl = ipcPath + nodeConfig.SeqCoordinator.Enable = opts.enableSecCoordinator + nodeConfig.SeqCoordinator.RedisUrl = opts.redisUrl + nodeConfig.SeqCoordinator.MyUrlImpl = opts.ipcPath return createTestNodeOnL1WithConfig(t, ctx, true, nodeConfig, nil, stackConfig) } func createForwardingNode( - t *testing.T, ctx context.Context, + ctx context.Context, t *testing.T, first *arbnode.Node, l1stack *node.Node, l1info *BlockchainTestInfo, @@ -106,7 +117,7 @@ func createForwardingNode( redisUrl string, fallbackPath string, ) (*ethclient.Client, *arbnode.Node) { - stackConfig := getTestStackConfig(t) + stackConfig := stackConfigForTest(t) if ipcPath != "" { ipcConfig := genericconf.IPCConfigDefault ipcConfig.Path = ipcPath @@ -123,7 +134,7 @@ func createForwardingNode( } func createSequencer( - t *testing.T, ctx context.Context, + ctx context.Context, t *testing.T, first *arbnode.Node, l1stack *node.Node, l1info *BlockchainTestInfo, @@ -131,7 +142,7 @@ func createSequencer( ipcPath string, redisUrl string, ) (*ethclient.Client, *arbnode.Node) { - stackConfig := getTestStackConfig(t) + stackConfig := stackConfigForTest(t) ipcConfig := genericconf.IPCConfigDefault ipcConfig.Path = ipcPath ipcConfig.Apply(stackConfig) @@ -144,126 +155,180 @@ func createSequencer( return Create2ndNodeWithConfig(t, ctx, first, l1stack, l1info, l2InitData, nodeConfig, stackConfig) } -func TestRedisForwarder(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() +// tmpPath returns file path with specified filename from temporary directory of the test. +func tmpPath(t *testing.T, filename string) string { + return filepath.Join(t.TempDir(), filename) +} + +// testNodes creates specified number of paths for ipc from temporary directory of the test. +// e.g. /tmp/TestRedisForwarder689063006/003/0.ipc, /tmp/TestRedisForwarder689063006/007/1.ipc and so on. +func testNodes(t *testing.T, n int) []string { + var paths []string + for i := 0; i < n; i++ { + paths = append(paths, tmpPath(t, fmt.Sprintf("%d.ipc", i))) + } + return paths +} + +// waitForSequencerLockout blocks and waits until there is some sequencer chosen for specified duration. +// Errors out after timeout. +func waitForSequencerLockout(ctx context.Context, node *arbnode.Node, duration time.Duration) error { + if node == nil { + return fmt.Errorf("node is nil") + } + if node.SeqCoordinator == nil { + return fmt.Errorf("sequence coordinator in the node is nil") + } + // TODO: implement exponential backoff retry mechanism and use it instead. + for { + select { + case <-time.After(duration): + return fmt.Errorf("no sequencer was chosen") + default: + if c, err := node.SeqCoordinator.CurrentChosenSequencer(ctx); err == nil && c != "" { + return nil + } + time.Sleep(100 * time.Millisecond) + } + } +} - fallbackIpcPath := filepath.Join(t.TempDir(), "fallback.ipc") - nodePaths := []string{} - for i := 0; i < 5; i++ { - nodePaths = append(nodePaths, filepath.Join(t.TempDir(), fmt.Sprintf("%d.ipc", i))) +// stopNodes blocks and waits until all nodes are stopped. +func stopNodes(nodes []*arbnode.Node) { + var wg sync.WaitGroup + for _, node := range nodes { + if node != nil { + wg.Add(1) + n := node + go func() { + n.StopAndWait() + wg.Done() + }() + } } - redisServer, redisUrl := initMiniRedisForTest(t, ctx, nodePaths) + wg.Wait() +} + +func user(suffix string, idx int) string { + return fmt.Sprintf("User%s_%d", suffix, idx) +} + +// tryWithTimeout calls function f() repeatedly foruntil it succeeds. +func tryWithTimeout(ctx context.Context, f func() error, duration time.Duration) error { + for { + select { + case <-time.After(duration): + return fmt.Errorf("timeout expired") + default: + if err := f(); err == nil { + return nil + } + } + } +} + +func TestRedisForwarder(t *testing.T) { + ctx := context.Background() + + nodePaths := testNodes(t, nodesCount) + fbNodePath := tmpPath(t, "fallback.ipc") // fallback node path + redisServer, redisUrl := initRedis(ctx, t, append(nodePaths, fbNodePath)) defer redisServer.Close() - l2info, fallbackNode, fallbackClient, l1info, _, _, l1stack := createFallbackSequencer(t, ctx, fallbackIpcPath, redisUrl) + l2info, fallbackNode, fallbackClient, l1info, _, _, l1stack := fallbackSequencer(ctx, t, + &fallbackSequencerOpts{ + ipcPath: fbNodePath, + redisUrl: redisUrl, + enableSecCoordinator: true, + }) defer requireClose(t, l1stack) defer fallbackNode.StopAndWait() - forwardingClient, forwardingNode := createForwardingNode(t, ctx, fallbackNode, l1stack, l1info, &l2info.ArbInitData, "", redisUrl, fallbackIpcPath) + forwardingClient, forwardingNode := createForwardingNode(ctx, t, fallbackNode, l1stack, l1info, &l2info.ArbInitData, "", redisUrl, fbNodePath) defer forwardingNode.StopAndWait() - var sequencers []*arbnode.Node + var seqNodes []*arbnode.Node var seqClients []*ethclient.Client for _, path := range nodePaths { - client, node := createSequencer(t, ctx, fallbackNode, l1stack, l1info, &l2info.ArbInitData, path, redisUrl) - sequencers = append(sequencers, node) + client, node := createSequencer(ctx, t, fallbackNode, l1stack, l1info, &l2info.ArbInitData, path, redisUrl) + seqNodes = append(seqNodes, node) seqClients = append(seqClients, client) } - clients := seqClients - clients = append(clients, fallbackClient) - nodes := sequencers - nodes = append(nodes, fallbackNode) - defer func() { - var wg sync.WaitGroup - for _, node := range nodes { - if node != nil && node != fallbackNode { - wg.Add(1) - n := node - go func() { - n.StopAndWait() - wg.Done() - }() - } - } - wg.Wait() - }() + defer stopNodes(seqNodes) - for i := range clients { - userA := fmt.Sprintf("UserA%d", i) + for i := range seqClients { + userA := user("A", i) l2info.GenerateAccount(userA) tx := l2info.PrepareTx("Owner", userA, l2info.TransferGas, big.NewInt(1e12+int64(l2info.TransferGas)*l2info.GasPrice.Int64()), nil) err := fallbackClient.SendTransaction(ctx, tx) - testhelpers.RequireImpl(t, err) + Require(t, err) _, err = EnsureTxSucceeded(ctx, fallbackClient, tx) - testhelpers.RequireImpl(t, err) + Require(t, err) } - for i := range clients { - userA := fmt.Sprintf("UserA%d", i) - userB := fmt.Sprintf("UserB%d", i) + for i := range seqClients { + if err := waitForSequencerLockout(ctx, fallbackNode, 2*time.Second); err != nil { + t.Fatalf("Error waiting for lockout: %v", err) + } + userA := user("A", i) + userB := user("B", i) l2info.GenerateAccount(userB) - tx := l2info.PrepareTx(userA, userB, l2info.TransferGas, big.NewInt(1e12), nil) - var err error - for j := 0; j < 20; j++ { - err = forwardingClient.SendTransaction(ctx, tx) - if err == nil { - break - } - time.Sleep(execution.DefaultTestForwarderConfig.UpdateInterval / 2) + tx := l2info.PrepareTx(userA, userB, l2info.TransferGas, transferAmount, nil) + + sendFunc := func() error { return forwardingClient.SendTransaction(ctx, tx) } + if err := tryWithTimeout(ctx, sendFunc, execution.DefaultTestForwarderConfig.UpdateInterval*10); err != nil { + t.Fatalf("Client: %v, error sending transaction: %v", i, err) } - testhelpers.RequireImpl(t, err) - _, err = EnsureTxSucceeded(ctx, clients[i], tx) - testhelpers.RequireImpl(t, err) - l2balance, err := clients[i].BalanceAt(ctx, l2info.GetAddress(userB), nil) - testhelpers.RequireImpl(t, err) - if l2balance.Cmp(big.NewInt(1e12)) != 0 { - testhelpers.FailImpl(t, "Unexpected balance:", l2balance) + _, err := EnsureTxSucceeded(ctx, seqClients[i], tx) + Require(t, err) + + l2balance, err := seqClients[i].BalanceAt(ctx, l2info.GetAddress(userB), nil) + Require(t, err) + + if l2balance.Cmp(transferAmount) != 0 { + Fatal(t, "Unexpected balance:", l2balance) } - if i < len(nodes)-1 { - time.Sleep(100 * time.Millisecond) - nodes[i].StopAndWait() - nodes[i] = nil + if i < len(seqNodes) { + seqNodes[i].StopAndWait() + seqNodes[i] = nil } } } func TestRedisForwarderFallbackNoRedis(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := context.Background() - fallbackIpcPath := filepath.Join(t.TempDir(), "fallback.ipc") - nodePaths := []string{} - for i := 0; i < 10; i++ { - nodePaths = append(nodePaths, filepath.Join(t.TempDir(), fmt.Sprintf("%d.ipc", i))) - } - redisServer, redisUrl := initMiniRedisForTest(t, ctx, nodePaths) + fallbackIpcPath := tmpPath(t, "fallback.ipc") + nodePaths := testNodes(t, nodesCount) + redisServer, redisUrl := initRedis(ctx, t, nodePaths) redisServer.Close() - l2info, fallbackNode, fallbackClient, l1info, _, _, l1stack := createFallbackSequencer(t, ctx, fallbackIpcPath, redisUrl) + l2info, fallbackNode, fallbackClient, l1info, _, _, l1stack := fallbackSequencer(ctx, t, + &fallbackSequencerOpts{ + ipcPath: fallbackIpcPath, + redisUrl: redisUrl, + enableSecCoordinator: false, + }) defer requireClose(t, l1stack) defer fallbackNode.StopAndWait() - forwardingClient, forwardingNode := createForwardingNode(t, ctx, fallbackNode, l1stack, l1info, &l2info.ArbInitData, "", redisUrl, fallbackIpcPath) + forwardingClient, forwardingNode := createForwardingNode(ctx, t, fallbackNode, l1stack, l1info, &l2info.ArbInitData, "", redisUrl, fallbackIpcPath) defer forwardingNode.StopAndWait() - l2info.GenerateAccount("User2") - var err error - tx := l2info.PrepareTx("Owner", "User2", l2info.TransferGas, big.NewInt(1e12), nil) - for j := 0; j < 20; j++ { - err = forwardingClient.SendTransaction(ctx, tx) - if err == nil { - break - } - time.Sleep(100 * time.Millisecond) - } - testhelpers.RequireImpl(t, err) + user := "User2" + l2info.GenerateAccount(user) + tx := l2info.PrepareTx("Owner", "User2", l2info.TransferGas, transferAmount, nil) + sendFunc := func() error { return forwardingClient.SendTransaction(ctx, tx) } + err := tryWithTimeout(ctx, sendFunc, execution.DefaultTestForwarderConfig.UpdateInterval*10) + Require(t, err) _, err = EnsureTxSucceeded(ctx, fallbackClient, tx) - testhelpers.RequireImpl(t, err) - l2balance, err := fallbackClient.BalanceAt(ctx, l2info.GetAddress("User2"), nil) - testhelpers.RequireImpl(t, err) - if l2balance.Cmp(big.NewInt(1e12)) != 0 { - t.Fatal("Unexpected balance:", l2balance) + Require(t, err) + + l2balance, err := fallbackClient.BalanceAt(ctx, l2info.GetAddress(user), nil) + Require(t, err) + + if l2balance.Cmp(transferAmount) != 0 { + t.Errorf("Got balance: %v, want: %v", l2balance, transferAmount) } } diff --git a/system_tests/full_challenge_impl_test.go b/system_tests/full_challenge_impl_test.go index 9325689b5e..26e2d4a64e 100644 --- a/system_tests/full_challenge_impl_test.go +++ b/system_tests/full_challenge_impl_test.go @@ -38,27 +38,27 @@ import ( func DeployOneStepProofEntry(t *testing.T, ctx context.Context, auth *bind.TransactOpts, client *ethclient.Client) common.Address { osp0, _, _, err := ospgen.DeployOneStepProver0(auth, client) if err != nil { - Fail(t, err) + Fatal(t, err) } ospMem, _, _, err := ospgen.DeployOneStepProverMemory(auth, client) if err != nil { - Fail(t, err) + Fatal(t, err) } ospMath, _, _, err := ospgen.DeployOneStepProverMath(auth, client) if err != nil { - Fail(t, err) + Fatal(t, err) } ospHostIo, _, _, err := ospgen.DeployOneStepProverHostIo(auth, client) if err != nil { - Fail(t, err) + Fatal(t, err) } ospEntry, tx, _, err := ospgen.DeployOneStepProofEntry(auth, client, osp0, ospMem, ospMath, ospHostIo) if err != nil { - Fail(t, err) + Fatal(t, err) } _, err = EnsureTxSucceeded(ctx, client, tx) if err != nil { - Fail(t, err) + Fatal(t, err) } return ospEntry } @@ -165,7 +165,7 @@ func makeBatch(t *testing.T, l2Node *arbnode.Node, l2Info *BlockchainTestInfo, b batches, err := nodeSeqInbox.LookupBatchesInRange(ctx, receipt.BlockNumber, receipt.BlockNumber) Require(t, err) if len(batches) == 0 { - Fail(t, "batch not found after AddSequencerL2BatchFromOrigin") + Fatal(t, "batch not found after AddSequencerL2BatchFromOrigin") } err = l2Node.InboxTracker.AddSequencerBatches(ctx, backend, batches) Require(t, err) @@ -245,7 +245,7 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { configByValidationNode(t, conf, valStack) fatalErrChan := make(chan error, 10) - asserterRollupAddresses := DeployOnTestL1(t, ctx, l1Info, l1Backend, chainConfig) + asserterRollupAddresses, initMessage := DeployOnTestL1(t, ctx, l1Info, l1Backend, chainConfig) deployerTxOpts := l1Info.GetDefaultTransactOpts("deployer", ctx) sequencerTxOpts := l1Info.GetDefaultTransactOpts("sequencer", ctx) @@ -255,7 +255,7 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { asserterBridgeAddr, asserterSeqInbox, asserterSeqInboxAddr := setupSequencerInboxStub(ctx, t, l1Info, l1Backend, chainConfig) challengerBridgeAddr, challengerSeqInbox, challengerSeqInboxAddr := setupSequencerInboxStub(ctx, t, l1Info, l1Backend, chainConfig) - asserterL2Info, asserterL2Stack, asserterL2ChainDb, asserterL2ArbDb, asserterL2Blockchain := createL2BlockChain(t, nil, "", chainConfig) + asserterL2Info, asserterL2Stack, asserterL2ChainDb, asserterL2ArbDb, asserterL2Blockchain := createL2BlockChainWithStackConfig(t, nil, "", chainConfig, initMessage, nil) asserterRollupAddresses.Bridge = asserterBridgeAddr asserterRollupAddresses.SequencerInbox = asserterSeqInboxAddr asserterL2, err := arbnode.CreateNode(ctx, asserterL2Stack, asserterL2ChainDb, asserterL2ArbDb, NewFetcherFromConfig(conf), asserterL2Blockchain, l1Backend, asserterRollupAddresses, nil, nil, nil, fatalErrChan) @@ -263,7 +263,7 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { err = asserterL2.Start(ctx) Require(t, err) - challengerL2Info, challengerL2Stack, challengerL2ChainDb, challengerL2ArbDb, challengerL2Blockchain := createL2BlockChain(t, nil, "", chainConfig) + challengerL2Info, challengerL2Stack, challengerL2ChainDb, challengerL2ArbDb, challengerL2Blockchain := createL2BlockChainWithStackConfig(t, nil, "", chainConfig, initMessage, nil) challengerRollupAddresses := *asserterRollupAddresses challengerRollupAddresses.Bridge = challengerBridgeAddr challengerRollupAddresses.SequencerInbox = challengerSeqInboxAddr @@ -289,22 +289,22 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { locator, err := server_common.NewMachineLocator("") if err != nil { - Fail(t, err) + Fatal(t, err) } wasmModuleRoot := locator.LatestWasmModuleRoot() if (wasmModuleRoot == common.Hash{}) { - Fail(t, "latest machine not found") + Fatal(t, "latest machine not found") } asserterGenesis := asserterL2.Execution.ArbInterface.BlockChain().Genesis() challengerGenesis := challengerL2.Execution.ArbInterface.BlockChain().Genesis() if asserterGenesis.Hash() != challengerGenesis.Hash() { - Fail(t, "asserter and challenger have different genesis hashes") + Fatal(t, "asserter and challenger have different genesis hashes") } asserterLatestBlock := asserterL2.Execution.ArbInterface.BlockChain().CurrentBlock() challengerLatestBlock := challengerL2.Execution.ArbInterface.BlockChain().CurrentBlock() if asserterLatestBlock.Hash() == challengerLatestBlock.Hash() { - Fail(t, "asserter and challenger have the same end block") + Fatal(t, "asserter and challenger have the same end block") } asserterStartGlobalState := validator.GoGlobalState{ @@ -339,29 +339,29 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { asserterValidator, err := staker.NewStatelessBlockValidator(asserterL2.InboxReader, asserterL2.InboxTracker, asserterL2.TxStreamer, asserterL2Blockchain, asserterL2ChainDb, asserterL2ArbDb, nil, StaticFetcherFrom(t, &conf.BlockValidator), valStack) if err != nil { - Fail(t, err) + Fatal(t, err) } err = asserterValidator.Start(ctx) if err != nil { - Fail(t, err) + Fatal(t, err) } defer asserterValidator.Stop() asserterManager, err := staker.NewChallengeManager(ctx, l1Backend, &asserterTxOpts, asserterTxOpts.From, challengeManagerAddr, 1, asserterL2Blockchain, asserterL2.InboxTracker, asserterValidator, 0, 0) if err != nil { - Fail(t, err) + Fatal(t, err) } challengerValidator, err := staker.NewStatelessBlockValidator(challengerL2.InboxReader, challengerL2.InboxTracker, challengerL2.TxStreamer, challengerL2Blockchain, challengerL2ChainDb, challengerL2ArbDb, nil, StaticFetcherFrom(t, &conf.BlockValidator), valStack) if err != nil { - Fail(t, err) + Fatal(t, err) } err = challengerValidator.Start(ctx) if err != nil { - Fail(t, err) + Fatal(t, err) } defer challengerValidator.Stop() challengerManager, err := staker.NewChallengeManager(ctx, l1Backend, &challengerTxOpts, challengerTxOpts.From, challengeManagerAddr, 1, challengerL2Blockchain, challengerL2.InboxTracker, challengerValidator, 0, 0) if err != nil { - Fail(t, err) + Fatal(t, err) } for i := 0; i < 100; i++ { @@ -389,10 +389,10 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { t.Log("challenge completed! asserter hit expected error:", err) return } - Fail(t, "challenge step", i, "hit error:", err) + Fatal(t, "challenge step", i, "hit error:", err) } if tx == nil { - Fail(t, "no move") + Fatal(t, "no move") } _, err = EnsureTxSucceeded(ctx, l1Backend, tx) if err != nil { @@ -400,22 +400,22 @@ func RunChallengeTest(t *testing.T, asserterIsCorrect bool) { t.Log("challenge complete! Tx failed as expected:", err) return } - Fail(t, err) + Fatal(t, err) } confirmLatestBlock(ctx, t, l1Info, l1Backend) winner, err := resultReceiver.Winner(&bind.CallOpts{}) if err != nil { - Fail(t, err) + Fatal(t, err) } if winner == (common.Address{}) { continue } if winner != expectedWinner { - Fail(t, "wrong party won challenge") + Fatal(t, "wrong party won challenge") } } - Fail(t, "challenge timed out without winner") + Fatal(t, "challenge timed out without winner") } diff --git a/system_tests/infra_fee_test.go b/system_tests/infra_fee_test.go index fd10badd4e..89f869576d 100644 --- a/system_tests/infra_fee_test.go +++ b/system_tests/infra_fee_test.go @@ -67,9 +67,9 @@ func TestInfraFee(t *testing.T) { Require(t, err) if !arbmath.BigEquals(netFeeBalanceBefore, netFeeBalanceAfter) { - Fail(t, netFeeBalanceBefore, netFeeBalanceAfter) + Fatal(t, netFeeBalanceBefore, netFeeBalanceAfter) } if !arbmath.BigEquals(infraFeeBalanceAfter, expectedBalanceAfter) { - Fail(t, infraFeeBalanceBefore, expectedFunds, infraFeeBalanceAfter, expectedBalanceAfter) + Fatal(t, infraFeeBalanceBefore, expectedFunds, infraFeeBalanceAfter, expectedBalanceAfter) } } diff --git a/system_tests/ipc_test.go b/system_tests/ipc_test.go index ad5a8fbc64..01ecf859d8 100644 --- a/system_tests/ipc_test.go +++ b/system_tests/ipc_test.go @@ -18,7 +18,7 @@ func TestIpcRpc(t *testing.T) { ipcConfig := genericconf.IPCConfigDefault ipcConfig.Path = ipcPath - stackConf := getTestStackConfig(t) + stackConf := stackConfigForTest(t) ipcConfig.Apply(stackConf) ctx, cancel := context.WithCancel(context.Background()) diff --git a/system_tests/log_subscription_test.go b/system_tests/log_subscription_test.go index d0896c0ea7..5ee1732fb0 100644 --- a/system_tests/log_subscription_test.go +++ b/system_tests/log_subscription_test.go @@ -37,7 +37,7 @@ func TestLogSubscription(t *testing.T) { Require(t, err) if len(receipt.Logs) != 1 { - Fail(t, "Unexpected number of logs", len(receipt.Logs)) + Fatal(t, "Unexpected number of logs", len(receipt.Logs)) } var receiptLog types.Log = *receipt.Logs[0] @@ -46,11 +46,11 @@ func TestLogSubscription(t *testing.T) { defer timer.Stop() select { case <-timer.C: - Fail(t, "Hit timeout waiting for log from subscription") + Fatal(t, "Hit timeout waiting for log from subscription") case subscriptionLog = <-logChan: } if !reflect.DeepEqual(receiptLog, subscriptionLog) { - Fail(t, "Receipt log", receiptLog, "is different than subscription log", subscriptionLog) + Fatal(t, "Receipt log", receiptLog, "is different than subscription log", subscriptionLog) } _, err = client.BlockByHash(ctx, subscriptionLog.BlockHash) Require(t, err) diff --git a/system_tests/meaningless_reorg_test.go b/system_tests/meaningless_reorg_test.go index f9e9f6e57f..851bf38ce0 100644 --- a/system_tests/meaningless_reorg_test.go +++ b/system_tests/meaningless_reorg_test.go @@ -35,22 +35,22 @@ func TestMeaninglessBatchReorg(t *testing.T) { for i := 0; ; i++ { if i >= 500 { - Fail(t, "Failed to read batch from L1") + Fatal(t, "Failed to read batch from L1") } msgNum, err := arbNode.Execution.ExecEngine.HeadMessageNumber() Require(t, err) if msgNum == 1 { break } else if msgNum > 1 { - Fail(t, "More than two batches in test?") + Fatal(t, "More than two batches in test?") } time.Sleep(10 * time.Millisecond) } metadata, err := arbNode.InboxTracker.GetBatchMetadata(1) Require(t, err) originalBatchBlock := batchReceipt.BlockNumber.Uint64() - if metadata.L1Block != originalBatchBlock { - Fail(t, "Posted batch in block", originalBatchBlock, "but metadata says L1 block was", metadata.L1Block) + if metadata.ParentChainBlock != originalBatchBlock { + Fatal(t, "Posted batch in block", originalBatchBlock, "but metadata says L1 block was", metadata.ParentChainBlock) } _, l2Receipt := TransferBalance(t, "Owner", "Owner", common.Big1, l2Info, l2Client, ctx) @@ -77,21 +77,21 @@ func TestMeaninglessBatchReorg(t *testing.T) { newBatchBlock := newBatchReceipt.BlockNumber.Uint64() if newBatchBlock == originalBatchBlock { - Fail(t, "Attempted to change L1 block number in batch reorg, but it ended up in the same block", newBatchBlock) + Fatal(t, "Attempted to change L1 block number in batch reorg, but it ended up in the same block", newBatchBlock) } else { t.Log("Batch successfully moved in reorg from L1 block", originalBatchBlock, "to L1 block", newBatchBlock) } for i := 0; ; i++ { if i >= 500 { - Fail(t, "Failed to read batch reorg from L1") + Fatal(t, "Failed to read batch reorg from L1") } metadata, err = arbNode.InboxTracker.GetBatchMetadata(1) Require(t, err) - if metadata.L1Block == newBatchBlock { + if metadata.ParentChainBlock == newBatchBlock { break - } else if metadata.L1Block != originalBatchBlock { - Fail(t, "Batch L1 block changed from", originalBatchBlock, "to", metadata.L1Block, "instead of expected", metadata.L1Block) + } else if metadata.ParentChainBlock != originalBatchBlock { + Fatal(t, "Batch L1 block changed from", originalBatchBlock, "to", metadata.ParentChainBlock, "instead of expected", metadata.ParentChainBlock) } time.Sleep(10 * time.Millisecond) } @@ -103,6 +103,6 @@ func TestMeaninglessBatchReorg(t *testing.T) { Require(t, err) if l2Header.Hash() != l2Receipt.BlockHash { - Fail(t, "L2 block hash changed") + Fatal(t, "L2 block hash changed") } } diff --git a/system_tests/outbox_test.go b/system_tests/outbox_test.go index f72d3486bc..6b43cc83b0 100644 --- a/system_tests/outbox_test.go +++ b/system_tests/outbox_test.go @@ -90,10 +90,10 @@ func TestOutboxProofs(t *testing.T) { Require(t, err, "No receipt for txn") if receipt.Status != types.ReceiptStatusSuccessful { - Fail(t, "Tx failed with status code:", receipt) + Fatal(t, "Tx failed with status code:", receipt) } if len(receipt.Logs) == 0 { - Fail(t, "Tx didn't emit any logs") + Fatal(t, "Tx didn't emit any logs") } for _, log := range receipt.Logs { @@ -230,7 +230,7 @@ func TestOutboxProofs(t *testing.T) { if zero, ok := partials[place]; ok { if zero != (common.Hash{}) { - Fail(t, "Somehow got 2 partials for the same level\n\t1st:", zero, "\n\t2nd:", hash) + Fatal(t, "Somehow got 2 partials for the same level\n\t1st:", zero, "\n\t2nd:", hash) } partials[place] = hash partialsByLevel[level] = hash @@ -264,7 +264,7 @@ func TestOutboxProofs(t *testing.T) { curr, ok := known[step] if !ok { - Fail(t, "We should know the current node's value") + Fatal(t, "We should know the current node's value") } left := curr @@ -276,7 +276,7 @@ func TestOutboxProofs(t *testing.T) { step.Leaf -= 1 << step.Level partial, ok := known[step] if !ok { - Fail(t, "There should be a partial here") + Fatal(t, "There should be a partial here") } left = partial } else { @@ -309,7 +309,7 @@ func TestOutboxProofs(t *testing.T) { for i, place := range nodes { hash, ok := known[place] if !ok { - Fail(t, "We're missing data for the node at position", place) + Fatal(t, "We're missing data for the node at position", place) } hashes[i] = hash t.Log("node", place, hash) @@ -323,7 +323,7 @@ func TestOutboxProofs(t *testing.T) { } if !proof.IsCorrect() { - Fail(t, "Proof is wrong") + Fatal(t, "Proof is wrong") } // Check NodeInterface.sol produces equivalent proofs @@ -336,10 +336,10 @@ func TestOutboxProofs(t *testing.T) { nodeSend := outboxProof.Send if nodeRoot != rootHash { - Fail(t, "NodeInterface root differs\n", nodeRoot, "\n", rootHash) + Fatal(t, "NodeInterface root differs\n", nodeRoot, "\n", rootHash) } if len(hashes) != len(nodeProof) { - Fail(t, "NodeInterface proof is the wrong size", len(nodeProof), len(hashes)) + Fatal(t, "NodeInterface proof is the wrong size", len(nodeProof), len(hashes)) } for i, correct := range hashes { if nodeProof[i] != correct { @@ -347,7 +347,7 @@ func TestOutboxProofs(t *testing.T) { } } if nodeSend != provable.hash { - Fail(t, "NodeInterface send differs\n", nodeSend, "\n", provable.hash) + Fatal(t, "NodeInterface send differs\n", nodeSend, "\n", provable.hash) } } } diff --git a/system_tests/precompile_fuzz_test.go b/system_tests/precompile_fuzz_test.go index b5680cbb74..8ab133cf58 100644 --- a/system_tests/precompile_fuzz_test.go +++ b/system_tests/precompile_fuzz_test.go @@ -4,7 +4,6 @@ package arbtest import ( - "encoding/json" "math/big" "testing" @@ -13,9 +12,9 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/offchainlabs/nitro/arbos/arbosState" + "github.com/offchainlabs/nitro/arbos/arbostypes" "github.com/offchainlabs/nitro/arbos/burn" "github.com/offchainlabs/nitro/gethhook" "github.com/offchainlabs/nitro/precompiles" @@ -34,11 +33,7 @@ func FuzzPrecompiles(f *testing.F) { } burner := burn.NewSystemBurner(nil, false) chainConfig := params.ArbitrumDevTestChainConfig() - serializedChainConfig, err := json.Marshal(chainConfig) - if err != nil { - log.Crit("failed to serialize chain config", "error", err) - } - _, err = arbosState.InitializeArbosState(sdb, burner, chainConfig, serializedChainConfig) + _, err = arbosState.InitializeArbosState(sdb, burner, chainConfig, arbostypes.TestInitMessage) if err != nil { panic(err) } @@ -59,7 +54,7 @@ func FuzzPrecompiles(f *testing.F) { GasLimit: fuzzGas, BaseFee: common.Big1, } - evm := vm.NewEVM(blockContext, txContext, sdb, params.ArbitrumDevTestChainConfig(), vm.Config{}) + evm := vm.NewEVM(blockContext, txContext, sdb, chainConfig, vm.Config{}) // Pick a precompile address based on the first byte of the input var addr common.Address diff --git a/system_tests/precompile_test.go b/system_tests/precompile_test.go index 21675eba39..ad08ff7471 100644 --- a/system_tests/precompile_test.go +++ b/system_tests/precompile_test.go @@ -29,7 +29,7 @@ func TestPurePrecompileMethodCalls(t *testing.T) { chainId, err := arbSys.ArbChainID(&bind.CallOpts{}) Require(t, err, "failed to get the ChainID") if chainId.Uint64() != params.ArbitrumDevTestChainConfig().ChainID.Uint64() { - Fail(t, "Wrong ChainID", chainId.Uint64()) + Fatal(t, "Wrong ChainID", chainId.Uint64()) } } @@ -45,7 +45,7 @@ func TestViewLogReverts(t *testing.T) { err = arbDebug.EventsView(nil) if err == nil { - Fail(t, "unexpected success") + Fatal(t, "unexpected success") } } @@ -61,24 +61,24 @@ func TestCustomSolidityErrors(t *testing.T) { Require(t, err, "could not bind ArbDebug contract") customError := arbDebug.CustomRevert(callOpts, 1024) if customError == nil { - Fail(t, "customRevert call should have errored") + Fatal(t, "customRevert call should have errored") } observedMessage := customError.Error() expectedMessage := "execution reverted: error Custom(1024, This spider family wards off bugs: /\\oo/\\ //\\(oo)/\\ /\\oo/\\, true)" if observedMessage != expectedMessage { - Fail(t, observedMessage) + Fatal(t, observedMessage) } arbSys, err := precompilesgen.NewArbSys(arbos.ArbSysAddress, client) Require(t, err, "could not bind ArbSys contract") _, customError = arbSys.ArbBlockHash(callOpts, big.NewInt(1e9)) if customError == nil { - Fail(t, "out of range ArbBlockHash call should have errored") + Fatal(t, "out of range ArbBlockHash call should have errored") } observedMessage = customError.Error() expectedMessage = "execution reverted: error InvalidBlockNumber(1000000000, 1)" if observedMessage != expectedMessage { - Fail(t, observedMessage) + Fatal(t, observedMessage) } } @@ -98,7 +98,7 @@ func TestPrecompileErrorGasLeft(t *testing.T) { Require(t, err, "Failed to call CheckGasUsed to precompile", to) maxGas := big.NewInt(100_000) if arbmath.BigGreaterThan(gas, maxGas) { - Fail(t, "Precompile", to, "used", gas, "gas reverting, greater than max expected", maxGas) + Fatal(t, "Precompile", to, "used", gas, "gas reverting, greater than max expected", maxGas) } } diff --git a/system_tests/reorg_resequencing_test.go b/system_tests/reorg_resequencing_test.go index c56f919403..f132d46487 100644 --- a/system_tests/reorg_resequencing_test.go +++ b/system_tests/reorg_resequencing_test.go @@ -42,7 +42,7 @@ func TestReorgResequencing(t *testing.T) { balance, err := client.BalanceAt(ctx, l2info.GetAddress(account), nil) Require(t, err) if balance.Int64() != params.Ether { - Fail(t, "expected account", account, "to have a balance of 1 ether but instead it has", balance, "wei "+scenario) + Fatal(t, "expected account", account, "to have a balance of 1 ether but instead it has", balance, "wei "+scenario) } } } diff --git a/system_tests/retryable_test.go b/system_tests/retryable_test.go index c711ac1021..7b0c3a7563 100644 --- a/system_tests/retryable_test.go +++ b/system_tests/retryable_test.go @@ -54,7 +54,7 @@ func retryableSetup(t *testing.T) ( messages, err := delayedBridge.LookupMessagesInRange(ctx, l1Receipt.BlockNumber, l1Receipt.BlockNumber, nil) Require(t, err) if len(messages) == 0 { - Fail(t, "didn't find message for retryable submission") + Fatal(t, "didn't find message for retryable submission") } var submissionTxs []*types.Transaction for _, message := range messages { @@ -70,7 +70,7 @@ func retryableSetup(t *testing.T) ( } } if len(submissionTxs) != 1 { - Fail(t, "expected 1 tx from retryable submission, found", len(submissionTxs)) + Fatal(t, "expected 1 tx from retryable submission, found", len(submissionTxs)) } return submissionTxs[0].Hash() @@ -89,7 +89,7 @@ func retryableSetup(t *testing.T) ( block, err := l2client.BlockByNumber(ctx, arbmath.UintToBig(number)) Require(t, err, "failed to get L2 block", number, "of", blockNum) if block.Number().Uint64() != number { - Fail(t, "block number mismatch", number, block.Number().Uint64()) + Fatal(t, "block number mismatch", number, block.Number().Uint64()) } } @@ -111,7 +111,7 @@ func TestRetryableNoExist(t *testing.T) { Require(t, err) _, err = arbRetryableTx.GetTimeout(&bind.CallOpts{}, common.Hash{}) if err.Error() != "execution reverted: error NoTicketWithID()" { - Fail(t, "didn't get expected NoTicketWithID error") + Fatal(t, "didn't get expected NoTicketWithID error") } } @@ -166,7 +166,7 @@ func TestSubmitRetryableImmediateSuccess(t *testing.T) { l1receipt, err := EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) if l1receipt.Status != types.ReceiptStatusSuccessful { - Fail(t, "l1receipt indicated failure") + Fatal(t, "l1receipt indicated failure") } waitForL1DelayBlocks(t, ctx, l1client, l1info) @@ -174,14 +174,14 @@ func TestSubmitRetryableImmediateSuccess(t *testing.T) { receipt, err := WaitForTx(ctx, l2client, lookupSubmitRetryableL2TxHash(l1receipt), time.Second*5) Require(t, err) if receipt.Status != types.ReceiptStatusSuccessful { - Fail(t) + Fatal(t) } l2balance, err := l2client.BalanceAt(ctx, l2info.GetAddress("User2"), nil) Require(t, err) if !arbmath.BigEquals(l2balance, big.NewInt(1e6)) { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } } @@ -216,7 +216,7 @@ func TestSubmitRetryableFailThenRetry(t *testing.T) { l1receipt, err := EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) if l1receipt.Status != types.ReceiptStatusSuccessful { - Fail(t, "l1receipt indicated failure") + Fatal(t, "l1receipt indicated failure") } waitForL1DelayBlocks(t, ctx, l1client, l1info) @@ -224,10 +224,10 @@ func TestSubmitRetryableFailThenRetry(t *testing.T) { receipt, err := WaitForTx(ctx, l2client, lookupSubmitRetryableL2TxHash(l1receipt), time.Second*5) Require(t, err) if receipt.Status != types.ReceiptStatusSuccessful { - Fail(t) + Fatal(t) } if len(receipt.Logs) != 2 { - Fail(t, len(receipt.Logs)) + Fatal(t, len(receipt.Logs)) } ticketId := receipt.Logs[0].Topics[1] firstRetryTxId := receipt.Logs[1].Topics[2] @@ -236,7 +236,7 @@ func TestSubmitRetryableFailThenRetry(t *testing.T) { receipt, err = WaitForTx(ctx, l2client, firstRetryTxId, time.Second*5) Require(t, err) if receipt.Status != types.ReceiptStatusFailed { - Fail(t, receipt.GasUsed) + Fatal(t, receipt.GasUsed) } arbRetryableTx, err := precompilesgen.NewArbRetryableTx(common.HexToAddress("6e"), l2client) @@ -252,7 +252,7 @@ func TestSubmitRetryableFailThenRetry(t *testing.T) { receipt, err = WaitForTx(ctx, l2client, retryTxId, time.Second*1) Require(t, err) if receipt.Status != 1 { - Fail(t, receipt.Status) + Fatal(t, receipt.Status) } // verify that the increment happened, so we know the retry succeeded @@ -260,20 +260,20 @@ func TestSubmitRetryableFailThenRetry(t *testing.T) { Require(t, err) if counter != 1 { - Fail(t, "Unexpected counter:", counter) + Fatal(t, "Unexpected counter:", counter) } if len(receipt.Logs) != 1 { - Fail(t, "Unexpected log count:", len(receipt.Logs)) + Fatal(t, "Unexpected log count:", len(receipt.Logs)) } parsed, err := simple.ParseRedeemedEvent(*receipt.Logs[0]) Require(t, err) aliasedSender := util.RemapL1Address(usertxopts.From) if parsed.Caller != aliasedSender { - Fail(t, "Unexpected caller", parsed.Caller, "expected", aliasedSender) + Fatal(t, "Unexpected caller", parsed.Caller, "expected", aliasedSender) } if parsed.Redeemer != ownerTxOpts.From { - Fail(t, "Unexpected redeemer", parsed.Redeemer, "expected", ownerTxOpts.From) + Fatal(t, "Unexpected redeemer", parsed.Redeemer, "expected", ownerTxOpts.From) } } @@ -324,7 +324,7 @@ func TestSubmissionGasCosts(t *testing.T) { l1receipt, err := EnsureTxSucceeded(ctx, l1client, l1tx) Require(t, err) if l1receipt.Status != types.ReceiptStatusSuccessful { - Fail(t, "l1receipt indicated failure") + Fatal(t, "l1receipt indicated failure") } waitForL1DelayBlocks(t, ctx, l1client, l1info) @@ -353,13 +353,13 @@ func TestSubmissionGasCosts(t *testing.T) { colors.PrintMint("Receive ", receiveFunds) colors.PrintBlue("L2 Call Value ", retryableL2CallValue) if !arbmath.BigEquals(receiveFunds, retryableL2CallValue) { - Fail(t, "Recipient didn't receive the right funds") + Fatal(t, "Recipient didn't receive the right funds") } // the beneficiary should receive nothing colors.PrintMint("Beneficiary ", beneficiaryFunds) if beneficiaryFunds.Sign() != 0 { - Fail(t, "The beneficiary shouldn't have received funds") + Fatal(t, "The beneficiary shouldn't have received funds") } // the fee refund address should recieve the excess gas @@ -369,7 +369,7 @@ func TestSubmissionGasCosts(t *testing.T) { colors.PrintBlue("Excess Wei ", excessWei) colors.PrintMint("Fee Refund ", refundFunds) if !arbmath.BigEquals(refundFunds, arbmath.BigAdd(excessWei, maxSubmissionFee)) { - Fail(t, "The Fee Refund Address didn't receive the right funds") + Fatal(t, "The Fee Refund Address didn't receive the right funds") } // the faucet must pay for both the gas used and the call value supplied @@ -383,7 +383,7 @@ func TestSubmissionGasCosts(t *testing.T) { colors.PrintRed("Expected ", expectedGasChange) colors.PrintRed("Observed ", diff) colors.PrintRed("Off by ", arbmath.BigSub(expectedGasChange, diff)) - Fail(t, "Supplied gas was improperly deducted\n", fundsBeforeSubmit, "\n", fundsAfterSubmit) + Fatal(t, "Supplied gas was improperly deducted\n", fundsBeforeSubmit, "\n", fundsAfterSubmit) } } diff --git a/system_tests/seq_coordinator_test.go b/system_tests/seq_coordinator_test.go index 84636e1549..2209e82d93 100644 --- a/system_tests/seq_coordinator_test.go +++ b/system_tests/seq_coordinator_test.go @@ -125,7 +125,7 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { break } if attempts > 10 { - Fail(t, "timeout waiting for msg ", msgNum, " debug: ", currentNode.SeqCoordinator.DebugPrint()) + Fatal(t, "timeout waiting for msg ", msgNum, " debug: ", currentNode.SeqCoordinator.DebugPrint()) } <-time.After(nodeConfig.SeqCoordinator.UpdateInterval / 3) } @@ -198,7 +198,7 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { // sequencing suceeds only on the leder for i := arbutil.MessageIndex(0); i < messagesPerRound; i++ { if sequencer := trySequencingEverywhere(); sequencer != currentSequencer { - Fail(t, "unexpected sequencer. expected: ", currentSequencer, " got ", sequencer) + Fatal(t, "unexpected sequencer. expected: ", currentSequencer, " got ", sequencer) } sequencedMesssages++ } @@ -223,7 +223,7 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { for attempts := 0; ; attempts++ { sequencer := trySequencingEverywhere() if sequencer == -1 && attempts > 15 { - Fail(t, "failed to sequence") + Fatal(t, "failed to sequence") } if sequencer != -1 { sequencedMesssages++ @@ -236,7 +236,7 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { if sequencer == currentSequencer { break } - Fail(t, "unexpected sequencer", "expected", currentSequencer, "got", sequencer, "messages", sequencedMesssages) + Fatal(t, "unexpected sequencer", "expected", currentSequencer, "got", sequencer, "messages", sequencedMesssages) } // all nodes get messages @@ -246,7 +246,7 @@ func TestRedisSeqCoordinatorPriorities(t *testing.T) { for i := arbutil.MessageIndex(0); i < messagesPerRound; i++ { sequencer := trySequencingEverywhere() if sequencer != currentSequencer { - Fail(t, "unexpected sequencer", "expected", currentSequencer, "got", sequencer, "messages", sequencedMesssages) + Fatal(t, "unexpected sequencer", "expected", currentSequencer, "got", sequencer, "messages", sequencedMesssages) } sequencedMesssages++ } @@ -329,7 +329,7 @@ func testCoordinatorMessageSync(t *testing.T, successCase bool) { } else { _, err = WaitForTx(ctx, clientB, tx.Hash(), time.Second) if err == nil { - Fail(t, "tx received by node with different seq coordinator signing key") + Fatal(t, "tx received by node with different seq coordinator signing key") } } } diff --git a/system_tests/seq_nonce_test.go b/system_tests/seq_nonce_test.go index 80de4cfa0a..968f141364 100644 --- a/system_tests/seq_nonce_test.go +++ b/system_tests/seq_nonce_test.go @@ -53,7 +53,7 @@ func TestSequencerParallelNonces(t *testing.T) { balance, err := client.BalanceAt(ctx, addr, nil) Require(t, err) if !arbmath.BigEquals(balance, big.NewInt(100)) { - Fail(t, "Unexpected user balance", balance) + Fatal(t, "Unexpected user balance", balance) } } @@ -72,14 +72,14 @@ func TestSequencerNonceTooHigh(t *testing.T) { tx := l2info.PrepareTx("Owner", "Owner", l2info.TransferGas, common.Big0, nil) err := client.SendTransaction(ctx, tx) if err == nil { - Fail(t, "No error when nonce was too high") + Fatal(t, "No error when nonce was too high") } if !strings.Contains(err.Error(), core.ErrNonceTooHigh.Error()) { - Fail(t, "Unexpected transaction error", err) + Fatal(t, "Unexpected transaction error", err) } elapsed := time.Since(before) if elapsed > 2*config.Sequencer.NonceFailureCacheExpiry { - Fail(t, "Sequencer took too long to respond with nonce too high") + Fatal(t, "Sequencer took too long to respond with nonce too high") } } @@ -102,7 +102,7 @@ func TestSequencerNonceTooHighQueueFull(t *testing.T) { go func() { err := client.SendTransaction(ctx, tx) if err == nil { - Fail(t, "No error when nonce was too high") + Fatal(t, "No error when nonce was too high") } atomic.AddUint64(&completed, 1) }() @@ -115,7 +115,7 @@ func TestSequencerNonceTooHighQueueFull(t *testing.T) { break } if wait == 0 || got > expected { - Fail(t, "Wrong number of transaction responses; got", got, "but expected", expected) + Fatal(t, "Wrong number of transaction responses; got", got, "but expected", expected) } time.Sleep(time.Millisecond * 100) } diff --git a/system_tests/seq_reject_test.go b/system_tests/seq_reject_test.go index 1e26c0182d..19c06c4bc3 100644 --- a/system_tests/seq_reject_test.go +++ b/system_tests/seq_reject_test.go @@ -108,11 +108,11 @@ func TestSequencerRejection(t *testing.T) { break } if i == 0 { - Fail(t, "failed to reach block 200, only reached block", block) + Fatal(t, "failed to reach block 200, only reached block", block) } select { case err := <-feedErrChan: - Fail(t, "error: ", err) + Fatal(t, "error: ", err) case <-time.After(time.Millisecond * 100): } } @@ -128,12 +128,12 @@ func TestSequencerRejection(t *testing.T) { if err != nil { select { case err := <-feedErrChan: - Fail(t, "error: ", err) + Fatal(t, "error: ", err) case <-time.After(time.Millisecond * 100): } if i == 0 { client2Block, _ := client2.BlockNumber(ctx) - Fail(t, "client2 failed to reach client1 block ", header1.Number, ", only reached block", client2Block) + Fatal(t, "client2 failed to reach client1 block ", header1.Number, ", only reached block", client2Block) } continue } @@ -143,7 +143,7 @@ func TestSequencerRejection(t *testing.T) { } else { colors.PrintBlue("header 1:", header1) colors.PrintBlue("header 2:", header2) - Fail(t, "header 1 and header 2 have different hashes") + Fatal(t, "header 1 and header 2 have different hashes") } } } diff --git a/system_tests/seq_whitelist_test.go b/system_tests/seq_whitelist_test.go index f24ce79c9b..2d671dcdd6 100644 --- a/system_tests/seq_whitelist_test.go +++ b/system_tests/seq_whitelist_test.go @@ -35,6 +35,6 @@ func TestSequencerWhitelist(t *testing.T) { tx := l2info.PrepareTx("User2", "User", l2info.TransferGas, big.NewInt(params.Ether/10), nil) err := client.SendTransaction(ctx, tx) if err == nil { - Fail(t, "transaction from user not on whitelist accepted") + Fatal(t, "transaction from user not on whitelist accepted") } } diff --git a/system_tests/seqcompensation_test.go b/system_tests/seqcompensation_test.go index d56854ac13..362acf6a30 100644 --- a/system_tests/seqcompensation_test.go +++ b/system_tests/seqcompensation_test.go @@ -50,12 +50,12 @@ func TestSequencerCompensation(t *testing.T) { l2balance, err := l2clientB.BalanceAt(ctx, l2info.GetAddress("User2"), nil) Require(t, err) if l2balance.Cmp(big.NewInt(1e12)) != 0 { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } initialSeqBalance, err := l2clientB.BalanceAt(ctx, l1pricing.BatchPosterAddress, big.NewInt(0)) Require(t, err) if initialSeqBalance.Sign() != 0 { - Fail(t, "Unexpected initial sequencer balance:", initialSeqBalance) + Fatal(t, "Unexpected initial sequencer balance:", initialSeqBalance) } } diff --git a/system_tests/seqinbox_test.go b/system_tests/seqinbox_test.go index cbe8740209..56d727dd26 100644 --- a/system_tests/seqinbox_test.go +++ b/system_tests/seqinbox_test.go @@ -123,7 +123,7 @@ func testSequencerInboxReaderImpl(t *testing.T, validator bool) { currentHeader, err := l1Client.HeaderByNumber(ctx, nil) Require(t, err) if currentHeader.Number.Int64()-int64(reorgTargetNumber) < 65 { - Fail(t, "Less than 65 blocks of difference between current block", currentHeader.Number, "and target", reorgTargetNumber) + Fatal(t, "Less than 65 blocks of difference between current block", currentHeader.Number, "and target", reorgTargetNumber) } t.Logf("Reorganizing to L1 block %v", reorgTargetNumber) reorgTarget := l1BlockChain.GetBlockByNumber(reorgTargetNumber) @@ -244,12 +244,12 @@ func testSequencerInboxReaderImpl(t *testing.T, validator bool) { for i := 0; ; i++ { batchCount, err := seqInbox.BatchCount(&bind.CallOpts{}) if err != nil { - Fail(t, err) + Fatal(t, err) } if batchCount.Cmp(big.NewInt(int64(len(blockStates)))) == 0 { break } else if i >= 100 { - Fail(t, "timed out waiting for l1 batch count update; have", batchCount, "want", len(blockStates)-1) + Fatal(t, "timed out waiting for l1 batch count update; have", batchCount, "want", len(blockStates)-1) } time.Sleep(10 * time.Millisecond) } @@ -260,7 +260,7 @@ func testSequencerInboxReaderImpl(t *testing.T, validator bool) { if blockNumber == expectedBlockNumber { break } else if i >= 1000 { - Fail(t, "timed out waiting for l2 block update; have", blockNumber, "want", expectedBlockNumber) + Fatal(t, "timed out waiting for l2 block update; have", blockNumber, "want", expectedBlockNumber) } time.Sleep(10 * time.Millisecond) } @@ -271,7 +271,7 @@ func testSequencerInboxReaderImpl(t *testing.T, validator bool) { if lastValidated == expectedBlockNumber { break } else if i >= 1000 { - Fail(t, "timed out waiting for block validator; have", lastValidated, "want", expectedBlockNumber) + Fatal(t, "timed out waiting for block validator; have", lastValidated, "want", expectedBlockNumber) } time.Sleep(time.Second) } @@ -281,14 +281,14 @@ func testSequencerInboxReaderImpl(t *testing.T, validator bool) { block, err := l2Backend.APIBackend().BlockByNumber(ctx, rpc.BlockNumber(state.l2BlockNumber)) Require(t, err) if block == nil { - Fail(t, "missing state block", state.l2BlockNumber) + Fatal(t, "missing state block", state.l2BlockNumber) } stateDb, _, err := l2Backend.APIBackend().StateAndHeaderByNumber(ctx, rpc.BlockNumber(state.l2BlockNumber)) Require(t, err) for acct, expectedBalance := range state.balances { haveBalance := stateDb.GetBalance(acct) if expectedBalance.Cmp(haveBalance) < 0 { - Fail(t, "unexpected balance for account", acct, "; expected", expectedBalance, "got", haveBalance) + Fatal(t, "unexpected balance for account", acct, "; expected", expectedBalance, "got", haveBalance) } } } diff --git a/system_tests/staker_test.go b/system_tests/staker_test.go index fe30ef7cb8..e5ed3879e9 100644 --- a/system_tests/staker_test.go +++ b/system_tests/staker_test.go @@ -89,11 +89,11 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) nodeBGenesis := l2nodeB.Execution.Backend.APIBackend().CurrentHeader().Hash() if faultyStaker { if nodeAGenesis == nodeBGenesis { - Fail(t, "node A L2 genesis hash", nodeAGenesis, "== node B L2 genesis hash", nodeBGenesis) + Fatal(t, "node A L2 genesis hash", nodeAGenesis, "== node B L2 genesis hash", nodeBGenesis) } } else { if nodeAGenesis != nodeBGenesis { - Fail(t, "node A L2 genesis hash", nodeAGenesis, "!= node B L2 genesis hash", nodeBGenesis) + Fatal(t, "node A L2 genesis hash", nodeAGenesis, "!= node B L2 genesis hash", nodeBGenesis) } } @@ -304,7 +304,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) Require(t, err) proxyAdminAddr := common.BytesToAddress(proxyAdminBytes) if proxyAdminAddr == (common.Address{}) { - Fail(t, "failed to get challenge manager proxy admin") + Fatal(t, "failed to get challenge manager proxy admin") } proxyAdmin, err := mocksgen.NewProxyAdminForBinding(proxyAdminAddr, l1client) @@ -348,14 +348,14 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) isHonestZombie, err := rollup.IsZombie(&bind.CallOpts{}, valWalletAddrA) Require(t, err) if isHonestZombie { - Fail(t, "staker A became a zombie") + Fatal(t, "staker A became a zombie") } watchTx, err := stakerC.Act(ctx) if err != nil && !strings.Contains(err.Error(), "catch up") { Require(t, err, "watchtower staker failed to act") } if watchTx != nil { - Fail(t, "watchtower staker made a transaction") + Fatal(t, "watchtower staker made a transaction") } if !stakerAWasStaked { stakerAWasStaked, err = rollup.IsStaked(&bind.CallOpts{}, valWalletAddrA) @@ -371,7 +371,7 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) } if stakerATxs == 0 || stakerBTxs == 0 { - Fail(t, "staker didn't make txs: staker A made", stakerATxs, "staker B made", stakerBTxs) + Fatal(t, "staker didn't make txs: staker A made", stakerATxs, "staker B made", stakerBTxs) } latestConfirmedNode, err := rollup.LatestConfirmed(&bind.CallOpts{}) @@ -380,18 +380,18 @@ func stakerTestImpl(t *testing.T, faultyStaker bool, honestStakerInactive bool) if latestConfirmedNode <= 1 && !honestStakerInactive { latestCreatedNode, err := rollup.LatestNodeCreated(&bind.CallOpts{}) Require(t, err) - Fail(t, "latest confirmed node didn't advance:", latestConfirmedNode, latestCreatedNode) + Fatal(t, "latest confirmed node didn't advance:", latestConfirmedNode, latestCreatedNode) } if faultyStaker && !sawStakerZombie { - Fail(t, "staker B didn't become a zombie despite being faulty") + Fatal(t, "staker B didn't become a zombie despite being faulty") } if !stakerAWasStaked { - Fail(t, "staker A was never staked") + Fatal(t, "staker A was never staked") } if !stakerBWasStaked { - Fail(t, "staker B was never staked") + Fatal(t, "staker B was never staked") } } diff --git a/system_tests/state_fuzz_test.go b/system_tests/state_fuzz_test.go index 4d46ffc930..a8209499df 100644 --- a/system_tests/state_fuzz_test.go +++ b/system_tests/state_fuzz_test.go @@ -127,11 +127,17 @@ func FuzzStateTransition(f *testing.F) { if err != nil { panic(err) } + initMessage := &arbostypes.ParsedInitMessage{ + ChainId: chainConfig.ChainID, + InitialL1BaseFee: arbostypes.DefaultInitialL1BaseFee, + ChainConfig: chainConfig, + SerializedChainConfig: serializedChainConfig, + } stateRoot, err := arbosState.InitializeArbosInDatabase( chainDb, statetransfer.NewMemoryInitDataReader(&statetransfer.ArbosInitializationInfo{}), chainConfig, - serializedChainConfig, + initMessage, 0, 0, ) diff --git a/system_tests/transfer_test.go b/system_tests/transfer_test.go index 217c61df00..2e3317907b 100644 --- a/system_tests/transfer_test.go +++ b/system_tests/transfer_test.go @@ -32,6 +32,6 @@ func TestTransfer(t *testing.T) { bal2, err := client.BalanceAt(ctx, l2info.GetAddress("User2"), nil) Require(t, err) if bal2.Cmp(big.NewInt(1e12)) != 0 { - Fail(t, "Unexpected recipient balance: ", bal2) + Fatal(t, "Unexpected recipient balance: ", bal2) } } diff --git a/system_tests/twonodes_test.go b/system_tests/twonodes_test.go index 6fef8ce484..165b01b35a 100644 --- a/system_tests/twonodes_test.go +++ b/system_tests/twonodes_test.go @@ -57,7 +57,7 @@ func testTwoNodesSimple(t *testing.T, dasModeStr string) { Require(t, err) if l2balance.Cmp(big.NewInt(1e12)) != 0 { - Fail(t, "Unexpected balance:", l2balance) + Fatal(t, "Unexpected balance:", l2balance) } } diff --git a/system_tests/twonodeslong_test.go b/system_tests/twonodeslong_test.go index e9bf3e8937..c2a5979c8d 100644 --- a/system_tests/twonodeslong_test.go +++ b/system_tests/twonodeslong_test.go @@ -75,7 +75,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { t.Logf("DelayedFaucet has %v, per delayd: %v, baseprice: %v", delayedFaucetBalance, fundsPerDelayed, l2pricing.InitialBaseFeeWei) if avgTotalL1MessagesPerLoop < avgDelayedMessagesPerLoop { - Fail(t, "bad params, avgTotalL1MessagesPerLoop should include avgDelayedMessagesPerLoop") + Fatal(t, "bad params, avgTotalL1MessagesPerLoop should include avgDelayedMessagesPerLoop") } for i := 0; i < largeLoops; i++ { l1TxsThisTime := rand.Int() % (avgTotalL1MessagesPerLoop * 2) @@ -97,7 +97,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { errs := l1backend.TxPool().AddLocals(l1Txs) for _, err := range errs { if err != nil { - Fail(t, err) + Fatal(t, err) } } l2TxsThisTime := rand.Int() % (avgL2MsgsPerLoop * 2) @@ -110,7 +110,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { if len(l1Txs) > 0 { _, err := EnsureTxSucceeded(ctx, l1client, l1Txs[len(l1Txs)-1]) if err != nil { - Fail(t, err) + Fatal(t, err) } } // create bad tx on delayed inbox @@ -129,7 +129,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { t.Log("Done sending", delayedTransfers, "delayed transfers", directTransfers, "direct transfers") if (delayedTransfers + directTransfers) == 0 { - Fail(t, "No transfers sent!") + Fatal(t, "No transfers sent!") } // sending l1 messages creates l1 blocks.. make enough to get that delayed inbox message in @@ -139,11 +139,11 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { tx = l1info.PrepareTx("Faucet", "User", 30000, big.NewInt(1e12), nil) err := l1client.SendTransaction(ctx, tx) if err != nil { - Fail(t, err) + Fatal(t, err) } _, err = EnsureTxSucceeded(ctx, l1client, tx) if err != nil { - Fail(t, err) + Fatal(t, err) } } } @@ -164,7 +164,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { ownerBalance, _ := l2clientB.BalanceAt(ctx, l2info.GetAddress("Owner"), nil) delayedFaucetBalance, _ := l2clientB.BalanceAt(ctx, l2info.GetAddress("DelayedFaucet"), nil) t.Error("owner balance", ownerBalance, "delayed faucet", delayedFaucetBalance) - Fail(t, "Unexpected balance") + Fatal(t, "Unexpected balance") } nodeA.StopAndWait() @@ -174,7 +174,7 @@ func testTwoNodesLong(t *testing.T, dasModeStr string) { Require(t, err) timeout := getDeadlineTimeout(t, time.Minute*30) if !nodeB.BlockValidator.WaitForBlock(ctx, lastBlockHeader.Number.Uint64(), timeout) { - Fail(t, "did not validate all blocks") + Fatal(t, "did not validate all blocks") } } } diff --git a/test-node.bash b/test-node.bash deleted file mode 100755 index 8b9a876462..0000000000 --- a/test-node.bash +++ /dev/null @@ -1,321 +0,0 @@ -#!/usr/bin/env bash - -set -e - -NITRO_NODE_VERSION=offchainlabs/nitro-node:v2.1.0-beta.1-03a2aea-dev -BLOCKSCOUT_VERSION=offchainlabs/blockscout:v1.0.0-c8db5b1 - -mydir=`dirname $0` -cd "$mydir" - -if ! which docker-compose > /dev/null; then - echo == Error! docker-compose not installed - echo please install docker-compose and have it in PATH - echo see https://docs.docker.com/compose/install/ - exit 1 -fi - -if [[ $# -gt 0 ]] && [[ $1 == "script" ]]; then - shift - docker-compose run testnode-scripts "$@" - exit $? -fi - -num_volumes=`docker volume ls --filter label=com.docker.compose.project=nitro -q | wc -l` - -if [[ $num_volumes -eq 0 ]]; then - force_init=true -else - force_init=false -fi - -run=true -force_build=false -validate=false -detach=false -blockscout=false -tokenbridge=true -consensusclient=false -redundantsequencers=0 -dev_build_nitro=false -dev_build_blockscout=false -batchposters=1 -devprivkey=b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 -l1chainid=1337 -while [[ $# -gt 0 ]]; do - case $1 in - --init) - if ! $force_init; then - echo == Warning! this will remove all previous data - read -p "are you sure? [y/n]" -n 1 response - if [[ $response == "y" ]] || [[ $response == "Y" ]]; then - force_init=true - echo - else - exit 0 - fi - fi - shift - ;; - --dev) - shift - if [[ $# -eq 0 || $1 == -* ]]; then - # If no argument after --dev, set both flags to true - dev_build_nitro=true - dev_build_blockscout=true - else - while [[ $# -gt 0 && $1 != -* ]]; do - if [[ $1 == "nitro" ]]; then - dev_build_nitro=true - elif [[ $1 == "blockscout" ]]; then - dev_build_blockscout=true - fi - shift - done - fi - ;; - --build) - force_build=true - shift - ;; - --validate) - validate=true - shift - ;; - --blockscout) - blockscout=true - shift - ;; - --no-tokenbridge) - tokenbridge=false - shift - ;; - --no-run) - run=false - shift - ;; - --detach) - detach=true - shift - ;; - --batchposters) - batchposters=$2 - if ! [[ $batchposters =~ [0-3] ]] ; then - echo "batchposters must be between 0 and 3 value:$batchposters." - exit 1 - fi - shift - shift - ;; - --pos) - consensusclient=true - l1chainid=32382 - shift - ;; - --redundantsequencers) - redundantsequencers=$2 - if ! [[ $redundantsequencers =~ [0-3] ]] ; then - echo "redundantsequencers must be between 0 and 3 value:$redundantsequencers." - exit 1 - fi - shift - shift - ;; - *) - echo Usage: $0 \[OPTIONS..] - echo $0 script [SCRIPT-ARGS] - echo - echo OPTIONS: - echo --build: rebuild docker images - echo --dev: build nitro and blockscout dockers from source \(otherwise - pull docker\) - echo --init: remove all data, rebuild, deploy new rollup - echo --pos: l1 is a proof-of-stake chain \(using prysm for consensus\) - echo --validate: heavy computation, validating all blocks in WASM - echo --batchposters: batch posters [0-3] - echo --redundantsequencers redundant sequencers [0-3] - echo --detach: detach from nodes after running them - echo --blockscout: build or launch blockscout - echo --no-tokenbridge: don\'t build or launch tokenbridge - echo --no-run: does not launch nodes \(usefull with build or init\) - echo - echo script runs inside a separate docker. For SCRIPT-ARGS, run $0 script --help - exit 0 - esac -done - -if $force_init; then - force_build=true -fi - -if $dev_build_nitro; then - if [[ "$(docker images -q nitro-node-dev:latest 2> /dev/null)" == "" ]]; then - force_build=true - fi -fi - -if $dev_build_blockscout; then - if [[ "$(docker images -q blockscout:latest 2> /dev/null)" == "" ]]; then - force_build=true - fi -fi - -NODES="sequencer" -INITIAL_SEQ_NODES="sequencer" - -if [ $redundantsequencers -gt 0 ]; then - NODES="$NODES sequencer_b" - INITIAL_SEQ_NODES="$INITIAL_SEQ_NODES sequencer_b" -fi -if [ $redundantsequencers -gt 1 ]; then - NODES="$NODES sequencer_c" -fi -if [ $redundantsequencers -gt 2 ]; then - NODES="$NODES sequencer_d" -fi - -if [ $batchposters -gt 0 ]; then - NODES="$NODES poster" -fi -if [ $batchposters -gt 1 ]; then - NODES="$NODES poster_b" -fi -if [ $batchposters -gt 2 ]; then - NODES="$NODES poster_c" -fi - - -if $validate; then - NODES="$NODES validator" -else - NODES="$NODES staker-unsafe" -fi -if $blockscout; then - NODES="$NODES blockscout" -fi -if $force_build; then - echo == Building.. - if $dev_build_nitro; then - docker build . -t nitro-node-dev --target nitro-node-dev - fi - if $dev_build_blockscout; then - if $blockscout; then - docker build blockscout -t blockscout -f blockscout/docker/Dockerfile - fi - fi - LOCAL_BUILD_NODES=testnode-scripts - if $tokenbridge; then - LOCAL_BUILD_NODES="$LOCAL_BUILD_NODES testnode-tokenbridge" - fi - docker-compose build --no-rm $LOCAL_BUILD_NODES -fi - -if $dev_build_nitro; then - docker tag nitro-node-dev:latest nitro-node-dev-testnode -else - docker pull $NITRO_NODE_VERSION - docker tag $NITRO_NODE_VERSION nitro-node-dev-testnode -fi - -if $dev_build_blockscout; then - if $blockscout; then - docker tag blockscout:latest blockscout-testnode - fi -else - if $blockscout; then - docker pull $BLOCKSCOUT_VERSION - docker tag $BLOCKSCOUT_VERSION blockscout-testnode - fi -fi - -if $force_build; then - docker-compose build --no-rm $NODES testnode-scripts -fi - -if $force_init; then - echo == Removing old data.. - docker-compose down - leftoverContainers=`docker container ls -a --filter label=com.docker.compose.project=nitro -q | xargs echo` - if [ `echo $leftoverContainers | wc -w` -gt 0 ]; then - docker rm $leftoverContainers - fi - docker volume prune -f --filter label=com.docker.compose.project=nitro - leftoverVolumes=`docker volume ls --filter label=com.docker.compose.project=nitro -q | xargs echo` - if [ `echo $leftoverVolumes | wc -w` -gt 0 ]; then - docker volume rm $leftoverVolumes - fi - - echo == Generating l1 keys - docker-compose run testnode-scripts write-accounts - docker-compose run --entrypoint sh geth -c "echo passphrase > /datadir/passphrase" - docker-compose run --entrypoint sh geth -c "chown -R 1000:1000 /keystore" - docker-compose run --entrypoint sh geth -c "chown -R 1000:1000 /config" - - if $consensusclient; then - echo == Writing configs - docker-compose run testnode-scripts write-geth-genesis-config - - echo == Writing configs - docker-compose run testnode-scripts write-prysm-config - - echo == Initializing go-ethereum genesis configuration - docker-compose run geth init --datadir /datadir/ /config/geth_genesis.json - - echo == Starting geth - docker-compose up -d geth - - echo == Creating prysm genesis - docker-compose up create_beacon_chain_genesis - - echo == Running prysm - docker-compose up -d prysm_beacon_chain - docker-compose up -d prysm_validator - else - docker-compose up -d geth - fi - - echo == Funding validator and sequencer - docker-compose run testnode-scripts send-l1 --ethamount 1000 --to validator --wait - docker-compose run testnode-scripts send-l1 --ethamount 1000 --to sequencer --wait - - echo == create l1 traffic - docker-compose run testnode-scripts send-l1 --ethamount 1000 --to user_l1user --wait - docker-compose run testnode-scripts send-l1 --ethamount 0.0001 --from user_l1user --to user_l1user_b --wait --delay 500 --times 500 > /dev/null & - - echo == Writing l2 chain config - docker-compose run testnode-scripts write-l2-chain-config - - echo == Deploying L2 - sequenceraddress=`docker-compose run testnode-scripts print-address --account sequencer | tail -n 1 | tr -d '\r\n'` - - docker-compose run --entrypoint /usr/local/bin/deploy poster --l1conn ws://geth:8546 --l1keystore /home/user/l1keystore --sequencerAddress $sequenceraddress --ownerAddress $sequenceraddress --l1DeployAccount $sequenceraddress --l1deployment /config/deployment.json --authorizevalidators 10 --wasmrootpath /home/user/target/machines --l1chainid=$l1chainid --l2chainconfig /config/l2_chain_config.json --l2chainname arb-dev-test --l2chaininfo /config/deployed_chain_info.json - docker-compose run --entrypoint sh poster -c "jq [.[]] /config/deployed_chain_info.json > /config/l2_chain_info.json" - echo == Writing configs - docker-compose run testnode-scripts write-config - - echo == Initializing redis - docker-compose run testnode-scripts redis-init --redundancy $redundantsequencers - - echo == Funding l2 funnel - docker-compose up -d $INITIAL_SEQ_NODES - docker-compose run testnode-scripts bridge-funds --ethamount 100000 --wait - - if $tokenbridge; then - echo == Deploying token bridge - docker-compose run -e ARB_KEY=$devprivkey -e ETH_KEY=$devprivkey testnode-tokenbridge gen:network - docker-compose run --entrypoint sh testnode-tokenbridge -c "cat localNetwork.json" - echo - fi -fi - -if $run; then - UP_FLAG="" - if $detach; then - UP_FLAG="-d" - fi - - echo == Launching Sequencer - echo if things go wrong - use --init to create a new chain - echo - - docker-compose up $UP_FLAG $NODES -fi diff --git a/testnode-scripts/.gitignore b/testnode-scripts/.gitignore deleted file mode 100644 index 538ed560a2..0000000000 --- a/testnode-scripts/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/ -*.js - diff --git a/testnode-scripts/Dockerfile b/testnode-scripts/Dockerfile deleted file mode 100644 index e9b91b8646..0000000000 --- a/testnode-scripts/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM node:16 -WORKDIR /workspace -COPY ./package.json ./yarn.lock ./ -RUN yarn -COPY ./*.ts ./tsconfig.json ./ -RUN yarn build -ENTRYPOINT ["node", "index.js"] diff --git a/testnode-scripts/accounts.ts b/testnode-scripts/accounts.ts deleted file mode 100644 index f0ccc2b11b..0000000000 --- a/testnode-scripts/accounts.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { ethers } from "ethers"; -import * as consts from "./consts"; -import * as fs from "fs"; -import * as crypto from "crypto"; -import { runStress } from "./stress"; -const path = require("path"); - -const specialAccounts = 3; - -async function writeAccounts() { - for (let i = 0; i < specialAccounts; i++) { - const wallet = specialAccount(i) - let walletJSON = await wallet.encrypt(consts.l1passphrase); - fs.writeFileSync( - path.join(consts.l1keystore, wallet.address + ".key"), - walletJSON - ); - } -} - -function specialAccount(index: number): ethers.Wallet { - return ethers.Wallet.fromMnemonic( - consts.l1mnemonic, - "m/44'/60'/0'/0/" + index - ); -} - -export function namedAccount( - name: string, - threadId?: number | undefined -): ethers.Wallet { - if (name == "funnel") { - return specialAccount(0); - } - if (name == "sequencer") { - return specialAccount(1); - } - if (name == "validator") { - return specialAccount(2); - } - if (name.startsWith("user_")) { - return new ethers.Wallet( - ethers.utils.sha256(ethers.utils.toUtf8Bytes(name)) - ); - } - if (name.startsWith("threaduser_")) { - if (threadId == undefined) { - throw Error("threaduser_ account used but not supported here"); - } - return new ethers.Wallet( - ethers.utils.sha256( - ethers.utils.toUtf8Bytes( - name.substring(6) + "_thread_" + threadId.toString() - ) - ) - ); - } - if (name.startsWith("key_")) { - return new ethers.Wallet(ethers.utils.hexlify(name.substring(4))); - } - throw Error("bad account name: [" + name + "] see general help"); -} - -export function namedAddress( - name: string, - threadId?: number | undefined -): string { - if (name.startsWith("address_")) { - return name.substring(8); - } - if (name == "random") { - return "0x" + crypto.randomBytes(20).toString("hex"); - } - return namedAccount(name, threadId).address; -} - -export const namedAccountHelpString = - "Valid account names:\n" + - "funnel | sequencer | validator - known keys\n" + - "user_[Alphanumeric] - key will be generated from username\n" + - "threaduser_[Alphanumeric] - same as user_[Alphanumeric]_thread_[thread-id]\n" + - "key_0x[full private key] - user with specified private key"; -"\n" + - "Valid addresses: any account name, or\n" + - "address_0x[full eth address]\n" + - "random"; - -async function handlePrintAddress(argv: any, threadId: number) { - console.log(namedAddress(argv.account, threadId)); -} - -export const printAddressCommand = { - command: "print-address", - describe: "prints the requested address", - builder: { - account: { - string: true, - describe: "address (see general help)", - default: "funnel", - }, - }, - handler: async (argv: any) => { - await runStress(argv, handlePrintAddress); - }, -}; - -export const writeAccountsCommand = { - command: "write-accounts", - describe: "writes wallet files", - handler: async (argv: any) => { - await writeAccounts(); - }, -}; diff --git a/testnode-scripts/config.ts b/testnode-scripts/config.ts deleted file mode 100644 index 6703f8a8d4..0000000000 --- a/testnode-scripts/config.ts +++ /dev/null @@ -1,345 +0,0 @@ -import * as fs from 'fs'; -import * as consts from './consts' -import { namedAccount } from './accounts' - -const path = require("path"); - -function writePrysmConfig(argv: any) { - const prysm = ` -CONFIG_NAME: interop -PRESET_BASE: interop - -# Genesis -GENESIS_FORK_VERSION: 0x20000089 - -# Altair -ALTAIR_FORK_EPOCH: 1 -ALTAIR_FORK_VERSION: 0x20000090 - -# Merge -BELLATRIX_FORK_EPOCH: 2 -BELLATRIX_FORK_VERSION: 0x20000091 -TERMINAL_TOTAL_DIFFICULTY: 50 - -# Time parameters -SECONDS_PER_SLOT: 12 -SLOTS_PER_EPOCH: 6 - -# Deposit contract -DEPOSIT_CONTRACT_ADDRESS: 0x4242424242424242424242424242424242424242 - ` - fs.writeFileSync(path.join(consts.configpath, "prysm.yaml"), prysm) -} - -function writeGethGenesisConfig(argv: any) { - const gethConfig = ` - { - "config": { - "ChainName": "l1_chain", - "chainId": 32382, - "consensus": "clique", - "homesteadBlock": 0, - "daoForkSupport": true, - "eip150Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "terminalBlockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "arrowGlacierBlock": 0, - "grayGlacierBlock": 0, - "clique": { - "period": 5, - "epoch": 30000 - }, - "terminalTotalDifficulty": 50 - }, - "difficulty": "1", - "extradata": "0x00000000000000000000000000000000000000000000000000000000000000003f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E0B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x42", - "timestamp": "0x0", - "gasLimit": "0x1C9C380", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "alloc": { - "0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E": { - "balance": "1000000000000000000000000000000000" - }, - "0x4242424242424242424242424242424242424242": { - "balance": "0", - "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100b6578063621fd130146101e3578063c5f2892f14610273575b600080fd5b34801561005057600080fd5b5061009c6004803603602081101561006757600080fd5b8101908080357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916906020019092919050505061029e565b604051808215151515815260200191505060405180910390f35b6101e1600480360360808110156100cc57600080fd5b81019080803590602001906401000000008111156100e957600080fd5b8201836020820111156100fb57600080fd5b8035906020019184600183028401116401000000008311171561011d57600080fd5b90919293919293908035906020019064010000000081111561013e57600080fd5b82018360208201111561015057600080fd5b8035906020019184600183028401116401000000008311171561017257600080fd5b90919293919293908035906020019064010000000081111561019357600080fd5b8201836020820111156101a557600080fd5b803590602001918460018302840111640100000000831117156101c757600080fd5b909192939192939080359060200190929190505050610370565b005b3480156101ef57600080fd5b506101f8610fd0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561023857808201518184015260208101905061021d565b50505050905090810190601f1680156102655780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561027f57600080fd5b50610288610fe2565b6040518082815260200191505060405180910390f35b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061036957507f85640907000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b603087879050146103cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806116ec6026913960400191505060405180910390fd5b60208585905014610428576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001806116836036913960400191505060405180910390fd5b60608383905014610484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061175f6029913960400191505060405180910390fd5b670de0b6b3a76400003410156104e5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806117396026913960400191505060405180910390fd5b6000633b9aca0034816104f457fe5b061461054b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806116b96033913960400191505060405180910390fd5b6000633b9aca00348161055a57fe5b04905067ffffffffffffffff80168111156105c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806117126027913960400191505060405180910390fd5b60606105cb82611314565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a610600602054611314565b60405180806020018060200180602001806020018060200186810386528e8e82818152602001925080828437600081840152601f19601f82011690508083019250505086810385528c8c82818152602001925080828437600081840152601f19601f82011690508083019250505086810384528a818151815260200191508051906020019080838360005b838110156106a657808201518184015260208101905061068b565b50505050905090810190601f1680156106d35780820380516001836020036101000a031916815260200191505b508681038352898982818152602001925080828437600081840152601f19601f820116905080830192505050868103825287818151815260200191508051906020019080838360005b8381101561073757808201518184015260208101905061071c565b50505050905090810190601f1680156107645780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b6040516020018084848082843780830192505050826fffffffffffffffffffffffffffffffff19166fffffffffffffffffffffffffffffffff1916815260100193505050506040516020818303038152906040526040518082805190602001908083835b6020831061080e57805182526020820191506020810190506020830392506107eb565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610850573d6000803e3d6000fd5b5050506040513d602081101561086557600080fd5b8101908080519060200190929190505050905060006002808888600090604092610891939291906115da565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108eb57805182526020820191506020810190506020830392506108c8565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561092d573d6000803e3d6000fd5b5050506040513d602081101561094257600080fd5b8101908080519060200190929190505050600289896040908092610968939291906115da565b6000801b604051602001808484808284378083019250505082815260200193505050506040516020818303038152906040526040518082805190602001908083835b602083106109cd57805182526020820191506020810190506020830392506109aa565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610a0f573d6000803e3d6000fd5b5050506040513d6020811015610a2457600080fd5b810190808051906020019092919050505060405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610a8e5780518252602082019150602081019050602083039250610a6b565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610ad0573d6000803e3d6000fd5b5050506040513d6020811015610ae557600080fd5b810190808051906020019092919050505090506000600280848c8c604051602001808481526020018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610b615780518252602082019150602081019050602083039250610b3e565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610ba3573d6000803e3d6000fd5b5050506040513d6020811015610bb857600080fd5b8101908080519060200190929190505050600286600060401b866040516020018084805190602001908083835b60208310610c085780518252602082019150602081019050602083039250610be5565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610c935780518252602082019150602081019050602083039250610c70565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610cd5573d6000803e3d6000fd5b5050506040513d6020811015610cea57600080fd5b810190808051906020019092919050505060405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610d545780518252602082019150602081019050602083039250610d31565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610d96573d6000803e3d6000fd5b5050506040513d6020811015610dab57600080fd5b81019080805190602001909291905050509050858114610e16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252605481526020018061162f6054913960600191505060405180910390fd5b6001602060020a0360205410610e77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602181526020018061160e6021913960400191505060405180910390fd5b60016020600082825401925050819055506000602054905060008090505b6020811015610fb75760018083161415610ec8578260008260208110610eb757fe5b018190555050505050505050610fc7565b600260008260208110610ed757fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610f335780518252602082019150602081019050602083039250610f10565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610f75573d6000803e3d6000fd5b5050506040513d6020811015610f8a57600080fd5b8101908080519060200190929190505050925060028281610fa757fe5b0491508080600101915050610e95565b506000610fc057fe5b5050505050505b50505050505050565b6060610fdd602054611314565b905090565b6000806000602054905060008090505b60208110156111d057600180831614156110e05760026000826020811061101557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310611071578051825260208201915060208101905060208303925061104e565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156110b3573d6000803e3d6000fd5b5050506040513d60208110156110c857600080fd5b810190808051906020019092919050505092506111b6565b600283602183602081106110f057fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061114b5780518252602082019150602081019050602083039250611128565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561118d573d6000803e3d6000fd5b5050506040513d60208110156111a257600080fd5b810190808051906020019092919050505092505b600282816111c057fe5b0491508080600101915050610ff2565b506002826111df602054611314565b600060401b6040516020018084815260200183805190602001908083835b6020831061122057805182526020820191506020810190506020830392506111fd565b6001836020036101000a0380198251168184511680821785525050505050509050018267ffffffffffffffff191667ffffffffffffffff1916815260180193505050506040516020818303038152906040526040518082805190602001908083835b602083106112a55780518252602082019150602081019050602083039250611282565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156112e7573d6000803e3d6000fd5b5050506040513d60208110156112fc57600080fd5b81019080805190602001909291905050509250505090565b6060600867ffffffffffffffff8111801561132e57600080fd5b506040519080825280601f01601f1916602001820160405280156113615781602001600182028036833780820191505090505b50905060008260c01b90508060076008811061137957fe5b1a60f81b8260008151811061138a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806006600881106113c657fe5b1a60f81b826001815181106113d757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060056008811061141357fe5b1a60f81b8260028151811061142457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060046008811061146057fe5b1a60f81b8260038151811061147157fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806003600881106114ad57fe5b1a60f81b826004815181106114be57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806002600881106114fa57fe5b1a60f81b8260058151811061150b57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060016008811061154757fe5b1a60f81b8260068151811061155857fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060006008811061159457fe5b1a60f81b826007815181106115a557fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b600080858511156115ea57600080fd5b838611156115f757600080fd5b600185028301915084860390509450949250505056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a2646970667358221220230afd4b6e3551329e50f1239e08fa3ab7907b77403c4f237d9adf679e8e43cf64736f6c634300060b0033" - }, - "0x123463a4B065722E99115D6c222f267d9cABb524": { - "balance": "20000000000000000000000" - }, - "0x5678E9E827B3be0E3d4b910126a64a697a148267": { - "balance": "20000000000000000000000" - }, - "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": { - "balance": "10000000000000000000000" - }, - "0x70997970c51812dc3a010c7d01b50e0d17dc79c8": { - "balance": "10000000000000000000000" - }, - "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc": { - "balance": "10000000000000000000000" - }, - "0x90f79bf6eb2c4f870365e785982e1f101e93b906": { - "balance": "10000000000000000000000" - }, - "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65": { - "balance": "10000000000000000000000" - }, - "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc": { - "balance": "10000000000000000000000" - }, - "0x976ea74026e726554db657fa54763abd0c3a0aa9": { - "balance": "10000000000000000000000" - }, - "0x14dc79964da2c08b23698b3d3cc7ca32193d9955": { - "balance": "10000000000000000000000" - }, - "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f": { - "balance": "10000000000000000000000" - }, - "0xa0ee7a142d267c1f36714e4a8f75612f20a79720": { - "balance": "10000000000000000000000" - }, - "0xbcd4042de499d14e55001ccbb24a551f3b954096": { - "balance": "10000000000000000000000" - }, - "0x71be63f3384f5fb98995898a86b02fb2426c5788": { - "balance": "10000000000000000000000" - }, - "0xfabb0ac9d68b0b445fb7357272ff202c5651694a": { - "balance": "10000000000000000000000" - }, - "0x1cbd3b2770909d4e10f157cabc84c7264073c9ec": { - "balance": "10000000000000000000000" - }, - "0xdf3e18d64bc6a983f673ab319ccae4f1a57c7097": { - "balance": "10000000000000000000000" - }, - "0xcd3b766ccdd6ae721141f452c550ca635964ce71": { - "balance": "10000000000000000000000" - }, - "0x2546bcd3c84621e976d8185a91a922ae77ecec30": { - "balance": "10000000000000000000000" - }, - "0xbda5747bfd65f08deb54cb465eb87d40e51b197e": { - "balance": "10000000000000000000000" - }, - "0xdd2fd4581271e230360230f9337d5c0430bf44c0": { - "balance": "10000000000000000000000" - }, - "0x8626f6940e2eb28930efb4cef49b2d1f2c9c1199": { - "balance": "10000000000000000000000" - } - } - } - ` - fs.writeFileSync(path.join(consts.configpath, "geth_genesis.json"), gethConfig) - const jwt = `0x98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4` - fs.writeFileSync(path.join(consts.configpath, "jwt.hex"), jwt) - const val_jwt = `0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855` - fs.writeFileSync(path.join(consts.configpath, "val_jwt.hex"), val_jwt) -} - -function writeConfigs(argv: any) { - const valJwtSecret = path.join(consts.configpath, "val_jwt.hex") - const chainInfoFile = path.join(consts.configpath, "l2_chain_info.json") - const baseConfig = { - "parent-chain": { - "connection" : { - "url": argv.l1url, - }, - "wallet": { - "account": "", - "password": consts.l1passphrase, - "pathname": consts.l1keystore, - }, - }, - "chain": { - "id": 412346, - "dev-wallet" : { - "private-key": "e887f7d17d07cc7b8004053fb8826f6657084e88904bb61590e498ca04704cf2" - }, - "info-files": [chainInfoFile], - }, - "node": { - "archive": true, - "forwarding-target": "null", - "staker": { - "dangerous": { - "without-block-validator": false - }, - "disable-challenge": false, - "enable": false, - "staker-interval": "10s", - "make-assertion-interval": "10s", - "strategy": "MakeNodes", - }, - "sequencer": { - "enable": false - }, - "delayed-sequencer": { - "enable": false - }, - "seq-coordinator": { - "enable": false, - "redis-url": argv.redisUrl, - "lockout-duration": "30s", - "lockout-spare": "1s", - "my-url": "", - "retry-interval": "0.5s", - "seq-num-duration": "24h0m0s", - "update-interval": "3s", - }, - "batch-poster": { - "enable": false, - "redis-url": argv.redisUrl, - "max-delay": "30s", - "data-poster": { - "redis-signer": { - "signing-key": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - }, - "wait-for-l1-finality": false - } - }, - "block-validator": { - "validation-server" : { - "url": argv.validationNodeUrl, - "jwtsecret": valJwtSecret, - } - } - }, - "persistent": { - "chain": "local" - }, - "ws": { - "addr": "0.0.0.0" - }, - "http": { - "addr": "0.0.0.0", - "vhosts": "*", - "corsdomain": "*" - }, - } - - - const baseConfJSON = JSON.stringify(baseConfig) - - let validatorConfig = JSON.parse(baseConfJSON) - validatorConfig["parent-chain"].wallet.account = namedAccount("validator").address - validatorConfig.node.staker.enable = true - validatorConfig.node.staker["use-smart-contract-wallet"] = true - let validconfJSON = JSON.stringify(validatorConfig) - fs.writeFileSync(path.join(consts.configpath, "validator_config.json"), validconfJSON) - - let unsafeStakerConfig = JSON.parse(validconfJSON) - unsafeStakerConfig.node.staker.dangerous["without-block-validator"] = true - fs.writeFileSync(path.join(consts.configpath, "unsafe_staker_config.json"), JSON.stringify(unsafeStakerConfig)) - - let sequencerConfig = JSON.parse(baseConfJSON) - sequencerConfig.node.sequencer.enable = true - sequencerConfig.node["seq-coordinator"].enable = true - sequencerConfig.node["delayed-sequencer"].enable = true - fs.writeFileSync(path.join(consts.configpath, "sequencer_config.json"), JSON.stringify(sequencerConfig)) - - let posterConfig = JSON.parse(baseConfJSON) - posterConfig["parent-chain"].wallet.account = namedAccount("sequencer").address - posterConfig.node["seq-coordinator"].enable = true - posterConfig.node["batch-poster"].enable = true - fs.writeFileSync(path.join(consts.configpath, "poster_config.json"), JSON.stringify(posterConfig)) - - let validationNodeConfig = JSON.parse(JSON.stringify({ - "persistent": { - "chain": "local" - }, - "ws": { - "addr": "", - }, - "http": { - "addr": "", - }, - "validation": { - "api-auth": true, - "api-public": false, - }, - "auth": { - "jwtsecret": valJwtSecret, - "addr": "0.0.0.0", - }, - })) - fs.writeFileSync(path.join(consts.configpath, "validation_node_config.json"), JSON.stringify(validationNodeConfig)) -} - -function writeL2ChainConfig(argv: any) { - const l2ChainConfig = { - "chainId": 412346, - "homesteadBlock": 0, - "daoForkSupport": true, - "eip150Block": 0, - "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "clique": { - "period": 0, - "epoch": 0 - }, - "arbitrum": { - "EnableArbOS": true, - "AllowDebugPrecompiles": true, - "DataAvailabilityCommittee": false, - "InitialArbOSVersion": 11, - "InitialChainOwner": "0x0000000000000000000000000000000000000000", - "GenesisBlockNum": 0 - } - } - const l2ChainConfigJSON = JSON.stringify(l2ChainConfig) - fs.writeFileSync(path.join(consts.configpath, "l2_chain_config.json"), l2ChainConfigJSON) -} - -export const writeConfigCommand = { - command: "write-config", - describe: "writes config files", - handler: (argv: any) => { - writeConfigs(argv) - } -} - -export const writePrysmCommand = { - command: "write-prysm-config", - describe: "writes prysm config files", - handler: (argv: any) => { - writePrysmConfig(argv) - } -} - -export const writeGethGenesisCommand = { - command: "write-geth-genesis-config", - describe: "writes a go-ethereum genesis configuration", - handler: (argv: any) => { - writeGethGenesisConfig(argv) - } -} - -export const writeL2ChainConfigCommand = { - command: "write-l2-chain-config", - describe: "writes l2 chain config file", - handler: (argv: any) => { - writeL2ChainConfig(argv) - } -} diff --git a/testnode-scripts/consts.ts b/testnode-scripts/consts.ts deleted file mode 100644 index 72728d2801..0000000000 --- a/testnode-scripts/consts.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const l1keystore = "/home/user/l1keystore"; -export const l1passphrase = "passphrase"; -export const configpath = "/config"; -// Not secure. Do not sure for production purposes -export const l1mnemonic = - "indoor dish desk flag debris potato excuse depart ticket judge file exit"; diff --git a/testnode-scripts/ethcommands.ts b/testnode-scripts/ethcommands.ts deleted file mode 100644 index ff71fa3f1c..0000000000 --- a/testnode-scripts/ethcommands.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { runStress } from "./stress"; -import { ethers } from "ethers"; -import * as consts from "./consts"; -import { namedAccount, namedAddress } from "./accounts"; -import * as fs from "fs"; -const path = require("path"); - -async function sendTransaction(argv: any, threadId: number) { - const account = namedAccount(argv.from, threadId).connect(argv.provider) - const startNonce = await account.getTransactionCount("pending") - for (let index = 0; index < argv.times; index++) { - const response = await - account.sendTransaction({ - to: namedAddress(argv.to, threadId), - value: ethers.utils.parseEther(argv.ethamount), - data: argv.data, - nonce: startNonce + index, - }) - console.log(response) - if (argv.wait) { - const receipt = await response.wait() - console.log(receipt) - } - if (argv.delay > 0) { - await new Promise(f => setTimeout(f, argv.delay)); - } - } -} - -export const bridgeFundsCommand = { - command: "bridge-funds", - describe: "sends funds from l1 to l2", - builder: { - ethamount: { - string: true, - describe: "amount to transfer (in eth)", - default: "10", - }, - from: { - string: true, - describe: "account (see general help)", - default: "funnel", - }, - wait: { - boolean: true, - describe: "wait till l2 has balance of ethamount", - default: false, - }, - }, - handler: async (argv: any) => { - argv.provider = new ethers.providers.WebSocketProvider(argv.l1url); - - const deploydata = JSON.parse( - fs - .readFileSync(path.join(consts.configpath, "deployment.json")) - .toString() - ); - const inboxAddr = ethers.utils.hexlify(deploydata.inbox); - argv.to = "address_" + inboxAddr; - argv.data = - "0x0f4d14e9000000000000000000000000000000000000000000000000000082f79cd90000"; - - await runStress(argv, sendTransaction); - - argv.provider.destroy(); - if (argv.wait) { - const l2provider = new ethers.providers.WebSocketProvider(argv.l2url); - const account = namedAccount(argv.from, argv.threadId).connect(l2provider) - const sleep = (ms: number) => new Promise(r => setTimeout(r, ms)); - while (true) { - const balance = await account.getBalance() - if (balance >= ethers.utils.parseEther(argv.ethamount)) { - return - } - await sleep(100) - } - } - }, -}; - -export const sendL1Command = { - command: "send-l1", - describe: "sends funds between l1 accounts", - builder: { - ethamount: { - string: true, - describe: "amount to transfer (in eth)", - default: "10", - }, - from: { - string: true, - describe: "account (see general help)", - default: "funnel", - }, - to: { - string: true, - describe: "address (see general help)", - default: "funnel", - }, - wait: { - boolean: true, - describe: "wait for transaction to complete", - default: false, - }, - data: { string: true, describe: "data" }, - }, - handler: async (argv: any) => { - argv.provider = new ethers.providers.WebSocketProvider(argv.l1url); - - await runStress(argv, sendTransaction); - - argv.provider.destroy(); - }, -}; - -export const sendL2Command = { - command: "send-l2", - describe: "sends funds between l2 accounts", - builder: { - ethamount: { - string: true, - describe: "amount to transfer (in eth)", - default: "10", - }, - from: { - string: true, - describe: "account (see general help)", - default: "funnel", - }, - to: { - string: true, - describe: "address (see general help)", - default: "funnel", - }, - wait: { - boolean: true, - describe: "wait for transaction to complete", - default: false, - }, - data: { string: true, describe: "data" }, - }, - handler: async (argv: any) => { - argv.provider = new ethers.providers.WebSocketProvider(argv.l2url); - - await runStress(argv, sendTransaction); - - argv.provider.destroy(); - }, -}; - -export const sendRPCCommand = { - command: "send-rpc", - describe: "sends funds to l2 node", - builder: { - method: { string: true, describe: "rpc method to call", default: "eth_syncing" }, - url: { string: true, describe: "url to send rpc call", default: "http://sequencer:8547"}, - params: { array : true, describe: "array of parameter name/values" }, - }, - handler: async (argv: any) => { - const rpcProvider = new ethers.providers.JsonRpcProvider(argv.url) - - await rpcProvider.send(argv.method, argv.params) - } -} diff --git a/testnode-scripts/index.ts b/testnode-scripts/index.ts deleted file mode 100644 index c980558e64..0000000000 --- a/testnode-scripts/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { hideBin } from "yargs/helpers"; -import Yargs from "yargs/yargs"; -import { stressOptions } from "./stress"; -import { redisReadCommand, redisInitCommand } from "./redis"; -import { writeConfigCommand, writeGethGenesisCommand, writePrysmCommand, writeL2ChainConfigCommand } from "./config"; -import { - printAddressCommand, - namedAccountHelpString, - writeAccountsCommand, -} from "./accounts"; -import { - bridgeFundsCommand, - sendL1Command, - sendL2Command, - sendRPCCommand, -} from "./ethcommands"; - -async function main() { - await Yargs(hideBin(process.argv)) - .options({ - redisUrl: { string: true, default: "redis://redis:6379" }, - l1url: { string: true, default: "ws://geth:8546" }, - l2url: { string: true, default: "ws://sequencer:8548" }, - validationNodeUrl: { string: true, default: "ws://validation_node:8549" }, - }) - .options(stressOptions) - .command(bridgeFundsCommand) - .command(sendL1Command) - .command(sendL2Command) - .command(sendRPCCommand) - .command(writeConfigCommand) - .command(writeGethGenesisCommand) - .command(writeL2ChainConfigCommand) - .command(writePrysmCommand) - .command(writeAccountsCommand) - .command(printAddressCommand) - .command(redisReadCommand) - .command(redisInitCommand) - .strict() - .demandCommand(1, "a command must be specified") - .epilogue(namedAccountHelpString) - .help().argv; -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); diff --git a/testnode-scripts/package.json b/testnode-scripts/package.json deleted file mode 100644 index e6ab62ec98..0000000000 --- a/testnode-scripts/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "nitro-testnode-scripts", - "version": "1.0.0", - "description": "testing environment Arbitrum Nitro", - "main": "index.js", - "author": "Offchain Labs, Inc.", - "license": "Apache-2.0", - "dependencies": { - "@node-redis/client": "^1.0.4", - "@types/node": "^17.0.22", - "@types/yargs": "^17.0.10", - "ethers": "^5.6.1", - "path": "^0.12.7", - "typescript": "^4.6.2", - "yargs": "^17.4.0" - }, - "scripts": { - "build": "tsc -p .", - "postinstall": "echo 'Postinstall running without source available'" - }, - "private": true, - "devDependencies": {} -} diff --git a/testnode-scripts/redis.ts b/testnode-scripts/redis.ts deleted file mode 100644 index 1d13c21d9f..0000000000 --- a/testnode-scripts/redis.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { - createClient, - RedisClientType, - RedisModules, - RedisScripts, -} from "@node-redis/client"; - -async function getAndPrint( - redis: RedisClientType, - key: string -) { - const val = await redis.get(key); - console.log("redis[%s]:%s", key, val); -} - -async function readRedis(redisUrl: string, key: string) { - const redis = createClient({ url: redisUrl }); - await redis.connect(); - await getAndPrint(redis, key); -} - -export const redisReadCommand = { - command: "redis-read", - describe: "read key", - builder: { - key: { - string: true, - describe: "key to read", - default: "coordinator.priorities", - }, - }, - handler: async (argv: any) => { - await readRedis(argv.redisUrl, argv.key); - }, -}; - -async function writeRedisPriorities(redisUrl: string, priorities: number) { - const redis = createClient({ url: redisUrl }); - - let prio_sequencers = "bcd"; - let priostring = ""; - if (priorities == 0) { - priostring = "ws://sequencer:8548"; - } - if (priorities > prio_sequencers.length) { - priorities = prio_sequencers.length; - } - for (let index = 0; index < priorities; index++) { - const this_prio = - "ws://sequencer_" + prio_sequencers.charAt(index) + ":8548"; - if (index != 0) { - priostring = priostring + ","; - } - priostring = priostring + this_prio; - } - await redis.connect(); - - await redis.set("coordinator.priorities", priostring); - - await getAndPrint(redis, "coordinator.priorities"); -} - -export const redisInitCommand = { - command: "redis-init", - describe: "init redis priorities", - builder: { - redundancy: { - string: true, - describe: "number of servers [0-3]", - default: 0, - }, - }, - handler: async (argv: any) => { - await writeRedisPriorities(argv.redisUrl, argv.redundancy); - }, -}; diff --git a/testnode-scripts/stress.ts b/testnode-scripts/stress.ts deleted file mode 100644 index df5807cf1c..0000000000 --- a/testnode-scripts/stress.ts +++ /dev/null @@ -1,31 +0,0 @@ - -export const stressOptions = { - times: { number: true, description: 'times to repeat per thread', default: 1 }, - delay: { number: true, description: 'delay between repeats (ms)', default: 0 }, - threads: { number: true, default: 1 }, - threadId: { number: true, description: 'first thread-Id used', default: 0 }, - serial: { boolean: true, description: 'do all actions serially (e.g. when from is identical for all threads)', default: false } -} - - -async function runThread(argv: any, threadIndex: number, commandHandler: (argv: any, thread: number) => Promise) { - await commandHandler(argv, threadIndex) -} - -export async function runStress(argv: any, commandHandler: (argv: any, thread: number) => Promise) { - let promiseArray: Array> - promiseArray = [] - for (let threadIndex = 0; threadIndex < argv.threads; threadIndex++) { - const threadPromise = runThread(argv, threadIndex + argv.threadId, commandHandler) - if (argv.serial) { - await threadPromise - } else { - promiseArray.push(threadPromise) - } - } - await Promise.all(promiseArray) - .catch(error => { - console.error(error) - process.exit(1) - }) -} diff --git a/testnode-scripts/tsconfig.json b/testnode-scripts/tsconfig.json deleted file mode 100644 index c90e21b482..0000000000 --- a/testnode-scripts/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2015", - "module": "CommonJS", - "strict": true, - "esModuleInterop": true, - "moduleResolution": "node" - }, - "files": ["index.ts"] - } diff --git a/testnode-scripts/yarn.lock b/testnode-scripts/yarn.lock deleted file mode 100644 index 624f5bcc28..0000000000 --- a/testnode-scripts/yarn.lock +++ /dev/null @@ -1,649 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@ethersproject/abi@5.6.0", "@ethersproject/abi@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.6.0.tgz#ea07cbc1eec2374d32485679c12408005895e9f3" - integrity sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg== - dependencies: - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/abstract-provider@5.6.0", "@ethersproject/abstract-provider@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz#0c4ac7054650dbd9c476cf5907f588bbb6ef3061" - integrity sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/web" "^5.6.0" - -"@ethersproject/abstract-signer@5.6.0", "@ethersproject/abstract-signer@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz#9cd7ae9211c2b123a3b29bf47aab17d4d016e3e7" - integrity sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/address@5.6.0", "@ethersproject/address@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.0.tgz#13c49836d73e7885fc148ad633afad729da25012" - integrity sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - -"@ethersproject/base64@5.6.0", "@ethersproject/base64@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.0.tgz#a12c4da2a6fb86d88563216b0282308fc15907c9" - integrity sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw== - dependencies: - "@ethersproject/bytes" "^5.6.0" - -"@ethersproject/basex@5.6.0", "@ethersproject/basex@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.6.0.tgz#9ea7209bf0a1c3ddc2a90f180c3a7f0d7d2e8a69" - integrity sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - -"@ethersproject/bignumber@5.6.0", "@ethersproject/bignumber@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.0.tgz#116c81b075c57fa765a8f3822648cf718a8a0e26" - integrity sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - bn.js "^4.11.9" - -"@ethersproject/bytes@5.6.0", "@ethersproject/bytes@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20" - integrity sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/constants@5.6.0", "@ethersproject/constants@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.0.tgz#55e3eb0918584d3acc0688e9958b0cedef297088" - integrity sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - -"@ethersproject/contracts@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.6.0.tgz#60f2cfc7addd99a865c6c8cfbbcec76297386067" - integrity sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw== - dependencies: - "@ethersproject/abi" "^5.6.0" - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - -"@ethersproject/hash@5.6.0", "@ethersproject/hash@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.0.tgz#d24446a5263e02492f9808baa99b6e2b4c3429a2" - integrity sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/hdnode@5.6.0", "@ethersproject/hdnode@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.6.0.tgz#9dcbe8d629bbbcf144f2cae476337fe92d320998" - integrity sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/basex" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/wordlists" "^5.6.0" - -"@ethersproject/json-wallets@5.6.0", "@ethersproject/json-wallets@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz#4c2fc27f17e36c583e7a252fb938bc46f98891e5" - integrity sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hdnode" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/pbkdf2" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@5.6.0", "@ethersproject/keccak256@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.0.tgz#fea4bb47dbf8f131c2e1774a1cecbfeb9d606459" - integrity sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w== - dependencies: - "@ethersproject/bytes" "^5.6.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@5.6.0", "@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - -"@ethersproject/networks@5.6.0", "@ethersproject/networks@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.0.tgz#486d03fff29b4b6b5414d47a232ded09fe10de5e" - integrity sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/pbkdf2@5.6.0", "@ethersproject/pbkdf2@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz#04fcc2d7c6bff88393f5b4237d906a192426685a" - integrity sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - -"@ethersproject/properties@5.6.0", "@ethersproject/properties@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" - integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== - dependencies: - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/providers@5.6.1": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.6.1.tgz#9a05f00ecbac59565bf6907c8d2af8ac33303b48" - integrity sha512-w8Wx15nH+aVDvnoKCyI1f3x0B5idmk/bDJXMEUqCfdO8Eadd0QpDx9lDMTMmenhOmf9vufLJXjpSm24D3ZnVpg== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/basex" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/web" "^5.6.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@5.6.0", "@ethersproject/random@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.0.tgz#1505d1ab6a250e0ee92f436850fa3314b2cb5ae6" - integrity sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/rlp@5.6.0", "@ethersproject/rlp@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.0.tgz#55a7be01c6f5e64d6e6e7edb6061aa120962a717" - integrity sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/sha2@5.6.0", "@ethersproject/sha2@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.6.0.tgz#364c4c11cc753bda36f31f001628706ebadb64d9" - integrity sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@5.6.0", "@ethersproject/signing-key@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.0.tgz#4f02e3fb09e22b71e2e1d6dc4bcb5dafa69ce042" - integrity sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/solidity@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.6.0.tgz#64657362a596bf7f5630bdc921c07dd78df06dc3" - integrity sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/sha2" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/strings@5.6.0", "@ethersproject/strings@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.0.tgz#9891b26709153d996bf1303d39a7f4bc047878fd" - integrity sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/transactions@5.6.0", "@ethersproject/transactions@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.0.tgz#4b594d73a868ef6e1529a2f8f94a785e6791ae4e" - integrity sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg== - dependencies: - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - -"@ethersproject/units@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.6.0.tgz#e5cbb1906988f5740254a21b9ded6bd51e826d9c" - integrity sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - -"@ethersproject/wallet@5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.0.tgz#33d11a806d783864208f348709a5a3badac8e22a" - integrity sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/hdnode" "^5.6.0" - "@ethersproject/json-wallets" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/random" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/wordlists" "^5.6.0" - -"@ethersproject/web@5.6.0", "@ethersproject/web@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.0.tgz#4bf8b3cbc17055027e1a5dd3c357e37474eaaeb8" - integrity sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg== - dependencies: - "@ethersproject/base64" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@ethersproject/wordlists@5.6.0", "@ethersproject/wordlists@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.6.0.tgz#79e62c5276e091d8575f6930ba01a29218ded032" - integrity sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/hash" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - -"@node-redis/client@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.4.tgz#fe185750df3bcc07524f63fe8dbc8d14d22d6cbb" - integrity sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g== - dependencies: - cluster-key-slot "1.1.0" - generic-pool "3.8.2" - redis-parser "3.0.0" - yallist "4.0.0" - -"@types/node@^17.0.22": - version "17.0.22" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.22.tgz#38b6c4b9b2f3ed9f2e376cce42a298fb2375251e" - integrity sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw== - -"@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== - -"@types/yargs@^17.0.10": - version "17.0.10" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" - integrity sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA== - dependencies: - "@types/yargs-parser" "*" - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" - integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -cluster-key-slot@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" - integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -ethers@^5.6.1: - version "5.6.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.6.1.tgz#a56cd67f1595b745dc3dde0ccf2b5de53a41a6d0" - integrity sha512-qtl/2W+dwmUa5Z3JqwsbV3JEBZZHNARe5K/A2ePcNAuhJYnEKIgGOT/O9ouPwBijSqVoQnmQMzi5D48LFNOY2A== - dependencies: - "@ethersproject/abi" "5.6.0" - "@ethersproject/abstract-provider" "5.6.0" - "@ethersproject/abstract-signer" "5.6.0" - "@ethersproject/address" "5.6.0" - "@ethersproject/base64" "5.6.0" - "@ethersproject/basex" "5.6.0" - "@ethersproject/bignumber" "5.6.0" - "@ethersproject/bytes" "5.6.0" - "@ethersproject/constants" "5.6.0" - "@ethersproject/contracts" "5.6.0" - "@ethersproject/hash" "5.6.0" - "@ethersproject/hdnode" "5.6.0" - "@ethersproject/json-wallets" "5.6.0" - "@ethersproject/keccak256" "5.6.0" - "@ethersproject/logger" "5.6.0" - "@ethersproject/networks" "5.6.0" - "@ethersproject/pbkdf2" "5.6.0" - "@ethersproject/properties" "5.6.0" - "@ethersproject/providers" "5.6.1" - "@ethersproject/random" "5.6.0" - "@ethersproject/rlp" "5.6.0" - "@ethersproject/sha2" "5.6.0" - "@ethersproject/signing-key" "5.6.0" - "@ethersproject/solidity" "5.6.0" - "@ethersproject/strings" "5.6.0" - "@ethersproject/transactions" "5.6.0" - "@ethersproject/units" "5.6.0" - "@ethersproject/wallet" "5.6.0" - "@ethersproject/web" "5.6.0" - "@ethersproject/wordlists" "5.6.0" - -generic-pool@3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" - integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -inherits@^2.0.3, inherits@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -path@^0.12.7: - version "0.12.7" - resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" - integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= - dependencies: - process "^0.11.1" - util "^0.10.3" - -process@^0.11.1: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -redis-errors@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= - -redis-parser@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= - dependencies: - redis-errors "^1.0.0" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -typescript@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== - -util@^0.10.3: - version "0.10.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" - integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== - dependencies: - inherits "2.0.3" - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@^21.0.0: - version "21.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" - integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== - -yargs@^17.4.0: - version "17.4.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.4.0.tgz#9fc9efc96bd3aa2c1240446af28499f0e7593d00" - integrity sha512-WJudfrk81yWFSOkZYpAZx4Nt7V4xp7S/uJkX0CnxovMCt1wCE8LNftPpNuF9X/u9gN5nsD7ycYtRcDf2pL3UiA== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.0.0" diff --git a/testnode-tokenbridge/Dockerfile b/testnode-tokenbridge/Dockerfile deleted file mode 100644 index 9ac611fe77..0000000000 --- a/testnode-tokenbridge/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM node:16-bullseye-slim -RUN apt-get update && \ - apt-get install -y git docker.io -WORKDIR /workspace -RUN git clone -b v3.0.0 https://github.com/OffchainLabs/arbitrum-sdk.git ./ -RUN yarn install -ENTRYPOINT ["yarn"] diff --git a/util/headerreader/header_reader.go b/util/headerreader/header_reader.go index 9fc563c194..f25fed02d9 100644 --- a/util/headerreader/header_reader.go +++ b/util/headerreader/header_reader.go @@ -380,6 +380,19 @@ func (s *HeaderReader) LastPendingCallBlockNr() uint64 { var ErrBlockNumberNotSupported = errors.New("block number not supported") +func headerIndicatesFinalitySupport(header *types.Header) bool { + if header.Difficulty.Sign() == 0 { + // This is an Ethereum PoS chain + return true + } + if types.DeserializeHeaderExtraInformation(header).ArbOSFormatVersion > 0 { + // This is an Arbitrum chain + return true + } + // This is probably an Ethereum PoW or Clique chain, which doesn't support finality + return false +} + func (s *HeaderReader) getCached(ctx context.Context, c *cachedBlockNumber) (uint64, error) { c.mutex.Lock() defer c.mutex.Unlock() @@ -390,7 +403,7 @@ func (s *HeaderReader) getCached(ctx context.Context, c *cachedBlockNumber) (uin if currentHead == c.headWhenCached { return c.blockNumber, nil } - if !s.config().UseFinalityData || currentHead.Difficulty.Sign() != 0 { + if !s.config().UseFinalityData || !headerIndicatesFinalitySupport(currentHead) { return 0, ErrBlockNumberNotSupported } header, err := s.client.HeaderByNumber(ctx, c.rpcBlockNum) diff --git a/util/testhelpers/testhelpers.go b/util/testhelpers/testhelpers.go index 6bc40e0b5a..bccc269171 100644 --- a/util/testhelpers/testhelpers.go +++ b/util/testhelpers/testhelpers.go @@ -4,7 +4,7 @@ package testhelpers import ( - "math/rand" + "crypto/rand" "os" "regexp" "sync" diff --git a/validator/execution_state.go b/validator/execution_state.go index 617de76a0a..092fbe2908 100644 --- a/validator/execution_state.go +++ b/validator/execution_state.go @@ -54,7 +54,7 @@ func (s GoGlobalState) AsSolidityStruct() challengegen.GlobalState { } } -func NewExecutionStateFromSolidity(eth rollupgen.RollupLibExecutionState) *ExecutionState { +func NewExecutionStateFromSolidity(eth rollupgen.ExecutionState) *ExecutionState { return &ExecutionState{ GlobalState: GoGlobalStateFromSolidity(challengegen.GlobalState(eth.GlobalState)), MachineStatus: MachineStatus(eth.MachineStatus), @@ -70,8 +70,8 @@ func GoGlobalStateFromSolidity(gs challengegen.GlobalState) GoGlobalState { } } -func (s *ExecutionState) AsSolidityStruct() rollupgen.RollupLibExecutionState { - return rollupgen.RollupLibExecutionState{ +func (s *ExecutionState) AsSolidityStruct() rollupgen.ExecutionState { + return rollupgen.ExecutionState{ GlobalState: rollupgen.GlobalState(s.GlobalState.AsSolidityStruct()), MachineStatus: uint8(s.MachineStatus), } diff --git a/validator/server_api/valiation_api.go b/validator/server_api/valiation_api.go index c8a276536b..9e5191ec81 100644 --- a/validator/server_api/valiation_api.go +++ b/validator/server_api/valiation_api.go @@ -60,7 +60,6 @@ type ExecServerAPI struct { } func NewExecutionServerAPI(valSpawner validator.ValidationSpawner, execution validator.ExecutionSpawner, config server_arb.ArbitratorSpawnerConfigFecher) *ExecServerAPI { - rand.Seed(time.Now().UnixNano()) return &ExecServerAPI{ ValidationServerAPI: *NewValidationServerAPI(valSpawner), execSpawner: execution,