diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 9291f7a6cf20..7d1524e60375 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -51,10 +51,10 @@ jobs: - name: Generate test vectors run: cargo run --bin reth -- test-vectors tables - name: Save baseline - run: cargo bench -p reth-db --bench iai --features test-utils -- --save-baseline=$BASELINE + run: cargo bench -p reth-db --bench iai --profile profiling --features test-utils -- --save-baseline=$BASELINE - name: Checkout PR uses: actions/checkout@v4 with: clean: false - name: Compare PR benchmarks - run: cargo bench -p reth-db --bench iai --features test-utils -- --baseline=$BASELINE + run: cargo bench -p reth-db --bench iai --profile profiling --features test-utils -- --baseline=$BASELINE diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 20ae6644b909..2af324a39eb7 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -39,14 +39,10 @@ jobs: docker run --privileged --rm tonistiigi/binfmt --install arm64,amd64 docker buildx create --use --name cross-builder - name: Build and push reth image, tag as "latest" - if: ${{ contains(github.event.ref, 'beta') }} run: make PROFILE=maxperf docker-build-push-latest - name: Build and push reth image - if: ${{ ! contains(github.event.ref, 'beta') }} run: make PROFILE=maxperf docker-build-push - name: Build and push op-reth image, tag as "latest" - if: ${{ contains(github.event.ref, 'beta') }} run: make IMAGE_NAME=$OP_IMAGE_NAME DOCKER_IMAGE_NAME=$OP_DOCKER_IMAGE_NAME PROFILE=maxperf op-docker-build-push-latest - name: Build and push op-reth image - if: ${{ ! contains(github.event.ref, 'beta') }} run: make IMAGE_NAME=$OP_IMAGE_NAME DOCKER_IMAGE_NAME=$OP_DOCKER_IMAGE_NAME PROFILE=maxperf op-docker-build-push diff --git a/.github/workflows/eth-sync.yml b/.github/workflows/eth-sync.yml new file mode 100644 index 000000000000..54c0d96079b9 --- /dev/null +++ b/.github/workflows/eth-sync.yml @@ -0,0 +1,50 @@ +# Runs an ethereum mainnet sync test. + +name: eth-sync-test + +on: + pull_request: + merge_group: + push: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + sync: + name: sync / 100k blocks + # Only run sync tests in merge groups + if: github.event_name == 'merge_group' + runs-on: + group: Reth + env: + RUST_LOG: info,sync=error + RUST_BACKTRACE: 1 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + - name: Build reth + run: | + cargo install --features asm-keccak,jemalloc --path bin/reth + - name: Run sync + run: | + reth node \ + --debug.tip 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 \ + --debug.max-block 100000 \ + --debug.terminate + - name: Verify the target block hash + run: | + reth db get static-file headers 100000 \ + | grep 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 + - name: Run stage unwind for 100 blocks + run: | + reth stage unwind num-blocks 100 diff --git a/.github/workflows/hive.yml b/.github/workflows/hive.yml index e34470e4dedd..3340393d0873 100644 --- a/.github/workflows/hive.yml +++ b/.github/workflows/hive.yml @@ -68,9 +68,9 @@ jobs: matrix: # TODO: enable etherem/sync once resolved: # https://github.com/paradigmxyz/reth/issues/8579 - # TODO: enable ethereum/rpc once resolved: + # ethereum/rpc to be deprecated: # https://github.com/ethereum/hive/pull/1117 - # sim: [ethereum/rpc, smoke/genesis, smoke/network, ethereum/sync] + # sim: [smoke/genesis, smoke/network, ethereum/sync] sim: [smoke/genesis, smoke/network] include: - sim: devp2p @@ -107,11 +107,12 @@ jobs: - sim: ethereum/engine limit: engine-transition # TODO: enable engine-api once resolved: - # https://github.com/paradigmxyz/reth/issues/6217 # https://github.com/paradigmxyz/reth/issues/8305 + # https://github.com/paradigmxyz/reth/issues/6217 # - sim: ethereum/engine # limit: engine-api # TODO: enable cancun once resolved: + # https://github.com/paradigmxyz/reth/issues/8305 # https://github.com/paradigmxyz/reth/issues/6217 # https://github.com/paradigmxyz/reth/issues/8306 # https://github.com/paradigmxyz/reth/issues/7144 diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index a57411744939..b4b494a90256 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -41,7 +41,7 @@ jobs: run: | cargo nextest run \ --locked --features "asm-keccak ${{ matrix.network }}" \ - --workspace --exclude example-exex-remote --exclude ef-tests \ + --workspace --exclude ef-tests \ -E "kind(test)" - if: matrix.network == 'optimism' name: Run tests @@ -49,39 +49,6 @@ jobs: cargo nextest run \ --locked -p reth-node-optimism --features "optimism" - sync: - name: sync / 100k blocks - # Only run sync tests in merge groups - if: github.event_name == 'merge_group' - runs-on: - group: Reth - env: - RUST_LOG: info,sync=error - RUST_BACKTRACE: 1 - timeout-minutes: 60 - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - with: - cache-on-failure: true - - name: Run sync - run: | - cargo run --release --features asm-keccak,jemalloc,min-error-logs --bin reth \ - -- node \ - --debug.tip 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 \ - --debug.max-block 100000 \ - --debug.terminate - - name: Verify the target block hash - run: | - cargo run --release --bin reth \ - -- db get static-file headers 100000 \ - | grep 0x91c90676cab257a59cd956d7cb0bceb9b1a71d79755c23c7277a0697ccfaf8c4 - - name: Run stage unwind for 100 blocks - run: | - cargo run --release --bin reth \ - -- stage unwind num-blocks 100 - integration-success: name: integration success runs-on: ubuntu-latest diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c758f6945a05..c07cee38830b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -41,7 +41,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - uses: arduino/setup-protoc@v3 - run: cargo clippy --workspace --lib --examples --tests --benches --all-features --locked env: RUSTFLAGS: -D warnings @@ -71,7 +70,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - uses: arduino/setup-protoc@v3 - run: cargo hack check msrv: @@ -107,7 +105,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - uses: arduino/setup-protoc@v3 - run: cargo docs --document-private-items env: # Keep in sync with ./book.yml:jobs.build diff --git a/.github/workflows/op-sync.yml b/.github/workflows/op-sync.yml new file mode 100644 index 000000000000..73303b032d05 --- /dev/null +++ b/.github/workflows/op-sync.yml @@ -0,0 +1,52 @@ +# Runs a base mainnet sync test. + +name: op-sync-test + +on: + pull_request: + merge_group: + push: + branches: [main] + +env: + CARGO_TERM_COLOR: always + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + sync: + name: op sync / 10k blocks + # Only run sync tests in merge groups + if: github.event_name == 'merge_group' + runs-on: + group: Reth + env: + RUST_LOG: info,sync=error + RUST_BACKTRACE: 1 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + - name: Build op-reth + run: | + cargo install --features asm-keccak,jemalloc,optimism --bin op-reth --path bin/reth + - name: Run sync + # https://basescan.org/block/10000 + run: | + op-reth node \ + --chain base \ + --debug.tip 0xbb9b85352c7ebca6ba8efc63bd66cecd038c92ec8ebd02e153a3e0b197e672b7 \ + --debug.max-block 10000 \ + --debug.terminate + - name: Verify the target block hash + run: | + op-reth db --chain base get static-file headers 10000 \ + | grep 0xbb9b85352c7ebca6ba8efc63bd66cecd038c92ec8ebd02e153a3e0b197e672b7 + - name: Run stage unwind for 100 blocks + run: | + op-reth stage --chain base unwind num-blocks 100 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c71b8c530990..5735ae6ef528 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -175,7 +175,7 @@ jobs: [See pre-built binaries documentation.](https://paradigmxyz.github.io/reth/installation/binaries.html) - The binaries are signed with the PGP key: `A3AE 097C 8909 3A12 4049 DF1F 5391 A3C4 1005 30B4` + The binaries are signed with the PGP key: `50FB 7CC5 5B2E 8AFA 59FE 03B7 AA5E D56A 7FBF 253E` | System | Architecture | Binary | PGP Signature | |:---:|:---:|:---:|:---| diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index a5d42a85d208..a6663aea8843 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -39,7 +39,7 @@ jobs: run: | cargo nextest run \ --locked --features "asm-keccak ${{ matrix.network }}" \ - --workspace --exclude example-exex-remote --exclude ef-tests \ + --workspace --exclude ef-tests \ --partition hash:${{ matrix.partition }}/2 \ -E "!kind(test)" @@ -84,7 +84,6 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - - uses: arduino/setup-protoc@v3 - name: Run doctests run: cargo test --doc --workspace --features "${{ matrix.network }}" diff --git a/CODEOWNERS b/CODEOWNERS index 1fd984ec1291..225d0f08b174 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,8 +6,9 @@ crates/chainspec/ @Rjected @joshieDo @mattsse crates/cli/ @onbjerg @mattsse crates/config/ @onbjerg crates/consensus/ @rkrasiuk @mattsse @Rjected +crates/engine @rkrasiuk @mattsse @Rjected crates/e2e-test-utils/ @mattsse @Rjected -crates/engine-primitives/ @rkrasiuk @mattsse @Rjected +crates/engine/ @rkrasiuk @mattsse @Rjected @fgimenez crates/errors/ @mattsse crates/ethereum/ @mattsse @Rjected crates/ethereum-forks/ @mattsse @Rjected @@ -26,7 +27,7 @@ crates/primitives/ @DaniPopes @Rjected crates/primitives-traits/ @DaniPopes @Rjected @joshieDo crates/prune/ @shekhirin @joshieDo crates/revm/ @mattsse @rakita -crates/rpc/ @mattsse @Rjected +crates/rpc/ @mattsse @Rjected @emhane crates/stages/ @onbjerg @rkrasiuk @shekhirin crates/static-file/ @joshieDo @shekhirin crates/storage/codecs/ @joshieDo diff --git a/Cargo.lock b/Cargo.lock index 4e26b254f381..41180ce37d3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,9 +109,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e9a1892803b02f53e25bea3e414ddd0501f12d97456c9d5ade4edf88f9516f" +checksum = "1752d7d62e2665da650a36d84abbf239f812534475d51f072a49a533513b7cdd" dependencies = [ "alloy-rlp", "arbitrary", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a016bfa21193744d4c38b3f3ab845462284d129e5e23c7cc0fafca7e92d9db37" +checksum = "3f63a6c9eb45684a5468536bc55379a2af0f45ffa5d756e4e4964532737e1836" dependencies = [ "alloy-eips", "alloy-primitives", @@ -134,7 +134,7 @@ dependencies = [ "arbitrary", "c-kzg", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "serde", ] @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d6d8118b83b0489cfb7e6435106948add2b35217f4a5004ef895f613f60299" +checksum = "aa4b0fc6a572ef2eebda0a31a5e393d451abda703fec917c75d9615d8c978cf2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -170,16 +170,16 @@ dependencies = [ "derive_more", "once_cell", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "serde", "sha2 0.10.8", ] [[package]] name = "alloy-genesis" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "894f33a7822abb018db56b10ab90398e63273ce1b5a33282afd186c132d764a6" +checksum = "48450f9c6f0821c1eee00ed912942492ed4f11dd69532825833de23ecc7a2256" dependencies = [ "alloy-primitives", "alloy-serde", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f0ae6e93b885cc70fe8dae449e7fd629751dbee8f59767eaaa7285333c5727" +checksum = "d484c2a934d0a4d86f8ad4db8113cb1d607707a6c54f6e78f4f1b4451b47aa70" dependencies = [ "alloy-primitives", "serde", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc122cbee2b8523854cc11d87bcd5773741602c553d2d2d106d82eeb9c16924a" +checksum = "7a20eba9bc551037f0626d6d29e191888638d979943fa4e842e9e6fc72bf0565" dependencies = [ "alloy-consensus", "alloy-eips", @@ -233,9 +233,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0e005ecc1b41f0b3bf90f68df5a446971e7eb34e1ea051da401e7e8eeef8fd" +checksum = "22e07c66b8b0ba8c87461a15fe3247c5b46fb500e103111b0ad4798738e45b1e" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -267,7 +267,7 @@ dependencies = [ "k256", "keccak-asm", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "rand 0.8.5", "ruint", "serde", @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d5af289798fe8783acd0c5f10644d9d26f54a12bc52a083e4f3b31718e9bf92" +checksum = "ad5d89acb7339fad13bc69e7b925232f242835bfd91c82fcb9326b36481bd0f0" dependencies = [ "alloy-chains", "alloy-consensus", @@ -312,9 +312,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702f330b7da123a71465ab9d39616292f8344a2811c28f2cc8d8438a69d79e35" +checksum = "034258dfaa51c278e1f7fcc46e587d10079ec9372866fa48c5df9d908fc1f6b1" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" +checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -342,20 +342,20 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8037e03c7f462a063f28daec9fda285a9a89da003c552f8637a80b9c8fd96241" +checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] name = "alloy-rpc-client" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40fcb53b2a9d0a78a4968b2eca8805a4b7011b9ee3fdfa2acaf137c5128f36b" +checksum = "479ce003e8c74bbbc7d4235131c1d6b7eaf14a533ae850295b90d240340989cb" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f2fbe956a3e0f0975c798f488dc6be96b669544df3737e18f4a325b42f4c86" +checksum = "0dfa1dd3e0bc3a3d89744fba8d1511216e83257160da2cd028a18b7d9c026030" dependencies = [ "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "334a8c00cde17a48e073031f1534e71a75b529dbf25552178c43c2337632e0ab" +checksum = "bae99de76a362c4311f0892e286eb752cf2a3a6ef6555dff6d93f51de2c24648" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -401,9 +401,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87f724e6170f558b809a520e37bdb34d99123092b78118bff31fb5b21dc2a2e" +checksum = "f67aec11f9f3bc5e96c2b7f342dba6e9541a8a48d2cfbe27b6b195136aa18eee" dependencies = [ "alloy-primitives", "alloy-serde", @@ -412,9 +412,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb383cd3981cee0031aeacbd394c4e726e907f3a0180fe36d5fc76d37c41cd82" +checksum = "dd2c363d49f460538899aaeb3325918f55fa01841fd7f3f11f58d438343ea083" dependencies = [ "alloy-eips", "alloy-primitives", @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd473d98ec552f8229cd6d566bd2b0bbfc5bb4efcefbb5288c834aa8fd832020" +checksum = "cc40df2dda7561d1406d0bee1d19c8787483a2cf2ee8011c05909475e7bc102d" dependencies = [ "alloy-consensus", "alloy-eips", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "083f443a83b9313373817236a8f4bea09cca862618e9177d822aee579640a5d6" +checksum = "13bd7aa9ff9e67f1ba7ee0dd8cebfc95831d1649b0e4eeefae940dc3681079fa" dependencies = [ "alloy-consensus", "alloy-eips", @@ -459,7 +459,7 @@ dependencies = [ "itertools 0.13.0", "jsonrpsee-types", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "serde", "serde_json", "thiserror", @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7a838f9a34aae7022c6cb53ecf21bc0a5a30c82f8d9eb0afed701ab5fd88de" +checksum = "535d26db98ac320a0d1637faf3e210328c3df3b1998abd7e72343d3857058efe" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -481,9 +481,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1572267dbc660843d87c02994029d1654c2c32867e186b266d1c03644b43af97" +checksum = "5971c92989c6a5588d3f6d1e99e5328fba6e68694efbe969d6ec96ae5b9d1037" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -493,23 +493,23 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d94da1c0c4e27cc344b05626fe22a89dc6b8b531b9475f3b7691dbf6913e4109" +checksum = "8913f9e825068d77c516188c221c44f78fd814fce8effe550a783295a2757d19" dependencies = [ "alloy-primitives", "arbitrary", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "serde", "serde_json", ] [[package]] name = "alloy-signer" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58d876be3afd8b78979540084ff63995292a26aa527ad0d44276405780aa0ffd" +checksum = "f740e13eb4c6a0e4d0e49738f1e86f31ad2d7ef93be499539f492805000f7237" dependencies = [ "alloy-primitives", "async-trait", @@ -521,9 +521,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40a37dc216c269b8a7244047cb1c18a9c69f7a0332ab2c4c2aa4cbb1a31468b" +checksum = "87db68d926887393a1d0f9c43833b44446ea29d603291e7b20e5d115f31aa4e3" dependencies = [ "alloy-consensus", "alloy-network", @@ -548,7 +548,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -565,7 +565,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "syn-solidity", "tiny-keccak", ] @@ -583,7 +583,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.67", + "syn 2.0.68", "syn-solidity", ] @@ -611,9 +611,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245af9541f0a0dbd5258669c80dfe3af118164cacec978a520041fc130550deb" +checksum = "dd9773e4ec6832346171605c776315544bd06e40f803e7b5b7824b325d5442ca" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -629,9 +629,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5619c017e1fdaa1db87f9182f4f0ed97c53d674957f4902fba655e972d359c6c" +checksum = "ff8ef947b901c0d4e97370f9fa25844cf8b63b1a58fd4011ee82342dc8a9fc6b" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -644,9 +644,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173cefa110afac7a53cf2e75519327761f2344d305eea2993f3af1b2c1fc1c44" +checksum = "bb40ee66887a66d875a5bb5e01cee4c9a467c263ef28c865cd4b0ebf15f705af" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -663,9 +663,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0aff8af5be5e58856c5cdd1e46db2c67c7ecd3a652d9100b4822c96c899947" +checksum = "3d92049d6642a18c9849ce7659430151e7c92b51552a0cabdc038c1af4cd7308" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -693,7 +693,7 @@ dependencies = [ "hashbrown 0.14.5", "nybbles", "proptest", - "proptest-derive", + "proptest-derive 0.4.0", "serde", "smallvec", "tracing", @@ -786,7 +786,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1006,7 +1006,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1017,7 +1017,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1055,7 +1055,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1064,51 +1064,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.29", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "backon" version = "0.4.4" @@ -1208,7 +1163,7 @@ version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cexpr", "clang-sys", "itertools 0.12.1", @@ -1221,7 +1176,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.67", + "syn 2.0.68", "which", ] @@ -1254,9 +1209,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "arbitrary", "serde", @@ -1329,7 +1284,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b6fb81ca0f301f33aff7401e2ffab37dc9e0e4a1cf0ccf6b34f4d9e60aa0682" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "boa_interner", "boa_macros", "indexmap 2.2.6", @@ -1344,7 +1299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "600e4e4a65b26efcef08a7b1cf2899d3845a32e82e067ee3b75eaf7e413ff31c" dependencies = [ "arrayvec", - "bitflags 2.5.0", + "bitflags 2.6.0", "boa_ast", "boa_gc", "boa_interner", @@ -1418,7 +1373,7 @@ checksum = "6be9c93793b60dac381af475b98634d4b451e28336e72218cad9a20176218dbc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "synstructure", ] @@ -1428,7 +1383,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8592556849f0619ed142ce2b3a19086769314a8d657f93a5765d06dbce4818" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "boa_ast", "boa_interner", "boa_macros", @@ -1527,7 +1482,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1614,9 +1569,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" dependencies = [ "jobserver", "libc", @@ -1718,9 +1673,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" dependencies = [ "clap_builder", "clap_derive", @@ -1728,9 +1683,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.7" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" dependencies = [ "anstream", "anstyle", @@ -1740,14 +1695,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.5" +version = "4.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -1910,10 +1865,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "const-str" -version = "0.5.7" +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3618cccc083bb987a415d85c02ca6c9994ea5b44731ec28b9ecf09658655fba9" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] [[package]] name = "convert_case" @@ -2075,7 +2045,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "crossterm_winapi", "libc", "mio", @@ -2218,7 +2188,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2242,7 +2212,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2253,7 +2223,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2359,7 +2329,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2372,7 +2342,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2486,7 +2456,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2579,9 +2549,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -2643,7 +2613,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2654,7 +2624,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -2755,6 +2725,7 @@ dependencies = [ "reth-discv4", "reth-network", "reth-network-api", + "reth-network-peers", "reth-primitives", "reth-tracing", "secp256k1", @@ -2808,6 +2779,7 @@ dependencies = [ "eyre", "reth", "reth-chainspec", + "reth-evm-ethereum", "reth-node-api", "reth-node-core", "reth-node-ethereum", @@ -2855,6 +2827,26 @@ dependencies = [ "tracing", ] +[[package]] +name = "example-custom-rlpx-subprotocol" +version = "0.0.0" +dependencies = [ + "eyre", + "futures", + "rand 0.8.5", + "reth", + "reth-eth-wire", + "reth-network", + "reth-network-api", + "reth-node-ethereum", + "reth-primitives", + "reth-provider", + "reth-rpc-types", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "example-db-access" version = "0.0.0" @@ -2868,76 +2860,83 @@ dependencies = [ ] [[package]] -name = "example-exex-in-memory-state" +name = "example-exex-discv5" version = "0.0.0" dependencies = [ + "clap", + "discv5", + "enr", "eyre", + "futures", + "futures-util", "reth", - "reth-execution-types", + "reth-chainspec", + "reth-discv5", "reth-exex", "reth-exex-test-utils", + "reth-network-peers", "reth-node-api", "reth-node-ethereum", "reth-testing-utils", "reth-tracing", + "serde_json", "tokio", + "tokio-stream", + "tracing", ] [[package]] -name = "example-exex-minimal" +name = "example-exex-in-memory-state" version = "0.0.0" dependencies = [ "eyre", - "futures", "reth", "reth-execution-types", "reth-exex", "reth-exex-test-utils", "reth-node-api", "reth-node-ethereum", + "reth-testing-utils", "reth-tracing", "tokio", ] [[package]] -name = "example-exex-op-bridge" +name = "example-exex-minimal" version = "0.0.0" dependencies = [ - "alloy-sol-types", "eyre", "futures", - "rand 0.8.5", "reth", "reth-execution-types", "reth-exex", "reth-exex-test-utils", "reth-node-api", "reth-node-ethereum", - "reth-primitives", - "reth-testing-utils", "reth-tracing", - "rusqlite", - "tempfile", "tokio", ] [[package]] -name = "example-exex-remote" +name = "example-exex-op-bridge" version = "0.0.0" dependencies = [ - "bincode", + "alloy-sol-types", "eyre", - "prost", + "futures", + "rand 0.8.5", "reth", + "reth-execution-types", "reth-exex", "reth-exex-test-utils", "reth-node-api", "reth-node-ethereum", + "reth-primitives", + "reth-testing-utils", "reth-tracing", + "rusqlite", + "tempfile", "tokio", - "tokio-stream", - "tonic", - "tonic-build", ] [[package]] @@ -3193,12 +3192,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.30" @@ -3324,7 +3317,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -3487,25 +3480,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.5" @@ -3706,17 +3680,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.0" @@ -3736,7 +3699,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "pin-project-lite", ] @@ -3800,30 +3763,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hyper" -version = "0.14.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.7", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.3.1" @@ -3833,9 +3772,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2", "http 1.1.0", - "http-body 1.0.0", + "http-body", "httparse", "httpdate", "itoa", @@ -3853,7 +3792,7 @@ checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.3.1", + "hyper", "hyper-util", "log", "rustls", @@ -3865,18 +3804,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.29", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "hyper-util" version = "0.1.5" @@ -3887,8 +3814,8 @@ dependencies = [ "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http-body", + "hyper", "pin-project-lite", "socket2 0.5.7", "tokio", @@ -3920,7 +3847,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -4026,9 +3953,9 @@ checksum = "e3744fecc0df9ce19999cdaf1f9f3a48c253431ce1d67ef499128fe9d0b607ab" [[package]] name = "icu_properties" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8173ba888885d250016e957b8ebfd5a65cdb690123d8833a19f6833f9c2b579" +checksum = "db9e559598096627aeca8cdfb98138a70eb4078025f8d1d5f2416a361241f756" dependencies = [ "displaydoc", "icu_collections", @@ -4070,7 +3997,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -4369,9 +4296,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a130d27083a4001b7b2d72a19f08786299550f76c9bd5307498dce2c2b20fa" +checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4387,9 +4314,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039db9fe25cd63b7221c3f8788c1ef4ea07987d40ec25a1e7d7a3c3e3e3fd130" +checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" dependencies = [ "base64 0.22.1", "futures-channel", @@ -4412,9 +4339,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21545a9445fbd582840ff5160a9a3e12b8e6da582151cdb07bde9a1970ba3a24" +checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" dependencies = [ "anyhow", "async-trait", @@ -4423,7 +4350,7 @@ dependencies = [ "futures-timer", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", "jsonrpsee-types", "parking_lot 0.12.3", @@ -4441,14 +4368,14 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb25cab482c8512c4f3323a5c90b95a3b8f7c90681a87bf7a68b942d52f08933" +checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.0", - "hyper 1.3.1", + "http-body", + "hyper", "hyper-rustls", "hyper-util", "jsonrpsee-core", @@ -4466,29 +4393,29 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c18184cd09b386feb18085609e8bf77bdc942482bdd82777b433b8d015edf561" +checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" dependencies = [ "heck 0.5.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] name = "jsonrpsee-server" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "810f63eff0f78fa8d413d678c0e55b702e2ea61d4587774c0db4ea2fc554ef92" +checksum = "654afab2e92e5d88ebd8a39d6074483f3f2bfdf91c5ac57fe285e7127cdd4f51" dependencies = [ "anyhow", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", - "hyper 1.3.1", + "hyper", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -4507,9 +4434,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f511b714bca46f9a3e97c0e0eb21d2c112e83e444d2db535b5ec7093f5836d73" +checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" dependencies = [ "beef", "http 1.1.0", @@ -4520,9 +4447,9 @@ dependencies = [ [[package]] name = "jsonrpsee-wasm-client" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c8a6dfa0c35c8549fa8e003ce0bbcf37b051ab7ef85fce587e8f0ed7881c84d" +checksum = "4727ac037f834c6f04c0912cada7532dbddb54e92fbc64e33d6cb8c24af313c9" dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", @@ -4531,9 +4458,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786c100eb67df2f2d863d231c2c6978bcf80ff4bf606ffc40e7e68ef562da7bf" +checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" dependencies = [ "http 1.1.0", "jsonrpsee-client-transport", @@ -4590,6 +4517,21 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "konst" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330f0e13e6483b8c34885f7e6c9f19b1a7bd449c673fbb948a51c99d66ef74f4" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + [[package]] name = "lazy_static" version = "1.5.0" @@ -4613,9 +4555,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets 0.52.5", @@ -4761,7 +4703,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -4863,9 +4805,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" @@ -4915,12 +4857,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "memchr" version = "2.7.4" @@ -4957,9 +4893,9 @@ dependencies = [ [[package]] name = "metrics-exporter-prometheus" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26eb45aff37b45cff885538e1dcbd6c2b462c04fe84ce0155ea469f325672c98" +checksum = "bf0af7a0d7ced10c0151f870e5e3f3f8bc9ffc5992d32873566ca1f9169ae776" dependencies = [ "base64 0.22.1", "indexmap 2.2.6", @@ -5005,9 +4941,9 @@ dependencies = [ [[package]] name = "mev-share-sse" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cbf228751922258c86a8492b39f987bb22338bef0b09426c106853be0c9fc7" +checksum = "e00cdd87dab765e7dac55c21eb680bfd10655b6c2530f6fe578acdfbb66c757c" dependencies = [ "alloy-primitives", "async-sse", @@ -5031,9 +4967,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -5090,7 +5026,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -5160,12 +5096,6 @@ dependencies = [ "unsigned-varint 0.7.2", ] -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "multistream-select" version = "0.13.0" @@ -5245,9 +5175,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -5348,7 +5278,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -5376,9 +5306,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -5415,9 +5345,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "4.2.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +checksum = "19ff2cf528c6c03d9ed653d6c4ce1dc0582dc4af309790ad92f07c1cd551b0be" dependencies = [ "num-traits", ] @@ -5574,16 +5504,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - [[package]] name = "ph" version = "0.8.3" @@ -5637,7 +5557,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -5666,7 +5586,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -5825,7 +5745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -5898,7 +5818,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "chrono", "flate2", "hex", @@ -5913,7 +5833,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "chrono", "hex", ] @@ -5926,7 +5846,7 @@ checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.5.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand 0.8.5", @@ -5960,56 +5880,14 @@ dependencies = [ ] [[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools 0.12.1", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.67", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" +name = "proptest-derive" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" dependencies = [ - "anyhow", - "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.67", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost", + "syn 2.0.68", ] [[package]] @@ -6205,19 +6083,20 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.26.3" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef" +checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cassowary", "compact_str", "crossterm", - "itertools 0.12.1", + "itertools 0.13.0", "lru", "paste", "stability", "strum", + "strum_macros", "unicode-segmentation", "unicode-truncate", "unicode-width", @@ -6229,7 +6108,7 @@ version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -6273,7 +6152,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -6352,9 +6231,9 @@ dependencies = [ "futures-core", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", - "hyper 1.3.1", + "hyper", "hyper-rustls", "hyper-util", "ipnet", @@ -6372,7 +6251,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-util", @@ -6401,12 +6280,12 @@ name = "reth" version = "1.0.0" dependencies = [ "ahash", + "alloy-chains", "alloy-rlp", "aquamarine", "arbitrary", "assert_matches", "backon", - "boyer-moore-magiclen", "clap", "comfy-table", "confy", @@ -6439,6 +6318,7 @@ dependencies = [ "reth-discv4", "reth-discv5", "reth-downloaders", + "reth-engine-util", "reth-errors", "reth-ethereum-payload-builder", "reth-evm", @@ -6456,30 +6336,38 @@ dependencies = [ "reth-node-ethereum", "reth-node-events", "reth-node-optimism", + "reth-node-taiko", "reth-optimism-primitives", "reth-payload-builder", "reth-payload-primitives", "reth-payload-validator", "reth-primitives", "reth-provider", + "reth-prune", "reth-prune-types", "reth-revm", "reth-rpc", "reth-rpc-api", "reth-rpc-builder", + "reth-rpc-eth-types", + "reth-rpc-server-types", "reth-rpc-types", "reth-rpc-types-compat", "reth-stages", "reth-static-file", "reth-static-file-types", + "reth-taiko-payload-builder", "reth-tasks", "reth-tracing", "reth-transaction-pool", "reth-trie", + "rlp", + "secp256k1", "serde", "serde_json", "similar-asserts", "tempfile", + "thiserror", "tikv-jemallocator", "tokio", "toml", @@ -6690,9 +6578,22 @@ dependencies = [ "reth-primitives-traits", "reth-rpc-types", "reth-trie-common", + "serde", "serde_json", ] +[[package]] +name = "reth-cli" +version = "1.0.0" +dependencies = [ + "clap", + "reth-cli-runner", +] + +[[package]] +name = "reth-cli-commands" +version = "1.0.0" + [[package]] name = "reth-cli-runner" version = "1.0.0" @@ -6715,7 +6616,7 @@ dependencies = [ "modular-bitfield", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "reth-codecs-derive", "serde", "serde_json", @@ -6730,7 +6631,7 @@ dependencies = [ "proc-macro2", "quote", "similar-asserts", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -6739,8 +6640,9 @@ version = "1.0.0" dependencies = [ "confy", "humantime-serde", - "reth-network", + "reth-network-types", "reth-prune-types", + "reth-stages-types", "serde", "tempfile", "toml", @@ -6845,7 +6747,7 @@ dependencies = [ "pprof", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "reth-codecs", "reth-primitives", @@ -6864,6 +6766,7 @@ name = "reth-db-common" version = "1.0.0" dependencies = [ "alloy-genesis", + "boyer-moore-magiclen", "eyre", "reth-chainspec", "reth-codecs", @@ -6871,6 +6774,7 @@ dependencies = [ "reth-db", "reth-db-api", "reth-etl", + "reth-fs-util", "reth-primitives", "reth-primitives-traits", "reth-provider", @@ -7013,6 +6917,7 @@ dependencies = [ "reth", "reth-chainspec", "reth-db", + "reth-network-peers", "reth-node-builder", "reth-payload-builder", "reth-primitives", @@ -7067,6 +6972,68 @@ dependencies = [ "serde", ] +[[package]] +name = "reth-engine-tree" +version = "1.0.0" +dependencies = [ + "aquamarine", + "assert_matches", + "futures", + "metrics", + "parking_lot 0.12.3", + "reth-beacon-consensus", + "reth-blockchain-tree", + "reth-blockchain-tree-api", + "reth-chainspec", + "reth-consensus", + "reth-db", + "reth-db-api", + "reth-engine-primitives", + "reth-errors", + "reth-ethereum-consensus", + "reth-evm", + "reth-metrics", + "reth-network-p2p", + "reth-payload-builder", + "reth-payload-primitives", + "reth-payload-validator", + "reth-primitives", + "reth-provider", + "reth-prune", + "reth-prune-types", + "reth-revm", + "reth-rpc-types", + "reth-stages", + "reth-stages-api", + "reth-static-file", + "reth-tasks", + "reth-tokio-util", + "reth-tracing", + "reth-trie", + "revm", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "reth-engine-util" +version = "1.0.0" +dependencies = [ + "eyre", + "futures", + "pin-project", + "reth-beacon-consensus", + "reth-engine-primitives", + "reth-fs-util", + "reth-rpc", + "reth-rpc-types", + "serde", + "serde_json", + "tokio-util", + "tracing", +] + [[package]] name = "reth-errors" version = "1.0.0" @@ -7092,7 +7059,7 @@ dependencies = [ "pin-project", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "reth-chainspec", "reth-codecs", @@ -7125,7 +7092,7 @@ dependencies = [ "derive_more", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "reth-chainspec", "reth-codecs-derive", @@ -7152,6 +7119,7 @@ dependencies = [ "alloy-rlp", "reth-chainspec", "reth-engine-primitives", + "reth-evm-ethereum", "reth-payload-primitives", "reth-primitives", "reth-rpc-types", @@ -7170,9 +7138,13 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "arbitrary", + "auto_impl", "crc", + "dyn-clone", + "once_cell", "proptest", - "proptest-derive", + "proptest-derive 0.5.0", + "rustc-hash 2.0.0", "serde", "thiserror-no-std", ] @@ -7230,6 +7202,7 @@ dependencies = [ "alloy-sol-types", "reth-chainspec", "reth-ethereum-consensus", + "reth-ethereum-forks", "reth-evm", "reth-execution-types", "reth-primitives", @@ -7247,6 +7220,7 @@ version = "1.0.0" dependencies = [ "reth-chainspec", "reth-consensus-common", + "reth-ethereum-forks", "reth-evm", "reth-execution-errors", "reth-execution-types", @@ -7293,7 +7267,13 @@ version = "1.0.0" dependencies = [ "eyre", "metrics", + "reth-blockchain-tree", + "reth-chainspec", "reth-config", + "reth-db-api", + "reth-db-common", + "reth-evm", + "reth-evm-ethereum", "reth-exex-types", "reth-metrics", "reth-network", @@ -7302,8 +7282,13 @@ dependencies = [ "reth-payload-builder", "reth-primitives", "reth-provider", + "reth-prune-types", + "reth-revm", + "reth-stages-api", "reth-tasks", + "reth-testing-utils", "reth-tracing", + "secp256k1", "serde", "tokio", "tokio-util", @@ -7380,7 +7365,7 @@ dependencies = [ name = "reth-libmdbx" version = "1.0.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "byteorder", "criterion", "dashmap", @@ -7425,7 +7410,7 @@ dependencies = [ "quote", "regex", "serial_test", - "syn 2.0.67", + "syn 2.0.68", "trybuild", ] @@ -7482,6 +7467,7 @@ dependencies = [ "reth-network-api", "reth-network-p2p", "reth-network-peers", + "reth-network-types", "reth-primitives", "reth-provider", "reth-tasks", @@ -7551,6 +7537,19 @@ dependencies = [ "url", ] +[[package]] +name = "reth-network-types" +version = "1.0.0" +dependencies = [ + "humantime-serde", + "reth-net-banlist", + "reth-network-api", + "reth-network-peers", + "serde", + "serde_json", + "tracing", +] + [[package]] name = "reth-nippy-jar" version = "1.0.0" @@ -7594,7 +7593,6 @@ dependencies = [ "aquamarine", "backon", "confy", - "discv5", "eyre", "fdlimit", "futures", @@ -7610,6 +7608,7 @@ dependencies = [ "reth-db-api", "reth-db-common", "reth-downloaders", + "reth-engine-util", "reth-evm", "reth-exex", "reth-network", @@ -7644,7 +7643,7 @@ dependencies = [ "alloy-genesis", "alloy-rpc-types-engine", "clap", - "const-str", + "const_format", "derive_more", "dirs-next", "eyre", @@ -7657,11 +7656,9 @@ dependencies = [ "metrics-process", "metrics-util", "once_cell", - "pin-project", "procfs", "proptest", "rand 0.8.5", - "reth-beacon-consensus", "reth-chainspec", "reth-config", "reth-consensus-common", @@ -7669,18 +7666,19 @@ dependencies = [ "reth-db-api", "reth-discv4", "reth-discv5", - "reth-engine-primitives", "reth-fs-util", "reth-metrics", "reth-net-nat", "reth-network", "reth-network-p2p", "reth-network-peers", + "reth-payload-builder", "reth-primitives", "reth-provider", "reth-prune-types", - "reth-rpc", "reth-rpc-api", + "reth-rpc-eth-api", + "reth-rpc-eth-types", "reth-rpc-server-types", "reth-rpc-types", "reth-rpc-types-compat", @@ -7690,13 +7688,11 @@ dependencies = [ "reth-tracing", "reth-transaction-pool", "secp256k1", - "serde", "serde_json", "shellexpand", "thiserror", "tikv-jemalloc-ctl", "tokio", - "tokio-util", "tower", "tracing", "vergen", @@ -7766,6 +7762,7 @@ dependencies = [ "clap", "eyre", "jsonrpsee", + "jsonrpsee-types", "parking_lot 0.12.3", "reqwest", "reth", @@ -7789,6 +7786,8 @@ dependencies = [ "reth-provider", "reth-revm", "reth-rpc", + "reth-rpc-eth-api", + "reth-rpc-eth-types", "reth-rpc-types", "reth-rpc-types-compat", "reth-tracing", @@ -7801,6 +7800,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-node-taiko" +version = "1.0.0" +dependencies = [ + "eyre", + "reth-basic-payload-builder", + "reth-db", + "reth-network", + "reth-node-api", + "reth-node-builder", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-rpc-types", + "reth-taiko-payload-builder", + "reth-tracing", + "reth-transaction-pool", + "serde", +] + +[[package]] +name = "reth-optimism-cli" +version = "1.0.0" + [[package]] name = "reth-optimism-consensus" version = "1.0.0" @@ -7844,6 +7867,7 @@ version = "1.0.0" name = "reth-payload-builder" version = "1.0.0" dependencies = [ + "alloy-rlp", "futures-util", "metrics", "reth-errors", @@ -7855,7 +7879,10 @@ dependencies = [ "reth-rpc-types", "reth-transaction-pool", "revm", + "revm-primitives", + "serde", "serde_json", + "sha2 0.10.8", "thiserror", "tokio", "tokio-stream", @@ -7881,6 +7908,7 @@ name = "reth-payload-validator" version = "1.0.0" dependencies = [ "reth-chainspec", + "reth-payload-builder", "reth-primitives", "reth-rpc-types", "reth-rpc-types-compat", @@ -7902,13 +7930,14 @@ dependencies = [ "c-kzg", "criterion", "derive_more", + "itertools 0.13.0", "modular-bitfield", "nybbles", "once_cell", "pprof", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "rayon", "reth-chainspec", @@ -7947,7 +7976,7 @@ dependencies = [ "modular-bitfield", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "reth-codecs", "revm-primitives", @@ -7993,6 +8022,7 @@ dependencies = [ "reth-testing-utils", "reth-trie", "revm", + "serde_json", "strum", "tempfile", "tokio", @@ -8040,7 +8070,7 @@ dependencies = [ "modular-bitfield", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "reth-codecs", "serde", "serde_json", @@ -8075,18 +8105,15 @@ dependencies = [ "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-sol-types", "assert_matches", "async-trait", - "derive_more", - "dyn-clone", "futures", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http-body", + "hyper", "jsonrpsee", + "jsonrpsee-types", "jsonwebtoken", - "metrics", "parking_lot 0.12.3", "pin-project", "rand 0.8.5", @@ -8096,8 +8123,6 @@ dependencies = [ "reth-evm", "reth-evm-ethereum", "reth-evm-optimism", - "reth-execution-types", - "reth-metrics", "reth-network-api", "reth-network-peers", "reth-primitives", @@ -8105,6 +8130,8 @@ dependencies = [ "reth-revm", "reth-rpc-api", "reth-rpc-engine-api", + "reth-rpc-eth-api", + "reth-rpc-eth-types", "reth-rpc-server-types", "reth-rpc-types", "reth-rpc-types-compat", @@ -8114,7 +8141,6 @@ dependencies = [ "revm", "revm-inspectors", "revm-primitives", - "schnellru", "secp256k1", "serde", "serde_json", @@ -8136,6 +8162,7 @@ dependencies = [ "reth-engine-primitives", "reth-network-peers", "reth-primitives", + "reth-rpc-eth-api", "reth-rpc-types", "serde", "serde_json", @@ -8149,6 +8176,7 @@ dependencies = [ "jsonrpsee", "reth-primitives", "reth-rpc-api", + "reth-rpc-eth-api", "reth-rpc-types", "serde_json", "similar-asserts", @@ -8173,6 +8201,7 @@ dependencies = [ "reth-ipc", "reth-metrics", "reth-network-api", + "reth-network-peers", "reth-node-core", "reth-payload-builder", "reth-primitives", @@ -8180,6 +8209,7 @@ dependencies = [ "reth-rpc", "reth-rpc-api", "reth-rpc-engine-api", + "reth-rpc-eth-types", "reth-rpc-layer", "reth-rpc-server-types", "reth-rpc-types", @@ -8230,6 +8260,74 @@ dependencies = [ "tracing", ] +[[package]] +name = "reth-rpc-eth-api" +version = "1.0.0" +dependencies = [ + "alloy-dyn-abi", + "async-trait", + "auto_impl", + "dyn-clone", + "futures", + "jsonrpsee", + "parking_lot 0.12.3", + "reth-chainspec", + "reth-errors", + "reth-evm", + "reth-execution-types", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-eth-types", + "reth-rpc-server-types", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-tasks", + "reth-transaction-pool", + "revm", + "revm-inspectors", + "revm-primitives", + "tokio", + "tracing", +] + +[[package]] +name = "reth-rpc-eth-types" +version = "1.0.0" +dependencies = [ + "alloy-sol-types", + "derive_more", + "futures", + "jsonrpsee-core", + "jsonrpsee-types", + "metrics", + "rand 0.8.5", + "reth-chainspec", + "reth-errors", + "reth-evm", + "reth-execution-types", + "reth-metrics", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-rpc-server-types", + "reth-rpc-types", + "reth-rpc-types-compat", + "reth-tasks", + "reth-transaction-pool", + "reth-trie", + "revm", + "revm-inspectors", + "revm-primitives", + "schnellru", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + [[package]] name = "reth-rpc-layer" version = "1.0.0" @@ -8252,6 +8350,12 @@ name = "reth-rpc-server-types" version = "1.0.0" dependencies = [ "alloy-primitives", + "jsonrpsee-core", + "jsonrpsee-types", + "reth-errors", + "reth-network-api", + "reth-primitives", + "reth-rpc-types", "serde", "strum", ] @@ -8273,7 +8377,7 @@ dependencies = [ "bytes", "jsonrpsee-types", "proptest", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "serde", "serde_json", @@ -8376,7 +8480,7 @@ dependencies = [ "modular-bitfield", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "rand 0.8.5", "reth-codecs", "reth-trie-common", @@ -8398,6 +8502,7 @@ dependencies = [ "reth-provider", "reth-prune-types", "reth-stages", + "reth-stages-types", "reth-static-file-types", "reth-storage-errors", "reth-testing-utils", @@ -8442,10 +8547,26 @@ dependencies = [ "thiserror-no-std", ] +[[package]] +name = "reth-taiko-payload-builder" +version = "1.0.0" +dependencies = [ + "reth-basic-payload-builder", + "reth-payload-builder", + "reth-primitives", + "reth-provider", + "reth-revm", + "reth-transaction-pool", + "revm", + "thiserror", + "tracing", +] + [[package]] name = "reth-tasks" version = "1.0.0" dependencies = [ + "auto_impl", "dyn-clone", "futures-util", "metrics", @@ -8499,7 +8620,7 @@ dependencies = [ "aquamarine", "assert_matches", "auto_impl", - "bitflags 2.5.0", + "bitflags 2.6.0", "criterion", "futures-util", "metrics", @@ -8583,7 +8704,7 @@ dependencies = [ "plain_hasher", "proptest", "proptest-arbitrary-interop", - "proptest-derive", + "proptest-derive 0.5.0", "reth-codecs", "reth-primitives-traits", "revm-primitives", @@ -8689,7 +8810,7 @@ checksum = "902184a7a781550858d4b96707098da357429f1e4545806fd5b589f455555cf2" dependencies = [ "alloy-primitives", "auto_impl", - "bitflags 2.5.0", + "bitflags 2.6.0", "bitvec", "c-kzg", "cfg-if", @@ -8714,9 +8835,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.37" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +checksum = "a7439be6844e40133eda024efd85bf07f59d0dd2f59b10c00dd6cfb92cc5c741" dependencies = [ "bytemuck", ] @@ -8832,7 +8953,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink 0.9.1", @@ -8888,7 +9009,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -8941,9 +9062,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "3e3beb939bcd33c269f4bf946cc829fcd336370267c4a927ac0399c84a3151a1" dependencies = [ "core-foundation", "core-foundation-sys", @@ -9108,7 +9229,7 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -9176,9 +9297,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -9191,14 +9312,14 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0" dependencies = [ "indexmap 2.2.6", "itoa", @@ -9240,9 +9361,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "079f3a42cd87588d924ed95b533f8d30a483388c4e400ab736a7058e34f16169" dependencies = [ "base64 0.22.1", "chrono", @@ -9258,14 +9379,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "bc03aad67c1d26b7de277d51c86892e7d9a0110a2fe44bf6b26cc569fba302d6" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9290,7 +9411,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9546,7 +9667,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a" dependencies = [ "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9575,9 +9696,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] @@ -9592,7 +9713,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9610,9 +9731,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sucds" @@ -9660,9 +9781,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.67" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -9678,15 +9799,9 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.1" @@ -9701,7 +9816,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9786,7 +9901,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9825,7 +9940,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -9963,9 +10078,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" dependencies = [ "tinyvec_macros", ] @@ -9995,16 +10110,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.3.0" @@ -10013,7 +10118,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -10115,46 +10220,6 @@ dependencies = [ "winnow 0.6.13", ] -[[package]] -name = "tonic" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.21.7", - "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.29", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 2.0.67", -] - [[package]] name = "tower" version = "0.4.13" @@ -10184,12 +10249,12 @@ checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "async-compression", "base64 0.21.7", - "bitflags 2.5.0", + "bitflags 2.6.0", "bytes", "futures-core", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body", "http-body-util", "http-range-header", "httpdate", @@ -10251,7 +10316,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -10518,6 +10583,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "universal-hash" version = "0.4.0" @@ -10584,9 +10655,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ "getrandom 0.2.15", ] @@ -10696,7 +10767,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -10730,7 +10801,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10871,7 +10942,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -10882,7 +10953,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -11140,7 +11211,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "synstructure", ] @@ -11161,7 +11232,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] @@ -11181,7 +11252,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", "synstructure", ] @@ -11202,14 +11273,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] name = "zerovec" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", @@ -11218,13 +11289,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.67", + "syn 2.0.68", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6724c5318889..d7f54d02b42b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ members = [ "crates/blockchain-tree/", "crates/blockchain-tree-api/", "crates/chainspec/", + "crates/cli/cli/", + "crates/cli/commands/", "crates/cli/runner/", "crates/config/", "crates/consensus/auto-seal/", @@ -23,7 +25,9 @@ members = [ "crates/consensus/debug-client/", "crates/ethereum-forks/", "crates/e2e-test-utils/", - "crates/engine-primitives/", + "crates/engine/primitives/", + "crates/engine/tree/", + "crates/engine/util/", "crates/errors/", "crates/ethereum-forks/", "crates/ethereum/consensus/", @@ -50,13 +54,16 @@ members = [ "crates/net/eth-wire/", "crates/net/nat/", "crates/net/network-api/", + "crates/net/network-types/", "crates/net/network/", "crates/net/p2p/", "crates/net/peers/", - "crates/node-core/", + "crates/node/core/", "crates/node/api/", "crates/node/builder/", "crates/node/events/", + "crates/node-taiko/", + "crates/optimism/cli", "crates/optimism/consensus", "crates/optimism/evm/", "crates/optimism/node/", @@ -64,7 +71,10 @@ members = [ "crates/optimism/primitives/", "crates/payload/basic/", "crates/payload/builder/", - "crates/payload/primitives/", + "crates/payload/primitives", + "crates/ethereum/payload", + "crates/optimism/payload", + "crates/payload/taiko/", "crates/payload/validator/", "crates/primitives/", "crates/primitives-traits/", @@ -75,8 +85,11 @@ members = [ "crates/rpc/rpc-api/", "crates/rpc/rpc-builder/", "crates/rpc/rpc-engine-api/", + "crates/rpc/rpc-eth-api/", + "crates/rpc/rpc-eth-types/", "crates/rpc/rpc-layer", "crates/rpc/rpc-testing-util/", + "crates/rpc/rpc-server-types/", "crates/rpc/rpc-types-compat/", "crates/rpc/rpc-types/", "crates/rpc/rpc/", @@ -123,6 +136,9 @@ members = [ "examples/polygon-p2p/", "examples/rpc-db/", "examples/txpool-tracing/", + "examples/custom-rlpx-subprotocol", + "examples/exex/minimal/", + "examples/exex/op-bridge/", "testing/ef-tests/", "testing/testing-utils", ] @@ -235,9 +251,13 @@ codegen-units = 16 # e.g. `cargo build --profile profiling` [profile.profiling] inherits = "release" -debug = 1 +debug = 2 strip = false +# Make sure debug symbols are in the bench profile +[profile.bench] +inherits = "profiling" + [profile.maxperf] inherits = "release" lto = "fat" @@ -253,6 +273,8 @@ reth-beacon-consensus = { path = "crates/consensus/beacon" } reth-blockchain-tree = { path = "crates/blockchain-tree" } reth-blockchain-tree-api = { path = "crates/blockchain-tree-api" } reth-chainspec = { path = "crates/chainspec" } +reth-cli = { path = "crates/cli/cli" } +reth-cli-commands = { path = "crates/cli/commands" } reth-cli-runner = { path = "crates/cli/runner" } reth-codecs = { path = "crates/storage/codecs" } reth-codecs-derive = { path = "crates/storage/codecs/derive" } @@ -269,7 +291,9 @@ reth-dns-discovery = { path = "crates/net/dns" } reth-downloaders = { path = "crates/net/downloaders" } reth-e2e-test-utils = { path = "crates/e2e-test-utils" } reth-ecies = { path = "crates/net/ecies" } -reth-engine-primitives = { path = "crates/engine-primitives" } +reth-engine-primitives = { path = "crates/engine/primitives" } +reth-engine-tree = { path = "crates/engine/tree" } +reth-engine-util = { path = "crates/engine/util" } reth-errors = { path = "crates/errors" } reth-eth-wire = { path = "crates/net/eth-wire" } reth-eth-wire-types = { path = "crates/net/eth-wire-types" } @@ -296,15 +320,18 @@ reth-net-banlist = { path = "crates/net/banlist" } reth-net-nat = { path = "crates/net/nat" } reth-network = { path = "crates/net/network" } reth-network-api = { path = "crates/net/network-api" } +reth-network-types = { path = "crates/net/network-types" } reth-network-peers = { path = "crates/net/peers", default-features = false } reth-network-p2p = { path = "crates/net/p2p" } reth-nippy-jar = { path = "crates/storage/nippy-jar" } reth-node-api = { path = "crates/node/api" } reth-node-builder = { path = "crates/node/builder" } -reth-node-core = { path = "crates/node-core" } +reth-node-core = { path = "crates/node/core" } reth-node-ethereum = { path = "crates/ethereum/node" } reth-node-events = { path = "crates/node/events" } reth-node-optimism = { path = "crates/optimism/node" } +reth-node-taiko = { path = "crates/node-taiko" } +reth-optimism-cli = { path = "crates/optimism/cli" } reth-optimism-consensus = { path = "crates/optimism/consensus" } reth-optimism-payload-builder = { path = "crates/optimism/payload" } reth-optimism-primitives = { path = "crates/optimism/primitives" } @@ -322,7 +349,9 @@ reth-rpc-api = { path = "crates/rpc/rpc-api" } reth-rpc-api-testing-util = { path = "crates/rpc/rpc-testing-util" } reth-rpc-builder = { path = "crates/rpc/rpc-builder" } reth-rpc-engine-api = { path = "crates/rpc/rpc-engine-api" } +reth-rpc-eth-api = { path = "crates/rpc/rpc-eth-api" } reth-rpc-layer = { path = "crates/rpc/rpc-layer" } +reth-rpc-eth-types = { path = "crates/rpc/rpc-eth-types" } reth-rpc-server-types = { path = "crates/rpc/rpc-server-types" } reth-rpc-types = { path = "crates/rpc/rpc-types" } reth-rpc-types-compat = { path = "crates/rpc/rpc-types-compat" } @@ -333,6 +362,7 @@ reth-static-file = { path = "crates/static-file/static-file" } reth-static-file-types = { path = "crates/static-file/types" } reth-storage-api = { path = "crates/storage/storage-api" } reth-storage-errors = { path = "crates/storage/errors" } +reth-taiko-payload-builder = { path = "crates/payload/taiko" } reth-tasks = { path = "crates/tasks" } reth-testing-utils = { path = "testing/testing-utils" } reth-tokio-util = { path = "crates/tokio-util" } @@ -397,6 +427,7 @@ aquamarine = "0.5" bytes = "1.5" bitflags = "2.4" clap = "4" +const_format = { version = "0.2.32", features = ["rust_1_64"] } dashmap = "5.5" derive_more = "0.99.17" fdlimit = "0.3.0" @@ -429,6 +460,7 @@ sha2 = { version = "0.10", default-features = false } paste = "1.0" url = "2.3" backon = "0.4" +boyer-moore-magiclen = "0.2.16" # metrics metrics = "0.23.0" @@ -495,7 +527,7 @@ tempfile = "3.8" criterion = "0.5" pprof = "0.13" proptest = "1.4" -proptest-derive = "0.4" +proptest-derive = "0.5" serial_test = "3" similar-asserts = "1.5.0" test-fuzz = "5" diff --git a/README.md b/README.md index bfb1c6c65f1b..ad98ba8529f3 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ | [Developer Docs](./docs) | [Crate Docs](https://reth.rs/docs) -_The project is still work in progress, see the [disclaimer below](#status)._ - [gh-ci]: https://github.com/paradigmxyz/reth/actions/workflows/unit.yml [gh-deny]: https://github.com/paradigmxyz/reth/actions/workflows/deny.yml [tg-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fparadigm%5Freth @@ -42,7 +40,7 @@ Reth is production ready, and suitable for usage in mission-critical environment More historical context below: * We released 1.0 "production-ready" stable Reth in June 2024. - * Reth completed an audit with [Sigma Prime](https://sigmaprime.io/), the developers of [Lighthouse](https://github.com/sigp/lighthouse), the Rust Consensus Layer implementation. Find it [here](./audit/sigma_prime_audit_v1.pdf). + * Reth completed an audit with [Sigma Prime](https://sigmaprime.io/), the developers of [Lighthouse](https://github.com/sigp/lighthouse), the Rust Consensus Layer implementation. Find it [here](./audit/sigma_prime_audit_v2.pdf). * Revm (the EVM used in Reth) underwent an audit with [Guido Vranken](https://twitter.com/guidovranken) (#1 [Ethereum Bug Bounty](https://ethereum.org/en/bug-bounty)). We will publish the results soon. * We released multiple iterative beta versions, up to [beta.9](https://github.com/paradigmxyz/reth/releases/tag/v0.2.0-beta.9) on Monday June 3rd 2024 the last beta release. * We released [beta](https://github.com/paradigmxyz/reth/releases/tag/v0.2.0-beta.1) on Monday March 4th 2024, our first breaking change to the database model, providing faster query speed, smaller database footprint, and allowing "history" to be mounted on separate drives. diff --git a/audit/sigma_prime_audit_v1.pdf b/audit/sigma_prime_audit_v2.pdf similarity index 51% rename from audit/sigma_prime_audit_v1.pdf rename to audit/sigma_prime_audit_v2.pdf index 4b31fb2b4448..50da37d23f46 100644 Binary files a/audit/sigma_prime_audit_v1.pdf and b/audit/sigma_prime_audit_v2.pdf differ diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 1440922ee225..80f08012764b 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -37,6 +37,8 @@ reth-rpc.workspace = true reth-rpc-types.workspace = true reth-rpc-types-compat.workspace = true reth-rpc-api = { workspace = true, features = ["client"] } +reth-rpc-eth-types.workspace = true +reth-rpc-server-types.workspace = true reth-network = { workspace = true, features = ["serde"] } reth-network-p2p.workspace = true reth-net-banlist.workspace = true @@ -45,6 +47,7 @@ reth-downloaders.workspace = true reth-tracing.workspace = true reth-tasks.workspace = true reth-ethereum-payload-builder.workspace = true +reth-taiko-payload-builder = { workspace = true, optional = true } reth-payload-builder.workspace = true reth-payload-primitives.workspace = true reth-payload-validator.workspace = true @@ -60,6 +63,7 @@ reth-node-ethereum.workspace = true reth-node-optimism = { workspace = true, optional = true, features = [ "optimism", ] } +reth-node-taiko = { workspace = true, optional = true } reth-node-core.workspace = true reth-db-common.workspace = true reth-node-builder.workspace = true @@ -67,9 +71,14 @@ reth-node-events.workspace = true reth-consensus.workspace = true reth-optimism-primitives.workspace = true reth-prune-types.workspace = true +reth-engine-util.workspace = true +reth-prune.workspace = true # crypto alloy-rlp.workspace = true +rlp = "0.5" +alloy-chains.workspace = true +secp256k1.workspace = true # tracing tracing.workspace = true @@ -91,9 +100,9 @@ proptest-arbitrary-interop.workspace = true rand.workspace = true # tui -comfy-table = "7.0" +comfy-table = "7.1" crossterm = "0.27.0" -ratatui = { version = "0.26", default-features = false, features = [ +ratatui = { version = "0.27", default-features = false, features = [ "crossterm", ] } human_bytes = "0.4.1" @@ -113,10 +122,10 @@ eyre.workspace = true clap = { workspace = true, features = ["derive", "env"] } tempfile.workspace = true backon.workspace = true +thiserror.workspace = true similar-asserts.workspace = true itertools.workspace = true rayon.workspace = true -boyer-moore-magiclen = "0.2.16" ahash = "0.8" # p2p @@ -152,6 +161,16 @@ optimism = [ "reth-blockchain-tree/optimism", "dep:reth-node-optimism", "reth-node-core/optimism", + "reth-rpc-eth-types/optimism", +] + +taiko = [ + "reth-primitives/taiko", + "reth-beacon-consensus/taiko", + "reth-payload-builder/taiko", + "reth-node-core/taiko", + "dep:reth-taiko-payload-builder", + "dep:reth-node-taiko", ] # no-op feature flag for switching between the `optimism` and default functionality in CI matrices @@ -165,3 +184,8 @@ path = "src/main.rs" name = "op-reth" path = "src/optimism.rs" required-features = ["optimism"] + +[[bin]] +name = "taiko-reth" +path = "src/taiko.rs" +required-features = ["taiko"] diff --git a/bin/reth/src/cli/mod.rs b/bin/reth/src/cli/mod.rs index ff5c4add541c..06b6ad34749e 100644 --- a/bin/reth/src/cli/mod.rs +++ b/bin/reth/src/cli/mod.rs @@ -8,7 +8,7 @@ use crate::{ commands::{ config_cmd, db, debug_cmd, dump_genesis, import, init_cmd, init_state, node::{self, NoArgs}, - p2p, recover, stage, test_vectors, + p2p, prune, recover, stage, t8n, test_vectors, }, version::{LONG_VERSION, SHORT_VERSION}, }; @@ -160,10 +160,12 @@ impl Cli { Commands::Db(command) => runner.run_blocking_until_ctrl_c(command.execute()), Commands::Stage(command) => runner.run_command_until_exit(|ctx| command.execute(ctx)), Commands::P2P(command) => runner.run_until_ctrl_c(command.execute()), + Commands::T8n(command) => runner.run_until_ctrl_c(command.execute()), Commands::TestVectors(command) => runner.run_until_ctrl_c(command.execute()), Commands::Config(command) => runner.run_until_ctrl_c(command.execute()), Commands::Debug(command) => runner.run_command_until_exit(|ctx| command.execute(ctx)), Commands::Recover(command) => runner.run_command_until_exit(|ctx| command.execute(ctx)), + Commands::Prune(command) => runner.run_until_ctrl_c(command.execute()), } } @@ -211,6 +213,12 @@ pub enum Commands { /// P2P Debugging utilities #[command(name = "p2p")] P2P(p2p::Command), + /// Runs an EVM state transition using the provided JSON pre-state files. + /// + /// Equivalent of Geth's `./evm t8n` utility, and should be used to confirm + /// equivalence of behavior between Geth and Reth executors. + #[command(name = "t8n")] + T8n(t8n::Command), /// Generate Test Vectors #[command(name = "test-vectors")] TestVectors(test_vectors::Command), @@ -223,6 +231,9 @@ pub enum Commands { /// Scripts for node recovery #[command(name = "recover")] Recover(recover::Command), + /// Prune according to the configuration without any limits + #[command(name = "prune")] + Prune(prune::PruneCommand), } #[cfg(test)] diff --git a/bin/reth/src/commands/common.rs b/bin/reth/src/commands/common.rs index 31c0329a5540..41758a9f09da 100644 --- a/bin/reth/src/commands/common.rs +++ b/bin/reth/src/commands/common.rs @@ -65,7 +65,11 @@ impl EnvironmentArgs { } let config_path = self.config.clone().unwrap_or_else(|| data_dir.config()); - let mut config: Config = confy::load_path(config_path).unwrap_or_default(); + let mut config: Config = confy::load_path(config_path) + .inspect_err( + |err| warn!(target: "reth::cli", %err, "Failed to load config file, using default"), + ) + .unwrap_or_default(); // Make sure ETL doesn't default to /tmp/, but to whatever datadir is set to if config.stages.etl.dir.is_none() { diff --git a/bin/reth/src/commands/db/checksum.rs b/bin/reth/src/commands/db/checksum.rs index 6aa6b69e6d3b..9af9a2321637 100644 --- a/bin/reth/src/commands/db/checksum.rs +++ b/bin/reth/src/commands/db/checksum.rs @@ -1,11 +1,9 @@ -use crate::{ - commands::db::get::{maybe_json_value_parser, table_key}, - utils::DbTool, -}; +use crate::commands::db::get::{maybe_json_value_parser, table_key}; use ahash::RandomState; use clap::Parser; use reth_db::{DatabaseEnv, RawKey, RawTable, RawValue, TableViewer, Tables}; use reth_db_api::{cursor::DbCursorRO, database::Database, table::Table, transaction::DbTx}; +use reth_db_common::DbTool; use std::{ hash::{BuildHasher, Hasher}, sync::Arc, diff --git a/bin/reth/src/commands/db/clear.rs b/bin/reth/src/commands/db/clear.rs index 76c1b97e38ad..b9edf458d3f4 100644 --- a/bin/reth/src/commands/db/clear.rs +++ b/bin/reth/src/commands/db/clear.rs @@ -5,8 +5,8 @@ use reth_db_api::{ table::Table, transaction::{DbTx, DbTxMut}, }; -use reth_primitives::{static_file::find_fixed_range, StaticFileSegment}; use reth_provider::{ProviderFactory, StaticFileProviderFactory}; +use reth_static_file_types::{find_fixed_range, StaticFileSegment}; /// The arguments for the `reth db clear` command #[derive(Parser, Debug)] diff --git a/bin/reth/src/commands/db/diff.rs b/bin/reth/src/commands/db/diff.rs index 246b107fa4a1..dd23dd032cb1 100644 --- a/bin/reth/src/commands/db/diff.rs +++ b/bin/reth/src/commands/db/diff.rs @@ -1,11 +1,11 @@ use crate::{ args::DatabaseArgs, dirs::{DataDirPath, PlatformPath}, - utils::DbTool, }; use clap::Parser; use reth_db::{open_db_read_only, tables_to_generic, DatabaseEnv, Tables}; use reth_db_api::{cursor::DbCursorRO, database::Database, table::Table, transaction::DbTx}; +use reth_db_common::DbTool; use std::{ collections::HashMap, fmt::Debug, @@ -298,12 +298,12 @@ where ) { // do not bother comparing if the key is already in the discrepancies map if self.discrepancies.contains_key(&key) { - return + return; } // do not bother comparing if the key is already in the extra elements map if self.extra_elements.contains_key(&key) { - return + return; } match (first, second) { diff --git a/bin/reth/src/commands/db/get.rs b/bin/reth/src/commands/db/get.rs index 699a31471802..cd721a1db4b1 100644 --- a/bin/reth/src/commands/db/get.rs +++ b/bin/reth/src/commands/db/get.rs @@ -1,4 +1,3 @@ -use crate::utils::DbTool; use clap::Parser; use reth_db::{ static_file::{ColumnSelectorOne, ColumnSelectorTwo, HeaderMask, ReceiptMask, TransactionMask}, @@ -8,8 +7,10 @@ use reth_db_api::{ database::Database, table::{Decompress, DupSort, Table}, }; -use reth_primitives::{BlockHash, Header, StaticFileSegment}; +use reth_db_common::DbTool; +use reth_primitives::{BlockHash, Header}; use reth_provider::StaticFileProviderFactory; +use reth_static_file_types::StaticFileSegment; use tracing::error; /// The arguments for the `reth db get` command diff --git a/bin/reth/src/commands/db/list.rs b/bin/reth/src/commands/db/list.rs index dd1a1846acbd..ed337bdcf81e 100644 --- a/bin/reth/src/commands/db/list.rs +++ b/bin/reth/src/commands/db/list.rs @@ -1,9 +1,9 @@ use super::tui::DbListTUI; -use crate::utils::{DbTool, ListFilter}; use clap::Parser; use eyre::WrapErr; use reth_db::{DatabaseEnv, RawValue, TableViewer, Tables}; use reth_db_api::{database::Database, table::Table}; +use reth_db_common::{DbTool, ListFilter}; use reth_primitives::hex; use std::{cell::RefCell, sync::Arc}; use tracing::error; diff --git a/bin/reth/src/commands/db/mod.rs b/bin/reth/src/commands/db/mod.rs index fcafcc41ac09..736d825c31b2 100644 --- a/bin/reth/src/commands/db/mod.rs +++ b/bin/reth/src/commands/db/mod.rs @@ -1,11 +1,9 @@ //! Database debugging tool -use crate::{ - commands::common::{AccessRights, Environment, EnvironmentArgs}, - utils::DbTool, -}; +use crate::commands::common::{AccessRights, Environment, EnvironmentArgs}; use clap::{Parser, Subcommand}; use reth_db::version::{get_db_version, DatabaseVersionError, DB_VERSION}; +use reth_db_common::DbTool; use std::io::{self, Write}; mod checksum; diff --git a/bin/reth/src/commands/db/stats.rs b/bin/reth/src/commands/db/stats.rs index 517b9c9e591f..b1a979e54918 100644 --- a/bin/reth/src/commands/db/stats.rs +++ b/bin/reth/src/commands/db/stats.rs @@ -1,4 +1,4 @@ -use crate::{commands::db::checksum::ChecksumViewer, utils::DbTool}; +use crate::commands::db::checksum::ChecksumViewer; use clap::Parser; use comfy_table::{Cell, Row, Table as ComfyTable}; use eyre::WrapErr; @@ -6,10 +6,11 @@ use human_bytes::human_bytes; use itertools::Itertools; use reth_db::{mdbx, static_file::iter_static_files, DatabaseEnv, TableViewer, Tables}; use reth_db_api::database::Database; +use reth_db_common::DbTool; use reth_fs_util as fs; use reth_node_core::dirs::{ChainPath, DataDirPath}; -use reth_primitives::static_file::{find_fixed_range, SegmentRangeInclusive}; use reth_provider::providers::StaticFileProvider; +use reth_static_file_types::{find_fixed_range, SegmentRangeInclusive}; use std::{sync::Arc, time::Duration}; #[derive(Parser, Debug)] diff --git a/bin/reth/src/commands/debug_cmd/execution.rs b/bin/reth/src/commands/debug_cmd/execution.rs index c1fd4cfa5fa2..2172a2b4c7ba 100644 --- a/bin/reth/src/commands/debug_cmd/execution.rs +++ b/bin/reth/src/commands/debug_cmd/execution.rs @@ -26,15 +26,14 @@ use reth_primitives::{BlockHashOrNumber, BlockNumber, B256}; use reth_provider::{ BlockExecutionWriter, ChainSpecProvider, ProviderFactory, StageCheckpointReader, }; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::{ - sets::DefaultStages, - stages::{ExecutionStage, ExecutionStageThresholds}, - Pipeline, StageId, StageSet, + sets::DefaultStages, stages::ExecutionStage, ExecutionStageThresholds, Pipeline, StageId, + StageSet, }; use reth_static_file::StaticFileProducer; use reth_tasks::TaskExecutor; -use std::{net::SocketAddr, path::PathBuf, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; use tokio::sync::watch; use tracing::*; @@ -130,11 +129,6 @@ impl Command { .network .network_config(config, provider_factory.chain_spec(), secret_key, default_peers_path) .with_task_executor(Box::new(task_executor)) - .listener_addr(SocketAddr::new(self.network.addr, self.network.port)) - .discovery_addr(SocketAddr::new( - self.network.discovery.addr, - self.network.discovery.port, - )) .build(provider_factory) .start_network() .await?; diff --git a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs index 8f78d6711073..8d138d2c2c1b 100644 --- a/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/commands/debug_cmd/in_memory_merkle.rs @@ -26,7 +26,7 @@ use reth_revm::database::StateProviderDatabase; use reth_stages::StageId; use reth_tasks::TaskExecutor; use reth_trie::{updates::TrieKey, StateRoot}; -use std::{net::SocketAddr, path::PathBuf, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; use tracing::*; /// `reth debug in-memory-merkle` command @@ -64,11 +64,6 @@ impl Command { .network .network_config(config, provider_factory.chain_spec(), secret_key, default_peers_path) .with_task_executor(Box::new(task_executor)) - .listener_addr(SocketAddr::new(self.network.addr, self.network.port)) - .discovery_addr(SocketAddr::new( - self.network.discovery.addr, - self.network.discovery.port, - )) .build(provider_factory) .start_network() .await?; @@ -201,7 +196,7 @@ impl Command { (Some(in_mem), Some(incr)) => { similar_asserts::assert_eq!(in_mem.0, incr.0, "Nibbles don't match"); if in_mem.1 != incr.1 && - matches!(in_mem.0, TrieKey::AccountNode(ref nibbles) if nibbles.0.len() > self.skip_node_depth.unwrap_or_default()) + matches!(in_mem.0, TrieKey::AccountNode(ref nibbles) if nibbles.len() > self.skip_node_depth.unwrap_or_default()) { in_mem_mismatched.push(in_mem); incremental_mismatched.push(incr); diff --git a/bin/reth/src/commands/debug_cmd/merkle.rs b/bin/reth/src/commands/debug_cmd/merkle.rs index 46e76d1da090..bd8f690b9a59 100644 --- a/bin/reth/src/commands/debug_cmd/merkle.rs +++ b/bin/reth/src/commands/debug_cmd/merkle.rs @@ -23,14 +23,14 @@ use reth_provider::{ BlockNumReader, BlockWriter, ChainSpecProvider, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, ProviderError, ProviderFactory, StateWriter, }; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_revm::database::StateProviderDatabase; use reth_stages::{ stages::{AccountHashingStage, MerkleStage, StorageHashingStage}, ExecInput, Stage, StageCheckpoint, }; use reth_tasks::TaskExecutor; -use std::{net::SocketAddr, path::PathBuf, sync::Arc}; +use std::{path::PathBuf, sync::Arc}; use tracing::*; /// `reth debug merkle` command @@ -69,11 +69,6 @@ impl Command { .network .network_config(config, provider_factory.chain_spec(), secret_key, default_peers_path) .with_task_executor(Box::new(task_executor)) - .listener_addr(SocketAddr::new(self.network.addr, self.network.port)) - .discovery_addr(SocketAddr::new( - self.network.discovery.addr, - self.network.discovery.port, - )) .build(provider_factory) .start_network() .await?; diff --git a/bin/reth/src/commands/debug_cmd/replay_engine.rs b/bin/reth/src/commands/debug_cmd/replay_engine.rs index 26c8a3558e73..224a0c993401 100644 --- a/bin/reth/src/commands/debug_cmd/replay_engine.rs +++ b/bin/reth/src/commands/debug_cmd/replay_engine.rs @@ -14,20 +14,20 @@ use reth_cli_runner::CliContext; use reth_config::Config; use reth_consensus::Consensus; use reth_db::DatabaseEnv; +use reth_engine_util::engine_store::{EngineMessageStore, StoredEngineApiMessage}; use reth_fs_util as fs; use reth_network::NetworkHandle; use reth_network_api::NetworkInfo; -use reth_node_core::engine::engine_store::{EngineMessageStore, StoredEngineApiMessage}; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_provider::{ providers::BlockchainProvider, CanonStateSubscriptions, ChainSpecProvider, ProviderFactory, }; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::Pipeline; use reth_static_file::StaticFileProducer; use reth_tasks::TaskExecutor; use reth_transaction_pool::noop::NoopTransactionPool; -use std::{net::SocketAddr, path::PathBuf, sync::Arc, time::Duration}; +use std::{path::PathBuf, sync::Arc, time::Duration}; use tokio::sync::oneshot; use tracing::*; @@ -65,11 +65,6 @@ impl Command { .network .network_config(config, provider_factory.chain_spec(), secret_key, default_peers_path) .with_task_executor(Box::new(task_executor)) - .listener_addr(SocketAddr::new(self.network.addr, self.network.port)) - .discovery_addr(SocketAddr::new( - self.network.discovery.addr, - self.network.discovery.port, - )) .build(provider_factory) .start_network() .await?; diff --git a/bin/reth/src/commands/import.rs b/bin/reth/src/commands/import.rs index 25d1864a2434..71357e083aaf 100644 --- a/bin/reth/src/commands/import.rs +++ b/bin/reth/src/commands/import.rs @@ -27,7 +27,7 @@ use reth_provider::{ BlockNumReader, ChainSpecProvider, HeaderProvider, ProviderError, ProviderFactory, StageCheckpointReader, }; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::{prelude::*, Pipeline, StageId, StageSet}; use reth_static_file::StaticFileProducer; use std::{path::PathBuf, sync::Arc}; diff --git a/bin/reth/src/commands/import_op.rs b/bin/reth/src/commands/import_op.rs index 646cd4f97232..f4b8716fe210 100644 --- a/bin/reth/src/commands/import_op.rs +++ b/bin/reth/src/commands/import_op.rs @@ -17,7 +17,7 @@ use reth_downloaders::file_client::{ }; use reth_optimism_primitives::bedrock_import::is_dup_tx; use reth_provider::StageCheckpointReader; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::StageId; use reth_static_file::StaticFileProducer; use std::{path::PathBuf, sync::Arc}; diff --git a/bin/reth/src/commands/import_receipts_op.rs b/bin/reth/src/commands/import_receipts_op.rs index d77332f86be2..7623c626cb02 100644 --- a/bin/reth/src/commands/import_receipts_op.rs +++ b/bin/reth/src/commands/import_receipts_op.rs @@ -13,12 +13,13 @@ use reth_downloaders::{ use reth_execution_types::ExecutionOutcome; use reth_node_core::version::SHORT_VERSION; use reth_optimism_primitives::bedrock_import::is_dup_tx; -use reth_primitives::{Receipts, StaticFileSegment}; +use reth_primitives::Receipts; use reth_provider::{ OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter, StaticFileProviderFactory, StaticFileWriter, StatsReader, }; use reth_stages::StageId; +use reth_static_file_types::StaticFileSegment; use std::path::{Path, PathBuf}; use tracing::{debug, error, info, trace}; diff --git a/bin/reth/src/commands/mod.rs b/bin/reth/src/commands/mod.rs index cd5a7e7ba6a3..748cca82fd53 100644 --- a/bin/reth/src/commands/mod.rs +++ b/bin/reth/src/commands/mod.rs @@ -7,14 +7,14 @@ pub mod dump_genesis; pub mod import; pub mod import_op; pub mod import_receipts_op; - pub mod init_cmd; pub mod init_state; - pub mod node; pub mod p2p; +pub mod prune; pub mod recover; pub mod stage; +pub mod t8n; pub mod test_vectors; pub mod common; diff --git a/bin/reth/src/commands/p2p/mod.rs b/bin/reth/src/commands/p2p/mod.rs index 290a0a0b08bb..161eb6cc9133 100644 --- a/bin/reth/src/commands/p2p/mod.rs +++ b/bin/reth/src/commands/p2p/mod.rs @@ -4,13 +4,12 @@ use crate::{ args::{ get_secret_key, utils::{chain_help, chain_value_parser, hash_or_num_value_parser, SUPPORTED_CHAINS}, - DatabaseArgs, DiscoveryArgs, NetworkArgs, + DatabaseArgs, NetworkArgs, }, utils::get_single_header, }; use backon::{ConstantBuilder, Retryable}; use clap::{Parser, Subcommand}; -use discv5::ListenConfig; use reth_chainspec::ChainSpec; use reth_config::Config; use reth_db::create_db; @@ -19,11 +18,7 @@ use reth_network_p2p::bodies::client::BodiesClient; use reth_node_core::args::DatadirArgs; use reth_primitives::BlockHashOrNumber; use reth_provider::{providers::StaticFileProvider, ProviderFactory}; -use std::{ - net::{IpAddr, SocketAddrV4, SocketAddrV6}, - path::PathBuf, - sync::Arc, -}; +use std::{path::PathBuf, sync::Arc}; /// `reth p2p` command #[derive(Debug, Parser)] @@ -113,47 +108,7 @@ impl Command { .disable_discv4_discovery_if(self.chain.chain.is_optimism()) .boot_nodes(boot_nodes.clone()) .apply(|builder| { - self.network - .discovery - .apply_to_builder(builder, rlpx_socket) - .map_discv5_config_builder(|builder| { - let DiscoveryArgs { - discv5_addr, - discv5_addr_ipv6, - discv5_port, - discv5_port_ipv6, - discv5_lookup_interval, - discv5_bootstrap_lookup_interval, - discv5_bootstrap_lookup_countdown, - .. - } = self.network.discovery; - - // Use rlpx address if none given - let discv5_addr_ipv4 = discv5_addr.or(match self.network.addr { - IpAddr::V4(ip) => Some(ip), - IpAddr::V6(_) => None, - }); - let discv5_addr_ipv6 = discv5_addr_ipv6.or(match self.network.addr { - IpAddr::V4(_) => None, - IpAddr::V6(ip) => Some(ip), - }); - - builder - .discv5_config( - discv5::ConfigBuilder::new(ListenConfig::from_two_sockets( - discv5_addr_ipv4 - .map(|addr| SocketAddrV4::new(addr, discv5_port)), - discv5_addr_ipv6.map(|addr| { - SocketAddrV6::new(addr, discv5_port_ipv6, 0, 0) - }), - )) - .build(), - ) - .add_unsigned_boot_nodes(boot_nodes.into_iter()) - .lookup_interval(discv5_lookup_interval) - .bootstrap_lookup_interval(discv5_bootstrap_lookup_interval) - .bootstrap_lookup_countdown(discv5_bootstrap_lookup_countdown) - }) + self.network.discovery.apply_to_builder(builder, rlpx_socket, boot_nodes) }) .build(Arc::new(ProviderFactory::new( noop_db, diff --git a/bin/reth/src/commands/prune.rs b/bin/reth/src/commands/prune.rs new file mode 100644 index 000000000000..f3b0fcaab966 --- /dev/null +++ b/bin/reth/src/commands/prune.rs @@ -0,0 +1,43 @@ +//! Command that runs pruning without any limits. + +use crate::commands::common::{AccessRights, Environment, EnvironmentArgs}; +use clap::Parser; +use reth_prune::PrunerBuilder; +use reth_static_file::StaticFileProducer; +use tracing::info; + +/// Prunes according to the configuration without any limits +#[derive(Debug, Parser)] +pub struct PruneCommand { + #[command(flatten)] + env: EnvironmentArgs, +} + +impl PruneCommand { + /// Execute the `prune` command + pub async fn execute(self) -> eyre::Result<()> { + let Environment { config, provider_factory, .. } = self.env.init(AccessRights::RW)?; + let prune_config = config.prune.unwrap_or_default(); + + // Copy data from database to static files + info!(target: "reth::cli", "Copying data from database to static files..."); + let static_file_producer = + StaticFileProducer::new(provider_factory.clone(), prune_config.segments.clone()); + let lowest_static_file_height = static_file_producer.lock().copy_to_static_files()?.min(); + info!(target: "reth::cli", ?lowest_static_file_height, "Copied data from database to static files"); + + // Delete data which has been copied to static files. + if let Some(prune_tip) = lowest_static_file_height { + info!(target: "reth::cli", ?prune_tip, ?prune_config, "Pruning data from database..."); + // Run the pruner according to the configuration, and don't enforce any limits on it + let mut pruner = PrunerBuilder::new(prune_config) + .prune_delete_limit(usize::MAX) + .build(provider_factory); + + pruner.run(prune_tip)?; + info!(target: "reth::cli", "Pruned data from database"); + } + + Ok(()) + } +} diff --git a/bin/reth/src/commands/stage/drop.rs b/bin/reth/src/commands/stage/drop.rs index 8297eafef81a..ec32af330e97 100644 --- a/bin/reth/src/commands/stage/drop.rs +++ b/bin/reth/src/commands/stage/drop.rs @@ -3,16 +3,18 @@ use crate::{ args::StageEnum, commands::common::{AccessRights, Environment, EnvironmentArgs}, - utils::DbTool, }; use clap::Parser; use itertools::Itertools; use reth_db::{static_file::iter_static_files, tables, DatabaseEnv}; use reth_db_api::transaction::DbTxMut; -use reth_db_common::init::{insert_genesis_header, insert_genesis_history, insert_genesis_state}; -use reth_primitives::{static_file::find_fixed_range, StaticFileSegment}; +use reth_db_common::{ + init::{insert_genesis_header, insert_genesis_history, insert_genesis_state}, + DbTool, +}; use reth_provider::{providers::StaticFileWriter, StaticFileProviderFactory}; use reth_stages::StageId; +use reth_static_file_types::{find_fixed_range, StaticFileSegment}; /// `reth drop-stage` command #[derive(Debug, Parser)] diff --git a/bin/reth/src/commands/stage/dump/execution.rs b/bin/reth/src/commands/stage/dump/execution.rs index b6d6721dcf8d..67b6d5a659c4 100644 --- a/bin/reth/src/commands/stage/dump/execution.rs +++ b/bin/reth/src/commands/stage/dump/execution.rs @@ -1,9 +1,10 @@ use super::setup; -use crate::{macros::block_executor, utils::DbTool}; +use crate::macros::block_executor; use reth_db::{tables, DatabaseEnv}; use reth_db_api::{ cursor::DbCursorRO, database::Database, table::TableImporter, transaction::DbTx, }; +use reth_db_common::DbTool; use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_provider::{providers::StaticFileProvider, ChainSpecProvider, ProviderFactory}; use reth_stages::{stages::ExecutionStage, Stage, StageCheckpoint, UnwindInput}; diff --git a/bin/reth/src/commands/stage/dump/hashing_account.rs b/bin/reth/src/commands/stage/dump/hashing_account.rs index 2e50a8ad6059..899b521fdc57 100644 --- a/bin/reth/src/commands/stage/dump/hashing_account.rs +++ b/bin/reth/src/commands/stage/dump/hashing_account.rs @@ -1,8 +1,8 @@ use super::setup; -use crate::utils::DbTool; use eyre::Result; use reth_db::{tables, DatabaseEnv}; use reth_db_api::{database::Database, table::TableImporter}; +use reth_db_common::DbTool; use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_primitives::BlockNumber; use reth_provider::{providers::StaticFileProvider, ProviderFactory}; diff --git a/bin/reth/src/commands/stage/dump/hashing_storage.rs b/bin/reth/src/commands/stage/dump/hashing_storage.rs index 1dfd722f5099..f05ac390dc8e 100644 --- a/bin/reth/src/commands/stage/dump/hashing_storage.rs +++ b/bin/reth/src/commands/stage/dump/hashing_storage.rs @@ -1,8 +1,8 @@ use super::setup; -use crate::utils::DbTool; use eyre::Result; use reth_db::{tables, DatabaseEnv}; use reth_db_api::{database::Database, table::TableImporter}; +use reth_db_common::DbTool; use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_provider::{providers::StaticFileProvider, ProviderFactory}; use reth_stages::{stages::StorageHashingStage, Stage, StageCheckpoint, UnwindInput}; diff --git a/bin/reth/src/commands/stage/dump/merkle.rs b/bin/reth/src/commands/stage/dump/merkle.rs index fa345bb474a4..4e2541b60ea2 100644 --- a/bin/reth/src/commands/stage/dump/merkle.rs +++ b/bin/reth/src/commands/stage/dump/merkle.rs @@ -1,20 +1,21 @@ use super::setup; -use crate::{macros::block_executor, utils::DbTool}; +use crate::macros::block_executor; use eyre::Result; use reth_config::config::EtlConfig; use reth_db::{tables, DatabaseEnv}; use reth_db_api::{database::Database, table::TableImporter}; +use reth_db_common::DbTool; use reth_exex::ExExManagerHandle; use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_primitives::BlockNumber; use reth_provider::{providers::StaticFileProvider, ProviderFactory}; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::{ stages::{ - AccountHashingStage, ExecutionStage, ExecutionStageThresholds, MerkleStage, - StorageHashingStage, MERKLE_STAGE_DEFAULT_CLEAN_THRESHOLD, + AccountHashingStage, ExecutionStage, MerkleStage, StorageHashingStage, + MERKLE_STAGE_DEFAULT_CLEAN_THRESHOLD, }, - Stage, StageCheckpoint, UnwindInput, + ExecutionStageThresholds, Stage, StageCheckpoint, UnwindInput, }; use tracing::info; diff --git a/bin/reth/src/commands/stage/dump/mod.rs b/bin/reth/src/commands/stage/dump/mod.rs index 287708b00d68..f1fbdbbdecbd 100644 --- a/bin/reth/src/commands/stage/dump/mod.rs +++ b/bin/reth/src/commands/stage/dump/mod.rs @@ -1,18 +1,17 @@ //! Database debugging tool use crate::{ + args::DatadirArgs, commands::common::{AccessRights, Environment, EnvironmentArgs}, dirs::DataDirPath, - utils::DbTool, }; - -use crate::args::DatadirArgs; use clap::Parser; use reth_db::{init_db, mdbx::DatabaseArguments, tables, DatabaseEnv}; use reth_db_api::{ cursor::DbCursorRO, database::Database, models::ClientVersion, table::TableImporter, transaction::DbTx, }; +use reth_db_common::DbTool; use reth_node_core::dirs::PlatformPath; use std::path::PathBuf; use tracing::info; diff --git a/bin/reth/src/commands/stage/run.rs b/bin/reth/src/commands/stage/run.rs index b8dcc7c9194d..55824bd79c69 100644 --- a/bin/reth/src/commands/stage/run.rs +++ b/bin/reth/src/commands/stage/run.rs @@ -20,11 +20,11 @@ use reth_provider::{ }; use reth_stages::{ stages::{ - AccountHashingStage, BodyStage, ExecutionStage, ExecutionStageThresholds, - IndexAccountHistoryStage, IndexStorageHistoryStage, MerkleStage, SenderRecoveryStage, - StorageHashingStage, TransactionLookupStage, + AccountHashingStage, BodyStage, ExecutionStage, IndexAccountHistoryStage, + IndexStorageHistoryStage, MerkleStage, SenderRecoveryStage, StorageHashingStage, + TransactionLookupStage, }, - ExecInput, ExecOutput, Stage, StageExt, UnwindInput, UnwindOutput, + ExecInput, ExecOutput, ExecutionStageThresholds, Stage, StageExt, UnwindInput, UnwindOutput, }; use std::{any::Any, net::SocketAddr, sync::Arc, time::Instant}; use tracing::*; diff --git a/bin/reth/src/commands/stage/unwind.rs b/bin/reth/src/commands/stage/unwind.rs index 157f33bff7cb..e3cb0cc8fcd5 100644 --- a/bin/reth/src/commands/stage/unwind.rs +++ b/bin/reth/src/commands/stage/unwind.rs @@ -13,11 +13,11 @@ use reth_provider::{ BlockExecutionWriter, BlockNumReader, ChainSpecProvider, FinalizedBlockReader, FinalizedBlockWriter, ProviderFactory, StaticFileProviderFactory, }; -use reth_prune_types::PruneModes; +use reth_prune::PruneModes; use reth_stages::{ - sets::DefaultStages, - stages::{ExecutionStage, ExecutionStageThresholds}, - Pipeline, StageSet, + sets::{DefaultStages, OfflineStages}, + stages::ExecutionStage, + ExecutionStageThresholds, Pipeline, StageSet, }; use reth_static_file::StaticFileProducer; use std::{ops::RangeInclusive, sync::Arc}; @@ -40,6 +40,11 @@ pub struct Command { #[command(subcommand)] command: Subcommands, + + /// If this is enabled, then all stages except headers, bodies, and sender recovery will be + /// unwound. + #[arg(long)] + offline: bool, } impl Command { @@ -52,16 +57,30 @@ impl Command { eyre::bail!("Cannot unwind genesis block") } - // Only execute a pipeline unwind if the start of the range overlaps the existing static - // files. If that's the case, then copy all available data from MDBX to static files, and - // only then, proceed with the unwind. - if let Some(highest_static_block) = provider_factory + let highest_static_file_block = provider_factory .static_file_provider() .get_highest_static_files() .max() - .filter(|highest_static_file_block| highest_static_file_block >= range.start()) - { - info!(target: "reth::cli", ?range, ?highest_static_block, "Executing a pipeline unwind."); + .filter(|highest_static_file_block| highest_static_file_block >= range.start()); + + // Execute a pipeline unwind if the start of the range overlaps the existing static + // files. If that's the case, then copy all available data from MDBX to static files, and + // only then, proceed with the unwind. + // + // We also execute a pipeline unwind if `offline` is specified, because we need to only + // unwind the data associated with offline stages. + if highest_static_file_block.is_some() || self.offline { + if self.offline { + info!(target: "reth::cli", "Performing an unwind for offline-only data!"); + } + + if let Some(highest_static_file_block) = highest_static_file_block { + info!(target: "reth::cli", ?range, ?highest_static_file_block, "Executing a pipeline unwind."); + } else { + info!(target: "reth::cli", ?range, "Executing a pipeline unwind."); + } + + // This will build an offline-only pipeline if the `offline` flag is enabled let mut pipeline = self.build_pipeline(config, provider_factory.clone()).await?; // Move all applicable data from database to static files. @@ -87,7 +106,7 @@ impl Command { provider.commit()?; } - println!("Unwound {} blocks", range.count()); + info!(target: "reth::cli", range=?range.clone(), count=range.count(), "Unwound blocks"); Ok(()) } @@ -105,9 +124,14 @@ impl Command { let (tip_tx, tip_rx) = watch::channel(B256::ZERO); let executor = block_executor!(provider_factory.chain_spec()); - let pipeline = Pipeline::builder() - .with_tip_sender(tip_tx) - .add_stages( + let builder = if self.offline { + Pipeline::builder().add_stages( + OfflineStages::new(executor, config.stages, PruneModes::default()) + .builder() + .disable(reth_stages::StageId::SenderRecovery), + ) + } else { + Pipeline::builder().with_tip_sender(tip_tx).add_stages( DefaultStages::new( provider_factory.clone(), tip_rx, @@ -131,10 +155,12 @@ impl Command { ExExManagerHandle::empty(), )), ) - .build( - provider_factory.clone(), - StaticFileProducer::new(provider_factory, PruneModes::default()), - ); + }; + + let pipeline = builder.build( + provider_factory.clone(), + StaticFileProducer::new(provider_factory, PruneModes::default()), + ); Ok(pipeline) } } diff --git a/bin/reth/src/commands/t8n/mem_db.rs b/bin/reth/src/commands/t8n/mem_db.rs new file mode 100644 index 000000000000..c49a3d93a07d --- /dev/null +++ b/bin/reth/src/commands/t8n/mem_db.rs @@ -0,0 +1,283 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use reth_primitives::{Address, B256, U256}; +use reth_revm::revm::{ + primitives::{hash_map::Entry, Account, AccountInfo, Bytecode, HashMap}, + Database, DatabaseCommit, +}; +use thiserror::Error as ThisError; + +/// Error returned by the [MemDb]. +#[derive(Debug, ThisError)] +pub(crate) enum DbError { + /// Returned when an account was accessed but not loaded into the DB. + #[error("account {0} not loaded")] + AccountNotFound(Address), + /// Returned when storage was accessed but not loaded into the DB. + #[error("storage {1}@{0} not loaded")] + SlotNotFound(Address, U256), + /// Returned when a block hash was accessed but not loaded into the DB. + #[error("block {0} not loaded")] + BlockNotFound(u64), + /// Unspecified error. + #[error(transparent)] + Unspecified(#[from] eyre::Error), +} + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub(crate) enum AccountState { + // Account can be cleared/removed from state. + Deleted, + /// EVM touched this account. + Touched, + /// EVM cleared storage of this account, mostly by `selfdestruct`. + StorageCleared, + /// EVM didn't interacted with this account. + #[default] + None, +} + +#[derive(Clone, Debug, Default)] +pub(crate) struct DbAccount { + pub(crate) info: AccountInfo, + pub(crate) state: AccountState, + pub(crate) storage: HashMap, +} + +impl DbAccount { + pub(crate) fn new(info: AccountInfo) -> Self { + Self { info, ..Default::default() } + } + + /// Return the account info or `None` if the account has been deleted. + pub(crate) fn info(&self) -> Option { + if self.state == AccountState::Deleted { + None + } else { + Some(self.info.clone()) + } + } +} + +/// In-memory EVM database. +#[derive(Clone, Debug, Default)] +pub(crate) struct MemDb { + /// Account info where None means it is not existing. + pub(crate) accounts: HashMap, + /// All cached block hashes. + pub(crate) block_hashes: HashMap, +} + +impl MemDb { + pub(crate) fn accounts_len(&self) -> usize { + self.accounts.len() + } + + pub(crate) fn storage_keys(&self) -> HashMap> { + let mut out = HashMap::new(); + for (address, account) in &self.accounts { + out.insert(*address, account.storage.keys().cloned().collect()); + } + + out + } + + /// Insert account info without overriding its storage. + /// Panics if a different account info exists. + pub(crate) fn insert_account_info(&mut self, address: Address, info: AccountInfo) { + match self.accounts.entry(address) { + Entry::Occupied(entry) => assert_eq!(info, entry.get().info), + Entry::Vacant(entry) => { + entry.insert(DbAccount::new(info)); + } + } + } + + /// insert account storage without overriding the account info. + /// Panics if the account does not exist. + pub(crate) fn insert_account_storage(&mut self, address: &Address, index: U256, data: U256) { + let account = self.accounts.get_mut(address).expect("account not found"); + account.storage.insert(index, data); + } + + /// Insert the specified block hash. Panics if a different block hash exists. + pub(crate) fn insert_block_hash(&mut self, block_no: u64, block_hash: B256) { + match self.block_hashes.entry(block_no) { + Entry::Occupied(entry) => assert_eq!(&block_hash, entry.get()), + Entry::Vacant(entry) => { + entry.insert(block_hash); + } + }; + } + + /// Increment the balance of the specified account. + pub(crate) fn drain_balances( + &mut self, + addresses: impl IntoIterator, + ) -> Vec { + addresses + .into_iter() + .map(|address| { + let account = self.accounts.get_mut(&address).expect("account not found"); + let balance = account.info.balance; + account.info.balance = U256::ZERO; + balance.to() + }) + .collect() + } + + /// Increment the balance of the specified account. + pub(crate) fn increment_balance(&mut self, address: &Address, balance: u128) { + let balance = U256::from(balance); + self.accounts.get_mut(address).expect("account not found").info.balance += balance; + } +} + +impl Database for MemDb { + type Error = DbError; + + /// Get basic account information. + fn basic(&mut self, address: Address) -> Result, Self::Error> { + match self.accounts.get(&address) { + Some(db_account) => Ok(db_account.info()), + None => Err(DbError::AccountNotFound(address)), + } + } + + /// Get account code by its hash. + fn code_by_hash(&mut self, _code_hash: B256) -> Result { + // not needed because we already load code with basic info + unreachable!() + } + + /// Get storage value of address at index. + fn storage(&mut self, address: Address, index: U256) -> Result { + match self.accounts.get(&address) { + // if we have this account in the cache, we can query its storage + Some(account) => match account.storage.get(&index) { + Some(value) => Ok(*value), + None => match account.state { + // it is impossible to access the storage from a non-existing account + AccountState::Deleted => unreachable!(), + // if the account has been deleted or cleared, we must return 0 + AccountState::StorageCleared => Ok(U256::ZERO), + // otherwise this is an uncached load + _ => Err(DbError::SlotNotFound(address, index)), + }, + }, + // otherwise this is an uncached load + None => Err(DbError::AccountNotFound(address)), + } + } + + fn block_hash(&mut self, number: U256) -> Result { + let block_no: u64 = number.try_into().map_err(|_| { + eyre::eyre!("invalid block number: expected <= {}, got {}", u64::MAX, &number) + })?; + self.block_hashes.get(&block_no).cloned().ok_or(DbError::BlockNotFound(block_no)) + } +} + +impl DatabaseCommit for MemDb { + fn commit(&mut self, changes: HashMap) { + for (address, new_account) in changes { + // if nothing was touched, there is nothing to do + if !new_account.is_touched() { + continue; + } + + if new_account.is_selfdestructed() { + // get the account we are destroying + let db_account = match self.accounts.entry(address) { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(_) => { + // destruction of a non-existing account, so there is nothing to do + // a) the account was created and destroyed in the same transaction + // b) or it was destroyed without reading and thus not cached + continue; + } + }; + + // it is not possible to delete a deleted account + debug_assert!(db_account.state != AccountState::Deleted); + + // clear the account and mark it as deleted + db_account.storage.clear(); + db_account.state = AccountState::Deleted; + db_account.info = AccountInfo::default(); + + continue; + } + + // empty accounts cannot have any non-zero storage + if new_account.is_empty() { + debug_assert!(new_account.storage.is_empty()); + } + + let is_newly_created = new_account.is_created(); + + // update account info + let db_account = match self.accounts.entry(address) { + Entry::Occupied(entry) => { + let db_account = entry.into_mut(); + + // the account was touched, but it is now empty, so it should be deleted + // this also deletes empty accounts previously contained in the state trie + if new_account.is_empty() { + // if the account is empty, it must be deleted + db_account.storage.clear(); + db_account.state = AccountState::Deleted; + db_account.info = AccountInfo::default(); + + continue; + } + + // update the account info + db_account.info = new_account.info; + db_account + } + Entry::Vacant(entry) => { + // create a new account only if it is not empty + if new_account.is_empty() { + continue; + } + + // create new non-empty account + entry.insert(DbAccount::new(new_account.info)) + } + }; + + // set the correct state + db_account.state = if is_newly_created { + db_account.storage.clear(); + AccountState::StorageCleared + } else if db_account.state == AccountState::StorageCleared { + // when creating the storage trie, it must be cleared it first + AccountState::StorageCleared + } else { + AccountState::Touched + }; + + // update all changed storage values + db_account.storage.extend( + new_account + .storage + .into_iter() + .filter(|(_, value)| value.is_changed()) + .map(|(key, value)| (key, value.present_value())), + ); + } + } +} diff --git a/bin/reth/src/commands/t8n/mod.rs b/bin/reth/src/commands/t8n/mod.rs new file mode 100644 index 000000000000..06e01980ae96 --- /dev/null +++ b/bin/reth/src/commands/t8n/mod.rs @@ -0,0 +1,534 @@ +#![allow(missing_docs)] +#![allow(dead_code)] +//! Main `t8n` command +//! +//! Runs an EVM state transition using revm. + +mod mem_db; +mod provider; +mod trie; +mod utils; + +use mem_db::*; +use provider::*; +use reth_revm::{ + eth_dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, + primitives::{AnalysisKind, ResultAndState}, + revm::{ + primitives::{AccountInfo, BlobExcessGasAndPrice, Bytecode, HashMap}, + Evm, + }, + state_change::apply_beacon_root_contract_call, + DatabaseCommit, +}; +use tracing::{info, warn}; +use trie::*; +use utils::*; + +use reth_primitives::{ + basefee::calculate_next_block_base_fee, + constants::eip4844::MAX_DATA_GAS_PER_BLOCK, + eip4844::calculate_excess_blob_gas, + hex, keccak256, + revm::{config::revm_spec, env::fill_tx_env}, + BaseFeeParams, Bloom, Bytes, ChainSpec, ForkSpec, Hardfork, Head, Log, Receipt, + ReceiptWithBloom, TxType, U256, +}; + +use clap::Parser; + +use std::{ + fs::{self, File}, + io::{self, Write}, + path::PathBuf, +}; + +const STDIN_ARG_NAME: &str = "stdin"; +const STDOUT_ARG_NAME: &str = "stdout"; +const STDERR_ARG_NAME: &str = "stderr"; +const RLP_EXT: &str = ".rlp"; + +/// `reth t8n` command +#[derive(Debug, Parser)] +pub struct Command { + #[arg(long = "input.alloc")] + input_alloc: String, + #[arg(long = "input.env")] + input_env: String, + #[arg(long = "input.txs")] + input_txs: String, + #[arg(long = "output.basedir")] + output_basedir: PathBuf, + #[arg(long = "output.alloc")] + output_alloc: String, + #[arg(long = "output.body")] + output_body: String, + #[arg(long = "output.result")] + output_result: String, + #[arg(long)] + trace: bool, + #[arg(long = "trace.tracer")] + tracer: String, + #[arg(long = "trace.jsonconfig")] + jsonconfig: String, + #[arg(long = "trace.memory")] + memory: bool, + #[arg(long = "trace.nostack")] + nostack: bool, + #[arg(long = "trace.returndata")] + returndata: bool, + #[arg(long = "state.reward")] + reward: i64, + #[arg(long = "state.chainid")] + chain_id: u64, + #[arg(long = "state.fork", value_enum)] + fork: ForkSpec, +} + +impl Command { + fn apply( + &self, + prestate: Prestate, + chain: &ChainSpec, + ) -> eyre::Result<(MemDb, ExecutionResult, Bytes)> { + let Prestate { alloc, env, txs } = prestate; + // set pre state with an in-memory state provider + let mut db = MemDb::default(); + for (address, account) in alloc { + let mut info = AccountInfo { + balance: account.balance, + nonce: account.nonce, + ..Default::default() + }; + if let Some(code) = account.code { + info.code_hash = keccak256(code.as_ref()); + info.code = Some(Bytecode::new_raw(code)); + } + db.insert_account_info(address, info); + for (slot, value) in account.storage { + db.insert_account_storage(&address, slot, value); + } + } + if chain.fork(Hardfork::Dao).transitions_at_block(env.current_number) { + let drained_balance: u128 = db.drain_balances(DAO_HARDKFORK_ACCOUNTS).into_iter().sum(); + db.increment_balance(&DAO_HARDFORK_BENEFICIARY, drained_balance); + } + + let mut init_state_trie = MptNode::default(); + apply_state_update(&mut init_state_trie, &db)?; + let spec_id = revm_spec( + chain, + Head::new( + env.current_number, + Default::default(), + env.current_difficulty.unwrap_or_default(), + U256::MAX, + env.current_timestamp, + ), + ); + let mut excess_blob_gas = 0; + let mut evm = Evm::builder() + .with_db(db) + .with_spec_id(spec_id) + .modify_block_env(|blk_env| { + // set the EVM block environment + blk_env.number = env.current_number.try_into().unwrap(); + blk_env.coinbase = env.current_coinbase; + blk_env.timestamp = env.current_timestamp.try_into().unwrap(); + blk_env.difficulty = env.current_difficulty.unwrap_or_default(); + blk_env.prevrandao = env.current_random.map(Into::into); + blk_env.basefee = env.current_base_fee.unwrap_or_default(); + blk_env.gas_limit = env.current_gas_limit.try_into().unwrap(); + excess_blob_gas = if env.current_excess_blob_gas.is_some() { + env.current_excess_blob_gas.unwrap() + } else if env.parent_excess_blob_gas.is_some() && env.parent_blob_gas_used.is_some() + { + calculate_excess_blob_gas( + env.parent_excess_blob_gas.unwrap(), + env.parent_blob_gas_used.unwrap(), + ) + } else { + 0 + }; + blk_env.blob_excess_gas_and_price = + Some(BlobExcessGasAndPrice::new(excess_blob_gas)); + }) + .modify_cfg_env(|cfg_env| { + // set the EVM configuration + cfg_env.chain_id = chain.chain.id(); + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; + }) + .build(); + + if env.parent_beacon_block_root.is_some() { + apply_beacon_root_contract_call( + &chain, + env.current_timestamp, + env.current_number, + env.parent_beacon_block_root, + &mut evm, + )?; + } + + let mut rejected_txs = vec![]; + let mut included_txs = vec![]; + let mut receipts: Vec = vec![]; + let mut blob_gas_used = 0; + let mut gas_used = 0; + + for (idx, tx) in txs.into_iter().enumerate() { + if tx.tx_type() == TxType::Eip4844 && evm.block().blob_excess_gas_and_price.is_none() { + let error = "blob tx used but field env.ExcessBlobGas missing"; + warn!(name: "rejected tx", index = idx, hash = ?tx.hash, error = error); + rejected_txs.push(RejectedTx { index: idx, error: error.to_string() }); + continue; + } + + let tx = match tx.try_into_ecrecovered() { + Ok(tx) => tx, + Err(_) => { + let error = "failed to recover transaction"; + warn!(name: "rejected tx", index = idx, error = error); + rejected_txs.push(RejectedTx { index: idx, error: error.to_string() }); + continue; + } + }; + fill_tx_env(evm.tx_mut(), tx.as_ref(), tx.signer()); + let tx_blob_gas = tx.blob_gas_used().unwrap_or_default(); + let (used, max) = (blob_gas_used + tx_blob_gas, MAX_DATA_GAS_PER_BLOCK); + if used > max { + let error = format!("blob gas ({}) would exceed maximum allowance {}", used, max); + warn!(name: "rejected tx", index = idx, error = error); + rejected_txs.push(RejectedTx { index: idx, error }); + continue; + } + let ResultAndState { result, state } = match evm.transact() { + Ok(result) => result, + Err(err) => { + info!( + name: "rejected tx", + index = idx, + hash = ?tx.as_ref().hash(), + from = ?tx.signer(), + error = ?err + ); + rejected_txs.push(RejectedTx { index: idx, error: err.to_string() }); + continue; + } + }; + blob_gas_used += tx_blob_gas; + gas_used += result.gas_used(); + + evm.db_mut().commit(state); + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push( + Receipt { + tx_type: tx.tx_type(), + // Success flag was added in `EIP-658: Embedding transaction status code in + // receipts`. + success: result.is_success(), + cumulative_gas_used: gas_used, + // convert to reth log + logs: result.into_logs().into_iter().map(Into::into).collect(), + } + .into(), + ); + + included_txs.push(tx); + } + // reward + if self.reward >= 0 { + let block_reward = self.reward as u64; + let mut miner_reward = block_reward; + let per_ommer = block_reward / 32; + for ommer in env.ommers { + miner_reward += per_ommer; + let reward = ((8 - ommer.delta) * block_reward) / 8; + evm.db_mut().increment_balance(&ommer.address, reward as u128); + } + evm.db_mut().increment_balance(&env.current_coinbase, miner_reward as u128); + } + // withdrawals + let mut withdrawals_trie = MptNode::default(); + for (i, withdrawal) in env.withdrawals.iter().enumerate() { + let amount = withdrawal.amount_wei(); + evm.db_mut().increment_balance(&withdrawal.address, amount); + withdrawals_trie.insert_rlp(&alloy_rlp::encode(i), withdrawal)?; + } + // take db + let db = std::mem::take(evm.db_mut()); + // calcuate roots + let mut tx_trie = MptNode::default(); + let mut receipt_trie = MptNode::default(); + let mut bloom = Bloom::default(); + for (idx, (tx, receipt)) in included_txs.iter().zip(receipts.iter()).enumerate() { + let trie_key = alloy_rlp::encode(idx); + tx_trie.insert_rlp(&trie_key, tx)?; + receipt_trie.insert_rlp(&trie_key, receipt)?; + bloom.accrue_bloom(&receipt.bloom); + } + apply_state_update(&mut init_state_trie, &db)?; + let logs: Vec<&Log> = receipts.iter().flat_map(|r| r.receipt.logs.iter()).collect(); + let exec_result = ExecutionResult { + state_root: init_state_trie.hash(), + tx_root: tx_trie.hash(), + receipt_root: receipt_trie.hash(), + logs_hash: keccak256(alloy_rlp::encode(logs)), + bloom, + receipts: receipts.into_iter().map(|v| v.into_receipt()).collect(), + rejected: rejected_txs, + difficulty: env.current_difficulty, + gas_used: gas_used.try_into().unwrap(), + base_fee: env.current_base_fee, + withdrawals_root: Some(withdrawals_trie.hash()), + current_excess_blob_gas: Some(excess_blob_gas), + current_blob_gas_used: Some(blob_gas_used), + }; + let body = alloy_rlp::encode(included_txs); + Ok((db, exec_result, Bytes::from(body))) + } + + fn output( + &self, + alloc: PrestateAlloc, + result: ExecutionResult, + body: Bytes, + ) -> eyre::Result<()> { + let mut stdout_output: HashMap = HashMap::default(); + let mut stderr_output: HashMap = HashMap::default(); + + let body = hex::encode(body); + let alloc_json = serde_json::to_string_pretty(&alloc)?; + let result_json = serde_json::to_string_pretty(&result)?; + let body_json = serde_json::to_string_pretty(&body)?; + + let mut dispatch = |name: &str, value: String| -> eyre::Result<()> { + match name { + STDOUT_ARG_NAME => { + stdout_output.insert(name.to_string(), value); + } + STDERR_ARG_NAME => { + stderr_output.insert(name.to_string(), value); + } + _ => { + let path = self.output_basedir.join(name); + fs::write(path, value)?; + } + } + Ok(()) + }; + + dispatch("alloc", alloc_json)?; + dispatch("result", result_json)?; + dispatch("body", body_json)?; + + if !stdout_output.is_empty() { + let stdout_json = serde_json::to_string_pretty(&stdout_output)?; + let mut stdout = io::stdout(); + stdout.write_all(stdout_json.as_bytes())?; + writeln!(&mut stdout)?; + stdout.flush()?; + } + + if !stderr_output.is_empty() { + let stderr_json = serde_json::to_string_pretty(&stderr_output)?; + let mut stderr = io::stderr(); + stderr.write_all(stderr_json.as_bytes())?; + writeln!(&mut stderr)?; + stderr.flush()?; + } + Ok(()) + } + + fn parse_prestate(&self) -> eyre::Result { + let mut input: Input = Default::default(); + if self.input_alloc == STDIN_ARG_NAME || + self.input_env == STDIN_ARG_NAME || + self.input_txs == STDIN_ARG_NAME + { + input = serde_json::from_reader(io::stdin())?; + } + + if self.input_alloc != STDIN_ARG_NAME { + input.alloc = Some(serde_json::from_reader(File::open(&self.input_alloc)?)?); + } + + if self.input_env != STDIN_ARG_NAME { + input.env = Some(serde_json::from_reader(File::open(&self.input_env)?)?); + } + let mut txs = vec![]; + if self.input_txs != STDIN_ARG_NAME { + if self.input_txs.ends_with(RLP_EXT) { + let buf = fs::read(&self.input_txs)?; + let mut rlp = alloy_rlp::Rlp::new(&buf)?; + while let Some(tx) = rlp.get_next()? { + txs.push(tx); + } + } else { + let tx_with_keys: Vec = + serde_json::from_reader(File::open(&self.input_txs)?)?; + for tx in tx_with_keys { + let tx = try_into_primitive_transaction_and_sign(tx.tx, &tx.secret_key)?; + txs.push(tx); + } + } + } else if input.tx_rlp.is_some() { + let buf = hex::decode(input.tx_rlp.as_ref().unwrap())?; + let mut rlp = alloy_rlp::Rlp::new(&buf)?; + while let Some(tx) = rlp.get_next()? { + txs.push(tx); + } + } else if input.txs.is_some() { + for tx in input.txs.unwrap() { + let tx = try_into_primitive_transaction_and_sign(tx.tx, &tx.secret_key)?; + txs.push(tx); + } + } + Ok(Prestate { alloc: input.alloc.unwrap(), env: input.env.unwrap(), txs }) + } + + /// Execute `stage` command + pub async fn execute(&self) -> eyre::Result<()> { + let mut prestate = self.parse_prestate()?; + let mut chain: ChainSpec = self.fork.clone().into(); + chain.chain = self.chain_id.into(); + + apply_london_checks(&mut prestate.env, &chain)?; + apply_shanghai_checks(&mut prestate.env, &chain)?; + apply_merge_checks(&mut prestate.env, &chain)?; + apply_cancun_checks(&mut prestate.env, &chain)?; + + let (db, result, body) = self.apply(prestate, &chain)?; + let alloc = dump_db(db); + self.output(alloc, result, body)?; + Ok(()) + } +} + +fn dump_db(db: MemDb) -> PrestateAlloc { + db.accounts + .into_iter() + .map(|(k, v)| { + ( + k, + PrestateAccount { + balance: v.info.balance, + nonce: v.info.nonce, + storage: v.storage.into(), + code: v.info.code.map(|v| v.bytecode), + }, + ) + }) + .collect() +} + +fn apply_london_checks(env: &mut PrestateEnv, chain: &ChainSpec) -> eyre::Result<()> { + if !chain.fork(Hardfork::London).active_at_block(env.current_number) { + return Ok(()); + } + if env.current_base_fee.is_some() { + return Ok(()); + } + if env.parent_base_fee.is_none() || env.current_number == 0 { + return Err(eyre::eyre!("EIP-1559 config but missing 'currentBaseFee' in env section")); + } + env.current_base_fee = Some( + calculate_next_block_base_fee( + env.parent_gas_used, + env.parent_gas_limit, + env.parent_base_fee.map(|v| v.to()).unwrap_or_default(), + BaseFeeParams::ethereum(), + ) + .try_into() + .unwrap(), + ); + Ok(()) +} + +fn apply_shanghai_checks(env: &mut PrestateEnv, chain: &ChainSpec) -> eyre::Result<()> { + if !(chain.fork(Hardfork::Shanghai).active_at_block(env.current_number) && + chain.is_shanghai_active_at_timestamp(env.current_timestamp)) + { + return Ok(()); + } + if env.withdrawals.is_empty() { + return Err(eyre::eyre!("Shanghai config but missing 'withdrawals' in env section")); + } + Ok(()) +} + +fn apply_merge_checks(env: &mut PrestateEnv, chain: &ChainSpec) -> eyre::Result<()> { + let is_merged = chain.get_final_paris_total_difficulty().is_some() && + chain.get_final_paris_total_difficulty().unwrap().is_zero(); + if !is_merged { + if env.current_difficulty.is_some() { + return Ok(()); + } + if env.parent_difficulty.is_none() { + return Err(eyre::eyre!( + "currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty" + )); + } + if env.current_number == 0 { + return Err(eyre::eyre!("currentDifficulty needs to be provided for block")); + } + if env.current_timestamp <= env.parent_timestamp { + return Err(eyre::eyre!( + "currentDifficulty cannot be calculated -- currentTime ({}) needs to be after parent time ({})", + env.current_timestamp, + env.parent_timestamp + )); + } + // TODO: calculate next block difficulty + return Ok(()); + } + if env.current_random.is_none() { + return Err(eyre::eyre!("post-merge requires currentRandom to be defined in env")); + } + if env.current_difficulty.is_some() && !env.current_difficulty.unwrap().is_zero() { + return Err(eyre::eyre!("post-merge difficulty must be zero (or omitted) in env")); + } + Ok(()) +} + +fn apply_cancun_checks(env: &mut PrestateEnv, chain: &ChainSpec) -> eyre::Result<()> { + if !(chain.fork(Hardfork::Cancun).active_at_block(env.current_number) && + chain.is_cancun_active_at_timestamp(env.current_timestamp)) + { + env.parent_beacon_block_root = None; + return Ok(()); + } + if env.parent_beacon_block_root.is_none() { + return Err(eyre::eyre!("post-cancun env requires parentBeaconBlockRoot to be set")); + } + Ok(()) +} + +fn apply_state_update(state_tire: &mut MptNode, db: &MemDb) -> eyre::Result<()> { + for (address, account) in &db.accounts { + let storage_root = { + let mut storage_trie = MptNode::default(); + // apply all new storage entries for the current account (address) + for (key, value) in &account.storage { + let storage_trie_index = keccak256(key.to_be_bytes::<32>()); + if value == &U256::ZERO { + storage_trie.delete(storage_trie_index.as_slice())?; + } else { + storage_trie.insert_rlp(storage_trie_index.as_slice(), *value)?; + } + } + + storage_trie.hash() + }; + let state_trie_index = keccak256(address); + let value = StateAccount { + nonce: account.info.nonce, + balance: account.info.balance, + storage_root, + code_hash: account.info.code_hash, + }; + state_tire.insert_rlp(state_trie_index.as_slice(), value)?; + } + Ok(()) +} diff --git a/bin/reth/src/commands/t8n/provider.rs b/bin/reth/src/commands/t8n/provider.rs new file mode 100644 index 000000000000..53d510e25394 --- /dev/null +++ b/bin/reth/src/commands/t8n/provider.rs @@ -0,0 +1,109 @@ +#![allow(dead_code)] +use secp256k1::SecretKey; +use serde::{Deserialize, Serialize}; + +use reth_primitives::{ + Address, Bloom, Bytes, Receipt, TransactionSigned, Withdrawal, B256, U256, U64, +}; +use reth_revm::revm::primitives::HashMap; +use reth_rpc_types::Transaction; + +#[derive(Serialize, PartialEq, Eq)] +pub(crate) struct RejectedTx { + pub(crate) index: usize, + pub(crate) error: String, +} + +#[derive(Serialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ExecutionResult { + pub(crate) state_root: B256, + pub(crate) tx_root: B256, + pub(crate) receipt_root: B256, + pub(crate) logs_hash: B256, + pub(crate) bloom: Bloom, + pub(crate) receipts: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub(crate) rejected: Vec, + pub(crate) difficulty: Option, + pub(crate) gas_used: U64, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) base_fee: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) withdrawals_root: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) current_excess_blob_gas: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) current_blob_gas_used: Option, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PrestateAccount { + #[serde(default)] + pub(crate) balance: U256, + #[serde(default)] + pub(crate) nonce: u64, + pub(crate) storage: HashMap, + pub(crate) code: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PrestateEnv { + pub(crate) current_coinbase: Address, + pub(crate) current_difficulty: Option, + pub(crate) current_random: Option, + pub(crate) parent_difficulty: Option, + pub(crate) parent_base_fee: Option, + pub(crate) parent_gas_used: u64, + pub(crate) parent_gas_limit: u64, + pub(crate) current_gas_limit: u64, + pub(crate) current_number: u64, + pub(crate) current_timestamp: u64, + pub(crate) parent_timestamp: u64, + pub(crate) block_hashes: HashMap, + pub(crate) ommers: Vec, + pub(crate) withdrawals: Vec, + pub(crate) current_base_fee: Option, + pub(crate) parent_uncle_hash: B256, + pub(crate) current_excess_blob_gas: Option, + pub(crate) parent_excess_blob_gas: Option, + pub(crate) parent_blob_gas_used: Option, + pub(crate) parent_beacon_block_root: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Ommer { + pub(crate) delta: u64, + pub(crate) address: Address, +} + +pub(crate) type PrestateAlloc = HashMap; +pub(crate) type Alloc = HashMap; + +// Input data from stdin +#[derive(Default, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Input { + pub(crate) alloc: Option, + pub(crate) env: Option, + pub(crate) txs: Option>, + pub(crate) tx_rlp: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct TxWithKey { + pub(crate) secret_key: Option, + #[serde(flatten)] + pub(crate) tx: Transaction, + pub(crate) protected: bool, +} + +pub(crate) struct Prestate { + pub(crate) alloc: PrestateAlloc, + pub(crate) env: PrestateEnv, + pub(crate) txs: Vec, +} diff --git a/bin/reth/src/commands/t8n/trie/account.rs b/bin/reth/src/commands/t8n/trie/account.rs new file mode 100644 index 000000000000..76f096ff74bb --- /dev/null +++ b/bin/reth/src/commands/t8n/trie/account.rs @@ -0,0 +1,59 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use alloy_rlp::{RlpDecodable, RlpEncodable, RlpMaxEncodedLen}; +use reth_primitives::{constants::EMPTY_ROOT_HASH, TxNumber, B256, KECCAK_EMPTY, U256}; +use serde::{Deserialize, Serialize}; + +/// Represents an Ethereum account within the state trie. +/// +/// The `StateAccount` struct encapsulates key details of an Ethereum account, including +/// its nonce, balance, storage root, and the hash of its associated bytecode. This +/// representation is used when interacting with or querying the Ethereum state trie. +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Serialize, + Deserialize, + RlpEncodable, + RlpDecodable, + RlpMaxEncodedLen, +)] +pub(crate) struct StateAccount { + /// The number of transactions sent from this account's address. + pub(crate) nonce: TxNumber, + /// The current balance of the account in Wei. + pub(crate) balance: U256, + /// The root of the account's storage trie, representing all stored contract data. + pub(crate) storage_root: B256, + /// The Keccak-256 hash of the account's associated bytecode (if it's a contract). + pub(crate) code_hash: B256, +} + +impl Default for StateAccount { + /// Provides default values for a [StateAccount]. + /// + /// The default account has a nonce of 0, a balance of 0 Wei, an empty storage root, + /// and an empty bytecode hash. + fn default() -> Self { + Self { + nonce: 0, + balance: U256::ZERO, + storage_root: EMPTY_ROOT_HASH, + code_hash: KECCAK_EMPTY, + } + } +} diff --git a/bin/reth/src/commands/t8n/trie/mod.rs b/bin/reth/src/commands/t8n/trie/mod.rs new file mode 100644 index 000000000000..dfbd2b24eb9c --- /dev/null +++ b/bin/reth/src/commands/t8n/trie/mod.rs @@ -0,0 +1,18 @@ +// Copyright 2023 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +mod account; +mod mpt; + +pub(crate) use self::{account::StateAccount, mpt::*}; diff --git a/bin/reth/src/commands/t8n/trie/mpt.rs b/bin/reth/src/commands/t8n/trie/mpt.rs new file mode 100644 index 000000000000..e590cc707005 --- /dev/null +++ b/bin/reth/src/commands/t8n/trie/mpt.rs @@ -0,0 +1,1053 @@ +// Copyright 2024 RISC Zero, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::{ + cell::RefCell, + cmp, + fmt::{Debug, Write}, + iter, mem, +}; + +use alloy_rlp::Encodable; +use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, B256}; +use rlp::{Decodable, DecoderError, Prototype, Rlp}; +use serde::{Deserialize, Serialize}; +use thiserror::Error as ThisError; + +/// Represents the root node of a sparse Merkle Patricia Trie. +/// +/// The "sparse" nature of this trie allows for truncation of certain unneeded parts, +/// representing them by their node hash. This design choice is particularly useful for +/// optimizing storage. However, operations targeting a truncated part will fail and +/// return an error. Another distinction of this implementation is that branches cannot +/// store values, aligning with the construction of MPTs in Ethereum. +#[derive(Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)] +pub(crate) struct MptNode { + /// The type and data of the node. + data: MptNodeData, + /// Cache for a previously computed reference of this node. This is skipped during + /// serialization. + #[serde(skip)] + cached_reference: RefCell>, +} + +/// Represents custom error types for the sparse Merkle Patricia Trie (MPT). +/// +/// These errors cover various scenarios that can occur during trie operations, such as +/// encountering unresolved nodes, finding values in branches where they shouldn't be, and +/// issues related to RLP (Recursive Length Prefix) encoding and decoding. +#[derive(Debug, ThisError)] +pub(crate) enum Error { + /// Triggered when an operation reaches an unresolved node. The associated `B256` + /// value provides details about the unresolved node. + #[error("reached an unresolved node: {0:#}")] + NodeNotResolved(B256), + /// Occurs when a value is unexpectedly found in a branch node. + #[error("branch node with value")] + ValueInBranch, + /// Represents errors related to the RLP encoding and decoding using the `alloy_rlp` + /// library. + #[error("RLP error")] + Rlp(#[from] alloy_rlp::Error), + /// Represents errors related to the RLP encoding and decoding, specifically legacy + /// errors. + #[error("RLP error")] + LegacyRlp(#[from] DecoderError), +} + +impl From for MptNode { + fn from(digest: B256) -> Self { + match digest { + EMPTY_ROOT_HASH | B256::ZERO => MptNode::default(), + _ => MptNodeData::Digest(digest).into(), + } + } +} + +/// Represents the various types of data that can be stored within a node in the sparse +/// Merkle Patricia Trie (MPT). +/// +/// Each node in the trie can be of one of several types, each with its own specific data +/// structure. This enum provides a clear and type-safe way to represent the data +/// associated with each node type. +#[derive(Clone, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)] +pub(crate) enum MptNodeData { + /// Represents an empty trie node. + #[default] + Null, + /// A node that can have up to 16 children. Each child is an optional boxed [MptNode]. + Branch([Option>; 16]), + /// A leaf node that contains a key and a value, both represented as byte vectors. + Leaf(Vec, Vec), + /// A node that has exactly one child and is used to represent a shared prefix of + /// several keys. + Extension(Vec, Box), + /// Represents a sub-trie by its hash, allowing for efficient storage of large + /// sub-tries without storing their entire content. + Digest(B256), +} + +/// Represents the ways in which one node can reference another node inside the sparse +/// Merkle Patricia Trie (MPT). +/// +/// Nodes in the MPT can reference other nodes either directly through their byte +/// representation or indirectly through a hash of their encoding. This enum provides a +/// clear and type-safe way to represent these references. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)] +pub(crate) enum MptNodeReference { + /// Represents a direct reference to another node using its byte encoding. Typically + /// used for short encodings that are less than 32 bytes in length. + Bytes(Vec), + /// Represents an indirect reference to another node using the Keccak hash of its long + /// encoding. Used for encodings that are not less than 32 bytes in length. + Digest(B256), +} + +/// Provides a conversion from [MptNodeData] to [MptNode]. +/// +/// This implementation allows for conversion from [MptNodeData] to [MptNode], +/// initializing the `data` field with the provided value and setting the +/// `cached_reference` field to `None`. +impl From for MptNode { + fn from(value: MptNodeData) -> Self { + Self { data: value, cached_reference: RefCell::new(None) } + } +} + +/// Provides encoding functionalities for the `MptNode` type. +/// +/// This implementation allows for the serialization of an [MptNode] into its RLP-encoded +/// form. The encoding is done based on the type of node data ([MptNodeData]) it holds. +impl Encodable for MptNode { + /// Encodes the node into the provided `out` buffer. + /// + /// The encoding is done using the Recursive Length Prefix (RLP) encoding scheme. The + /// method handles different node data types and encodes them accordingly. + #[inline] + fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { + match &self.data { + MptNodeData::Null => { + out.put_u8(alloy_rlp::EMPTY_STRING_CODE); + } + MptNodeData::Branch(nodes) => { + alloy_rlp::Header { list: true, payload_length: self.payload_length() }.encode(out); + nodes.iter().for_each(|child| match child { + Some(node) => node.reference_encode(out), + None => out.put_u8(alloy_rlp::EMPTY_STRING_CODE), + }); + // in the MPT reference, branches have values so always add empty value + out.put_u8(alloy_rlp::EMPTY_STRING_CODE); + } + MptNodeData::Leaf(prefix, value) => { + alloy_rlp::Header { list: true, payload_length: self.payload_length() }.encode(out); + prefix.as_slice().encode(out); + value.as_slice().encode(out); + } + MptNodeData::Extension(prefix, node) => { + alloy_rlp::Header { list: true, payload_length: self.payload_length() }.encode(out); + prefix.as_slice().encode(out); + node.reference_encode(out); + } + MptNodeData::Digest(digest) => { + digest.encode(out); + } + } + } + + /// Returns the length of the encoded node in bytes. + /// + /// This method calculates the length of the RLP-encoded node. It's useful for + /// determining the size requirements for storage or transmission. + #[inline] + fn length(&self) -> usize { + let payload_length = self.payload_length(); + payload_length + alloy_rlp::length_of_length(payload_length) + } +} + +/// Provides decoding functionalities for the [MptNode] type. +/// +/// This implementation allows for the deserialization of an RLP-encoded [MptNode] back +/// into its original form. The decoding is done based on the prototype of the RLP data, +/// ensuring that the node is reconstructed accurately. +/// +/// **Note**: This implementation is still using the older RLP library and needs to be +/// migrated to `alloy_rlp` in the future. +// TODO: migrate to alloy_rlp +impl Decodable for MptNode { + /// Decodes an RLP-encoded node from the provided `rlp` buffer. + /// + /// The method handles different RLP prototypes and reconstructs the `MptNode` based + /// on the encoded data. If the RLP data does not match any known prototype or if + /// there's an error during decoding, an error is returned. + fn decode(rlp: &Rlp<'_>) -> Result { + match rlp.prototype()? { + Prototype::Null | Prototype::Data(0) => Ok(MptNodeData::Null.into()), + Prototype::List(2) => { + let path: Vec = rlp.val_at(0)?; + let prefix = path[0]; + if (prefix & (2 << 4)) == 0 { + let node: MptNode = Decodable::decode(&rlp.at(1)?)?; + Ok(MptNodeData::Extension(path, Box::new(node)).into()) + } else { + Ok(MptNodeData::Leaf(path, rlp.val_at(1)?).into()) + } + } + Prototype::List(17) => { + let mut node_list = Vec::with_capacity(16); + for node_rlp in rlp.iter().take(16) { + match node_rlp.prototype()? { + Prototype::Null | Prototype::Data(0) => { + node_list.push(None); + } + _ => node_list.push(Some(Box::new(Decodable::decode(&node_rlp)?))), + } + } + let value: Vec = rlp.val_at(16)?; + if value.is_empty() { + Ok(MptNodeData::Branch(node_list.try_into().unwrap()).into()) + } else { + Err(DecoderError::Custom("branch node with value")) + } + } + Prototype::Data(32) => { + let bytes: Vec = rlp.as_val()?; + Ok(MptNodeData::Digest(B256::from_slice(&bytes)).into()) + } + _ => Err(DecoderError::RlpIncorrectListLen), + } + } +} + +/// Represents a node in the sparse Merkle Patricia Trie (MPT). +/// +/// The [MptNode] type encapsulates the data and functionalities associated with a node in +/// the MPT. It provides methods for manipulating the trie, such as inserting, deleting, +/// and retrieving values, as well as utility methods for encoding, decoding, and +/// debugging. +impl MptNode { + /// Clears the trie, replacing its data with an empty node, [MptNodeData::Null]. + /// + /// This method effectively removes all key-value pairs from the trie. + #[inline] + pub(crate) fn clear(&mut self) { + self.data = MptNodeData::Null; + self.invalidate_ref_cache(); + } + + /// Decodes an RLP-encoded [MptNode] from the provided byte slice. + /// + /// This method allows for the deserialization of a previously serialized [MptNode]. + #[inline] + pub(crate) fn decode(bytes: impl AsRef<[u8]>) -> Result { + rlp::decode(bytes.as_ref()).map_err(Error::from) + } + + /// Retrieves the underlying data of the node. + /// + /// This method provides a reference to the node's data, allowing for inspection and + /// manipulation. + #[inline] + pub(crate) fn as_data(&self) -> &MptNodeData { + &self.data + } + + /// Retrieves the [MptNodeReference] reference of the node when it's referenced inside + /// another node. + /// + /// This method provides a way to obtain a compact representation of the node for + /// storage or transmission purposes. + #[inline] + pub(crate) fn reference(&self) -> MptNodeReference { + self.cached_reference.borrow_mut().get_or_insert_with(|| self.calc_reference()).clone() + } + + /// Computes and returns the 256-bit hash of the node. + /// + /// This method provides a unique identifier for the node based on its content. + #[inline] + pub(crate) fn hash(&self) -> B256 { + match self.data { + MptNodeData::Null => EMPTY_ROOT_HASH, + _ => match self + .cached_reference + .borrow_mut() + .get_or_insert_with(|| self.calc_reference()) + { + MptNodeReference::Digest(digest) => *digest, + MptNodeReference::Bytes(bytes) => keccak256(bytes).into(), + }, + } + } + + /// Encodes the [MptNodeReference] of this node into the `out` buffer. + fn reference_encode(&self, out: &mut dyn alloy_rlp::BufMut) { + match self.cached_reference.borrow_mut().get_or_insert_with(|| self.calc_reference()) { + // if the reference is an RLP-encoded byte slice, copy it directly + MptNodeReference::Bytes(bytes) => out.put_slice(bytes), + // if the reference is a digest, RLP-encode it with its fixed known length + MptNodeReference::Digest(digest) => { + out.put_u8(alloy_rlp::EMPTY_STRING_CODE + 32); + out.put_slice(digest.as_slice()); + } + } + } + + /// Returns the length of the encoded [MptNodeReference] of this node. + fn reference_length(&self) -> usize { + match self.cached_reference.borrow_mut().get_or_insert_with(|| self.calc_reference()) { + MptNodeReference::Bytes(bytes) => bytes.len(), + MptNodeReference::Digest(_) => 1 + 32, + } + } + + fn calc_reference(&self) -> MptNodeReference { + match &self.data { + MptNodeData::Null => MptNodeReference::Bytes(vec![alloy_rlp::EMPTY_STRING_CODE]), + MptNodeData::Digest(digest) => MptNodeReference::Digest(*digest), + _ => { + let encoded = alloy_rlp::encode(self); + if encoded.len() < 32 { + MptNodeReference::Bytes(encoded) + } else { + MptNodeReference::Digest(keccak256(encoded).into()) + } + } + } + } + + /// Determines if the trie is empty. + /// + /// This method checks if the node represents an empty trie, i.e., it doesn't contain + /// any key-value pairs. + #[inline] + pub(crate) fn is_empty(&self) -> bool { + matches!(&self.data, MptNodeData::Null) + } + + /// Determines if the node represents a digest. + /// + /// A digest is a compact representation of a sub-trie, represented by its hash. + #[inline] + pub(crate) fn is_digest(&self) -> bool { + matches!(&self.data, MptNodeData::Digest(_)) + } + + /// Retrieves the nibbles corresponding to the node's prefix. + /// + /// Nibbles are half-bytes, and in the context of the MPT, they represent parts of + /// keys. + #[inline] + pub(crate) fn nibs(&self) -> Vec { + match &self.data { + MptNodeData::Null | MptNodeData::Branch(_) | MptNodeData::Digest(_) => vec![], + MptNodeData::Leaf(prefix, _) | MptNodeData::Extension(prefix, _) => prefix_nibs(prefix), + } + } + + /// Retrieves the value associated with a given key in the trie. + /// + /// If the key is not present in the trie, this method returns `None`. Otherwise, it + /// returns a reference to the associated value. If [None] is returned, the key is + /// provably not in the trie. + #[inline] + pub(crate) fn get(&self, key: &[u8]) -> Result, Error> { + self.get_internal(&to_nibs(key)) + } + + /// Retrieves the RLP-decoded value corresponding to the key. + /// + /// If the key is not present in the trie, this method returns `None`. Otherwise, it + /// returns the RLP-decoded value. + #[inline] + pub(crate) fn get_rlp(&self, key: &[u8]) -> Result, Error> { + match self.get(key)? { + Some(mut bytes) => Ok(Some(T::decode(&mut bytes)?)), + None => Ok(None), + } + } + + fn get_internal(&self, key_nibs: &[u8]) -> Result, Error> { + match &self.data { + MptNodeData::Null => Ok(None), + MptNodeData::Branch(nodes) => { + if let Some((i, tail)) = key_nibs.split_first() { + match nodes[*i as usize] { + Some(ref node) => node.get_internal(tail), + None => Ok(None), + } + } else { + Ok(None) + } + } + MptNodeData::Leaf(prefix, value) => { + if prefix_nibs(prefix) == key_nibs { + Ok(Some(value)) + } else { + Ok(None) + } + } + MptNodeData::Extension(prefix, node) => { + if let Some(tail) = key_nibs.strip_prefix(prefix_nibs(prefix).as_slice()) { + node.get_internal(tail) + } else { + Ok(None) + } + } + MptNodeData::Digest(digest) => Err(Error::NodeNotResolved(*digest)), + } + } + + /// Removes a key from the trie. + /// + /// This method attempts to remove a key-value pair from the trie. If the key is + /// present, it returns `true`. Otherwise, it returns `false`. + #[inline] + pub(crate) fn delete(&mut self, key: &[u8]) -> Result { + self.delete_internal(&to_nibs(key)) + } + + fn delete_internal(&mut self, key_nibs: &[u8]) -> Result { + match &mut self.data { + MptNodeData::Null => return Ok(false), + MptNodeData::Branch(children) => { + if let Some((i, tail)) = key_nibs.split_first() { + let child = &mut children[*i as usize]; + match child { + Some(node) => { + if !node.delete_internal(tail)? { + return Ok(false); + } + // if the node is now empty, remove it + if node.is_empty() { + *child = None; + } + } + None => return Ok(false), + } + } else { + return Err(Error::ValueInBranch); + } + + let mut remaining = children.iter_mut().enumerate().filter(|(_, n)| n.is_some()); + // there will always be at least one remaining node + let (index, node) = remaining.next().unwrap(); + // if there is only exactly one node left, we need to convert the branch + if remaining.next().is_none() { + let mut orphan = node.take().unwrap(); + match &mut orphan.data { + // if the orphan is a leaf, prepend the corresponding nib to it + MptNodeData::Leaf(prefix, orphan_value) => { + let new_nibs: Vec<_> = + iter::once(index as u8).chain(prefix_nibs(prefix)).collect(); + self.data = MptNodeData::Leaf( + to_encoded_path(&new_nibs, true), + mem::take(orphan_value), + ); + } + // if the orphan is an extension, prepend the corresponding nib to it + MptNodeData::Extension(prefix, orphan_child) => { + let new_nibs: Vec<_> = + iter::once(index as u8).chain(prefix_nibs(prefix)).collect(); + self.data = MptNodeData::Extension( + to_encoded_path(&new_nibs, false), + mem::take(orphan_child), + ); + } + // if the orphan is a branch or digest, convert to an extension + MptNodeData::Branch(_) | MptNodeData::Digest(_) => { + self.data = MptNodeData::Extension( + to_encoded_path(&[index as u8], false), + orphan, + ); + } + MptNodeData::Null => unreachable!(), + } + } + } + MptNodeData::Leaf(prefix, _) => { + if prefix_nibs(prefix) != key_nibs { + return Ok(false); + } + self.data = MptNodeData::Null; + } + MptNodeData::Extension(prefix, child) => { + let mut self_nibs = prefix_nibs(prefix); + if let Some(tail) = key_nibs.strip_prefix(self_nibs.as_slice()) { + if !child.delete_internal(tail)? { + return Ok(false); + } + } else { + return Ok(false); + } + + // an extension can only point to a branch or a digest; since it's sub trie was + // modified, we need to make sure that this property still holds + match &mut child.data { + // if the child is empty, remove the extension + MptNodeData::Null => { + self.data = MptNodeData::Null; + } + // for a leaf, replace the extension with the extended leaf + MptNodeData::Leaf(prefix, value) => { + self_nibs.extend(prefix_nibs(prefix)); + self.data = + MptNodeData::Leaf(to_encoded_path(&self_nibs, true), mem::take(value)); + } + // for an extension, replace the extension with the extended extension + MptNodeData::Extension(prefix, node) => { + self_nibs.extend(prefix_nibs(prefix)); + self.data = MptNodeData::Extension( + to_encoded_path(&self_nibs, false), + mem::take(node), + ); + } + // for a branch or digest, the extension is still correct + MptNodeData::Branch(_) | MptNodeData::Digest(_) => {} + } + } + MptNodeData::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + }; + + self.invalidate_ref_cache(); + Ok(true) + } + + /// Inserts a key-value pair into the trie. + /// + /// This method attempts to insert a new key-value pair into the trie. If the + /// insertion is successful, it returns `true`. If the key already exists, it updates + /// the value and returns `false`. + #[inline] + pub(crate) fn insert(&mut self, key: &[u8], value: Vec) -> Result { + if value.is_empty() { + panic!("value must not be empty"); + } + self.insert_internal(&to_nibs(key), value) + } + + /// Inserts an RLP-encoded value into the trie. + /// + /// This method inserts a value that's been encoded using RLP into the trie. + #[inline] + pub(crate) fn insert_rlp(&mut self, key: &[u8], value: impl Encodable) -> Result { + self.insert_internal(&to_nibs(key), alloy_rlp::encode(value)) + } + + fn insert_internal(&mut self, key_nibs: &[u8], value: Vec) -> Result { + match &mut self.data { + MptNodeData::Null => { + self.data = MptNodeData::Leaf(to_encoded_path(key_nibs, true), value); + } + MptNodeData::Branch(children) => { + if let Some((i, tail)) = key_nibs.split_first() { + let child = &mut children[*i as usize]; + match child { + Some(node) => { + if !node.insert_internal(tail, value)? { + return Ok(false); + } + } + // if the corresponding child is empty, insert a new leaf + None => { + *child = Some(Box::new( + MptNodeData::Leaf(to_encoded_path(tail, true), value).into(), + )); + } + } + } else { + return Err(Error::ValueInBranch); + } + } + MptNodeData::Leaf(prefix, old_value) => { + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() && common_len == key_nibs.len() { + // if self_nibs == key_nibs, update the value if it is different + if old_value == &value { + return Ok(false); + } + *old_value = value; + } else if common_len == self_nibs.len() || common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let split_point = common_len + 1; + // otherwise, create a branch with two children + let mut children: [Option>; 16] = Default::default(); + + children[self_nibs[common_len] as usize] = Some(Box::new( + MptNodeData::Leaf( + to_encoded_path(&self_nibs[split_point..], true), + mem::take(old_value), + ) + .into(), + )); + children[key_nibs[common_len] as usize] = Some(Box::new( + MptNodeData::Leaf(to_encoded_path(&key_nibs[split_point..], true), value) + .into(), + )); + + let branch = MptNodeData::Branch(children); + if common_len > 0 { + // create parent extension for new branch + self.data = MptNodeData::Extension( + to_encoded_path(&self_nibs[..common_len], false), + Box::new(branch.into()), + ); + } else { + self.data = branch; + } + } + } + MptNodeData::Extension(prefix, existing_child) => { + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() { + // traverse down for update + if !existing_child.insert_internal(&key_nibs[common_len..], value)? { + return Ok(false); + } + } else if common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let split_point = common_len + 1; + // otherwise, create a branch with two children + let mut children: [Option>; 16] = Default::default(); + + children[self_nibs[common_len] as usize] = if split_point < self_nibs.len() { + Some(Box::new( + MptNodeData::Extension( + to_encoded_path(&self_nibs[split_point..], false), + mem::take(existing_child), + ) + .into(), + )) + } else { + Some(mem::take(existing_child)) + }; + children[key_nibs[common_len] as usize] = Some(Box::new( + MptNodeData::Leaf(to_encoded_path(&key_nibs[split_point..], true), value) + .into(), + )); + + let branch = MptNodeData::Branch(children); + if common_len > 0 { + // Create parent extension for new branch + self.data = MptNodeData::Extension( + to_encoded_path(&self_nibs[..common_len], false), + Box::new(branch.into()), + ); + } else { + self.data = branch; + } + } + } + MptNodeData::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + }; + + self.invalidate_ref_cache(); + Ok(true) + } + + fn invalidate_ref_cache(&mut self) { + self.cached_reference.borrow_mut().take(); + } + + /// Returns the number of traversable nodes in the trie. + /// + /// This method provides a count of all the nodes that can be traversed within the + /// trie. + pub(crate) fn size(&self) -> usize { + match self.as_data() { + MptNodeData::Null => 0, + MptNodeData::Branch(children) => { + children.iter().flatten().map(|n| n.size()).sum::() + 1 + } + MptNodeData::Leaf(_, _) => 1, + MptNodeData::Extension(_, child) => child.size() + 1, + MptNodeData::Digest(_) => 0, + } + } + + /// Formats the trie as a string list, where each line corresponds to a trie leaf. + /// + /// This method is primarily used for debugging purposes, providing a visual + /// representation of the trie's structure. + pub(crate) fn debug_rlp(&self) -> Vec { + // convert the nibs to hex + let nibs: String = self.nibs().iter().fold(String::new(), |mut output, n| { + let _ = write!(output, "{:x}", n); + output + }); + + match self.as_data() { + MptNodeData::Null => vec![format!("{:?}", MptNodeData::Null)], + MptNodeData::Branch(children) => children + .iter() + .enumerate() + .flat_map(|(i, child)| { + match child { + Some(node) => node.debug_rlp::(), + None => vec!["None".to_string()], + } + .into_iter() + .map(move |s| format!("{:x} {}", i, s)) + }) + .collect(), + MptNodeData::Leaf(_, data) => { + vec![format!("{} -> {:?}", nibs, T::decode(&mut &data[..]).unwrap())] + } + MptNodeData::Extension(_, node) => { + node.debug_rlp::().into_iter().map(|s| format!("{} {}", nibs, s)).collect() + } + MptNodeData::Digest(digest) => vec![format!("#{:#}", digest)], + } + } + + /// Returns the length of the RLP payload of the node. + fn payload_length(&self) -> usize { + match &self.data { + MptNodeData::Null => 0, + MptNodeData::Branch(nodes) => { + 1 + nodes + .iter() + .map(|child| child.as_ref().map_or(1, |node| node.reference_length())) + .sum::() + } + MptNodeData::Leaf(prefix, value) => { + prefix.as_slice().length() + value.as_slice().length() + } + MptNodeData::Extension(prefix, node) => { + prefix.as_slice().length() + node.reference_length() + } + MptNodeData::Digest(_) => 32, + } + } +} + +/// Converts a byte slice into a vector of nibbles. +/// +/// A nibble is 4 bits or half of an 8-bit byte. This function takes each byte from the +/// input slice, splits it into two nibbles, and appends them to the resulting vector. +pub(crate) fn to_nibs(slice: &[u8]) -> Vec { + let mut result = Vec::with_capacity(2 * slice.len()); + for byte in slice { + result.push(byte >> 4); + result.push(byte & 0xf); + } + result +} + +/// Encodes a slice of nibbles into a vector of bytes, with an additional prefix to +/// indicate the type of node (leaf or extension). +/// +/// The function starts by determining the type of node based on the `is_leaf` parameter. +/// If the node is a leaf, the prefix is set to `0x20`. If the length of the nibbles is +/// odd, the prefix is adjusted and the first nibble is incorporated into it. +/// +/// The remaining nibbles are then combined into bytes, with each pair of nibbles forming +/// a single byte. The resulting vector starts with the prefix, followed by the encoded +/// bytes. +pub(crate) fn to_encoded_path(mut nibs: &[u8], is_leaf: bool) -> Vec { + let mut prefix = (is_leaf as u8) * 0x20; + if nibs.len() % 2 != 0 { + prefix += 0x10 + nibs[0]; + nibs = &nibs[1..]; + } + iter::once(prefix).chain(nibs.chunks_exact(2).map(|byte| (byte[0] << 4) + byte[1])).collect() +} + +/// Returns the length of the common prefix. +fn lcp(a: &[u8], b: &[u8]) -> usize { + for (i, (a, b)) in iter::zip(a, b).enumerate() { + if a != b { + return i; + } + } + cmp::min(a.len(), b.len()) +} + +fn prefix_nibs(prefix: &[u8]) -> Vec { + let (extension, tail) = prefix.split_first().unwrap(); + // the first bit of the first nibble denotes the parity + let is_odd = extension & (1 << 4) != 0; + + let mut result = Vec::with_capacity(2 * tail.len() + is_odd as usize); + // for odd lengths, the second nibble contains the first element + if is_odd { + result.push(extension & 0xf); + } + for nib in tail { + result.push(nib >> 4); + result.push(nib & 0xf); + } + result +} + +#[cfg(test)] +mod tests { + use hex_literal::hex; + + use super::*; + + #[test] + fn test_trie_pointer_no_keccak() { + let cases = [("do", "verb"), ("dog", "puppy"), ("doge", "coin"), ("horse", "stallion")]; + for (k, v) in cases { + let node: MptNode = + MptNodeData::Leaf(k.as_bytes().to_vec(), v.as_bytes().to_vec()).into(); + assert!( + matches!(node.reference(),MptNodeReference::Bytes(bytes) if bytes == alloy_rlp::encode(&node)) + ); + } + } + + #[test] + fn test_to_encoded_path() { + // extension node with an even path length + let nibbles = vec![0x0a, 0x0b, 0x0c, 0x0d]; + assert_eq!(to_encoded_path(&nibbles, false), vec![0x00, 0xab, 0xcd]); + // extension node with an odd path length + let nibbles = vec![0x0a, 0x0b, 0x0c]; + assert_eq!(to_encoded_path(&nibbles, false), vec![0x1a, 0xbc]); + // leaf node with an even path length + let nibbles = vec![0x0a, 0x0b, 0x0c, 0x0d]; + assert_eq!(to_encoded_path(&nibbles, true), vec![0x20, 0xab, 0xcd]); + // leaf node with an odd path length + let nibbles = vec![0x0a, 0x0b, 0x0c]; + assert_eq!(to_encoded_path(&nibbles, true), vec![0x3a, 0xbc]); + } + + #[test] + fn test_lcp() { + let cases = [ + (vec![], vec![], 0), + (vec![0xa], vec![0xa], 1), + (vec![0xa, 0xb], vec![0xa, 0xc], 1), + (vec![0xa, 0xb], vec![0xa, 0xb], 2), + (vec![0xa, 0xb], vec![0xa, 0xb, 0xc], 2), + (vec![0xa, 0xb, 0xc], vec![0xa, 0xb, 0xc], 3), + (vec![0xa, 0xb, 0xc], vec![0xa, 0xb, 0xc, 0xd], 3), + (vec![0xa, 0xb, 0xc, 0xd], vec![0xa, 0xb, 0xc, 0xd], 4), + ]; + for (a, b, cpl) in cases { + assert_eq!(lcp(&a, &b), cpl) + } + } + + #[test] + fn test_empty() { + let trie = MptNode::default(); + + assert!(trie.is_empty()); + assert_eq!(trie.reference(), MptNodeReference::Bytes(vec![0x80])); + let expected = hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); + assert_eq!(expected, trie.hash().0); + + // test RLP encoding + let mut out = Vec::new(); + trie.encode(&mut out); + assert_eq!(out, vec![0x80]); + assert_eq!(trie.length(), out.len()); + let decoded = MptNode::decode(out).unwrap(); + assert_eq!(trie.hash(), decoded.hash()); + } + + #[test] + fn test_empty_key() { + let mut trie = MptNode::default(); + + trie.insert(&[], b"empty".to_vec()).unwrap(); + assert_eq!(trie.get(&[]).unwrap(), Some(b"empty".as_ref())); + assert!(trie.delete(&[]).unwrap()); + } + + #[test] + fn test_clear() { + let mut trie = MptNode::default(); + trie.insert(b"dog", b"puppy".to_vec()).unwrap(); + assert!(!trie.is_empty()); + assert_ne!(trie.hash(), EMPTY_ROOT_HASH); + + trie.clear(); + assert!(trie.is_empty()); + assert_eq!(trie.hash(), EMPTY_ROOT_HASH); + } + + #[test] + fn test_tiny() { + // trie consisting of an extension, a branch and two leafs + let mut trie = MptNode::default(); + trie.insert_rlp(b"a", 0u8).unwrap(); + trie.insert_rlp(b"b", 1u8).unwrap(); + + assert!(!trie.is_empty()); + let exp_rlp = hex!("d816d680c3208180c220018080808080808080808080808080"); + assert_eq!(trie.reference(), MptNodeReference::Bytes(exp_rlp.to_vec())); + let exp_hash = hex!("6fbf23d6ec055dd143ff50d558559770005ff44ae1d41276f1bd83affab6dd3b"); + assert_eq!(trie.hash().0, exp_hash); + + // test RLP encoding + let mut out = Vec::new(); + trie.encode(&mut out); + assert_eq!(out, exp_rlp.to_vec()); + assert_eq!(trie.length(), out.len()); + let decoded = MptNode::decode(out).unwrap(); + assert_eq!(trie.hash(), decoded.hash()); + } + + #[test] + fn test_partial() { + let mut trie = MptNode::default(); + trie.insert_rlp(b"aa", 0u8).unwrap(); + trie.insert_rlp(b"ab", 1u8).unwrap(); + trie.insert_rlp(b"ba", 2u8).unwrap(); + + let exp_hash = trie.hash(); + + // replace one node with its digest + let MptNodeData::Extension(_, node) = &mut trie.data else { panic!("extension expected") }; + **node = MptNodeData::Digest(node.hash()).into(); + assert!(node.is_digest()); + + let trie = MptNode::decode(alloy_rlp::encode(&trie)).unwrap(); + assert_eq!(trie.hash(), exp_hash); + + // lookups should fail + trie.get(b"aa").unwrap_err(); + trie.get(b"a0").unwrap_err(); + } + + #[test] + fn test_branch_value() { + let mut trie = MptNode::default(); + trie.insert(b"do", b"verb".to_vec()).unwrap(); + // leads to a branch with value which is not supported + trie.insert(b"dog", b"puppy".to_vec()).unwrap_err(); + } + + #[test] + fn test_insert() { + let mut trie = MptNode::default(); + let vals = vec![ + ("painting", "place"), + ("guest", "ship"), + ("mud", "leave"), + ("paper", "call"), + ("gate", "boast"), + ("tongue", "gain"), + ("baseball", "wait"), + ("tale", "lie"), + ("mood", "cope"), + ("menu", "fear"), + ]; + for (key, val) in &vals { + assert!(trie.insert(key.as_bytes(), val.as_bytes().to_vec()).unwrap()); + } + + let expected = hex!("2bab6cdf91a23ebf3af683728ea02403a98346f99ed668eec572d55c70a4b08f"); + assert_eq!(expected, trie.hash().0); + + for (key, value) in &vals { + assert_eq!(trie.get(key.as_bytes()).unwrap(), Some(value.as_bytes())); + } + + // check inserting duplicate keys + assert!(trie.insert(vals[0].0.as_bytes(), b"new".to_vec()).unwrap()); + assert!(!trie.insert(vals[0].0.as_bytes(), b"new".to_vec()).unwrap()); + + // try RLP roundtrip + let decoded = MptNode::decode(alloy_rlp::encode(&trie)).unwrap(); + assert_eq!(trie.hash(), decoded.hash()); + } + + #[test] + fn test_keccak_trie() { + const N: usize = 512; + + // insert + let mut trie = MptNode::default(); + for i in 0..N { + assert!(trie.insert_rlp(&keccak256(i.to_be_bytes()), i).unwrap()); + + // check hash against trie build in reverse + let mut reference = MptNode::default(); + for j in (0..=i).rev() { + reference.insert_rlp(&keccak256(j.to_be_bytes()), j).unwrap(); + } + assert_eq!(trie.hash(), reference.hash()); + } + + let expected = hex!("7310027edebdd1f7c950a7fb3413d551e85dff150d45aca4198c2f6315f9b4a7"); + assert_eq!(trie.hash().0, expected); + + // get + for i in 0..N { + assert_eq!(trie.get_rlp(&keccak256(i.to_be_bytes())).unwrap(), Some(i)); + assert!(trie.get(&keccak256((i + N).to_be_bytes())).unwrap().is_none()); + } + + // delete + for i in 0..N { + assert!(trie.delete(&keccak256(i.to_be_bytes())).unwrap()); + + let mut reference = MptNode::default(); + for j in ((i + 1)..N).rev() { + reference.insert_rlp(&keccak256(j.to_be_bytes()), j).unwrap(); + } + assert_eq!(trie.hash(), reference.hash()); + } + assert!(trie.is_empty()); + } + + #[test] + fn test_index_trie() { + const N: usize = 512; + + // insert + let mut trie = MptNode::default(); + for i in 0..N { + assert!(trie.insert_rlp(&alloy_rlp::encode(i), i).unwrap()); + + // check hash against trie build in reverse + let mut reference = MptNode::default(); + for j in (0..=i).rev() { + reference.insert_rlp(&alloy_rlp::encode(j), j).unwrap(); + } + assert_eq!(trie.hash(), reference.hash()); + + // try RLP roundtrip + let decoded = MptNode::decode(alloy_rlp::encode(&trie)).unwrap(); + assert_eq!(trie.hash(), decoded.hash()); + } + + // get + for i in 0..N { + assert_eq!(trie.get_rlp(&alloy_rlp::encode(i)).unwrap(), Some(i)); + assert!(trie.get(&alloy_rlp::encode(i + N)).unwrap().is_none()); + } + + // delete + for i in 0..N { + assert!(trie.delete(&alloy_rlp::encode(i)).unwrap()); + + let mut reference = MptNode::default(); + for j in ((i + 1)..N).rev() { + reference.insert_rlp(&alloy_rlp::encode(j), j).unwrap(); + } + assert_eq!(trie.hash(), reference.hash()); + } + assert!(trie.is_empty()); + } +} diff --git a/bin/reth/src/commands/t8n/utils.rs b/bin/reth/src/commands/t8n/utils.rs new file mode 100644 index 000000000000..ff015b8466d7 --- /dev/null +++ b/bin/reth/src/commands/t8n/utils.rs @@ -0,0 +1,172 @@ +use eyre::{eyre, ContextCompat, Report}; +#[cfg(feature = "optimism")] +use reth_primitives::TxDeposit; +use reth_primitives::{ + sign_message, Address, Signature as PrimitiveSignature, Transaction as PrimitiveTransaction, + TransactionKind, TransactionSigned, TxEip1559, TxEip2930, TxEip4844, TxLegacy, TxType, B256, + U256, +}; +#[cfg(feature = "optimism")] +use reth_rpc_types::optimism::OptimismTransactionFields; +use reth_rpc_types::{AccessList, Signature, Transaction}; +use secp256k1::SecretKey; + +// Get the `odd_y_parity` from the `v` value depends on chain_id +#[inline] +fn get_odd_y_parity(v: u64, chain_id: Option) -> bool { + if let Some(chain_id) = chain_id { + // EIP-155: v = {0, 1} + CHAIN_ID * 2 + 35 + v - chain_id * 2 - 35 == 1 + } else { + v - 27 == 1 + } +} + +fn to_legacy_primitive_signature( + signature: Signature, + chain_id: Option, +) -> PrimitiveSignature { + PrimitiveSignature { + r: signature.r, + s: signature.s, + odd_y_parity: get_odd_y_parity(signature.v.to(), chain_id), + } +} + +fn to_primitive_transaction_kind(to: Option
) -> TransactionKind { + match to { + Some(to) => TransactionKind::Call(to), + None => TransactionKind::Create, + } +} + +fn to_typed_primitive_signature(signature: Signature) -> PrimitiveSignature { + PrimitiveSignature { + r: signature.r, + s: signature.s, + odd_y_parity: signature.v == U256::from(1), + } +} + +fn to_primitive_signature( + signature: Signature, + tx_type: TxType, + chain_id: Option, +) -> PrimitiveSignature { + match tx_type { + TxType::Legacy => to_legacy_primitive_signature(signature, chain_id), + _ => to_typed_primitive_signature(signature), + } +} +#[cfg(feature = "optimism")] +fn try_into_optimism_fields(other: OtherFields) -> eyre::Result { + let value = serde_json::to_value(other)?; + Ok(serde_json::from_value(value)?) +} + +/// Convert [Transaction] to [TransactionSigned] +pub(crate) fn try_into_primitive_transaction_and_sign( + tx: Transaction, + secret: &Option, +) -> eyre::Result { + let tx_type: TxType = tx + .transaction_type + .map(|v| v.to::()) + .unwrap_or_default() + .try_into() + .map_err(Report::msg)?; + let chain_id = tx.chain_id.map(|v| v.to()); + let transaction = match tx_type { + TxType::Legacy => PrimitiveTransaction::Legacy(TxLegacy { + chain_id, + nonce: tx.nonce.to(), + gas_price: tx.gas_price.map(|v| v.to()).context("missing gas_price")?, + gas_limit: tx.gas.to(), + to: to_primitive_transaction_kind(tx.to), + value: tx.value, + input: tx.input, + }), + TxType::Eip2930 => PrimitiveTransaction::Eip2930(TxEip2930 { + chain_id: chain_id.context("missing chain_id")?, + nonce: tx.nonce.to(), + gas_price: tx.gas_price.map(|v| v.to()).context("missing gas_price")?, + gas_limit: tx.gas.to(), + to: to_primitive_transaction_kind(tx.to), + value: tx.value, + access_list: tx + .access_list + .map(|v| AccessList(v).into()) + .context("missing access_list")?, + input: tx.input, + }), + TxType::Eip1559 => PrimitiveTransaction::Eip1559(TxEip1559 { + chain_id: chain_id.context("missing chain_id")?, + nonce: tx.nonce.to(), + gas_limit: tx.gas.to(), + max_fee_per_gas: tx + .max_fee_per_gas + .map(|v| v.to()) + .context("missing max_fee_per_gas")?, + max_priority_fee_per_gas: tx + .max_priority_fee_per_gas + .map(|v| v.to()) + .context("missing max_priority_fee_per_gas")?, + to: to_primitive_transaction_kind(tx.to), + value: tx.value, + access_list: tx + .access_list + .map(|v| AccessList(v).into()) + .context("missing access_list")?, + input: tx.input, + is_anchor: false, + }), + TxType::Eip4844 => PrimitiveTransaction::Eip4844(TxEip4844 { + chain_id: chain_id.context("missing chain_id")?, + nonce: tx.nonce.to(), + gas_limit: tx.gas.to(), + max_fee_per_gas: tx + .max_fee_per_gas + .map(|v| v.to()) + .context("missing max_fee_per_gas")?, + max_priority_fee_per_gas: tx + .max_priority_fee_per_gas + .map(|v| v.to()) + .context("missing max_priority_fee_per_gas")?, + to: to_primitive_transaction_kind(tx.to), + value: tx.value, + access_list: tx + .access_list + .map(|v| AccessList(v).into()) + .context("missing access_list")?, + input: tx.input, + blob_versioned_hashes: tx.blob_versioned_hashes, + max_fee_per_blob_gas: tx + .max_fee_per_blob_gas + .map(|v| v.to()) + .context("missing max_fee_per_blob_gas")?, + }), + #[cfg(feature = "optimism")] + TxType::Deposit => { + let other = try_into_optimism_fields(tx.other)?; + PrimitiveTransaction::Deposit(TxDeposit { + source_hash: other.source_hash.context("missing source_hash")?, + from: tx.from, + to: to_primitive_transaction_kind(tx.to), + mint: other.mint.map(|v| v.to()), + value: tx.value, + gas_limit: tx.gas.to(), + is_system_transaction: other.is_system_tx.context("missing is_system_tx")?, + input: tx.input, + }) + } + }; + let signature = match (tx.signature, secret) { + (Some(signature), _) => to_primitive_signature(signature, tx_type, chain_id), + (None, Some(secret)) => { + let hash = transaction.signature_hash(); + sign_message(B256::from_slice(secret.as_ref()), hash)? + } + _ => return Err(eyre!("missing signature({:?}) or secret({:?})", tx.signature, secret)), + }; + Ok(TransactionSigned::from_transaction_and_signature(transaction, signature)) +} diff --git a/bin/reth/src/lib.rs b/bin/reth/src/lib.rs index 7c024438ae27..c725b033b2c0 100644 --- a/bin/reth/src/lib.rs +++ b/bin/reth/src/lib.rs @@ -32,7 +32,15 @@ pub mod cli; pub mod commands; mod macros; -pub mod utils; + +/// Re-exported utils. +pub mod utils { + pub use reth_db::open_db_read_only; + + /// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment + /// on the `reth_node_core::args` re-export for more details. + pub use reth_node_core::utils::*; +} /// Re-exported payload related types pub mod payload { @@ -140,6 +148,15 @@ pub mod rpc { pub use reth_rpc_types::*; } + /// Re-exported from `reth_rpc_server_types`. + pub mod server_types { + pub use reth_rpc_server_types::*; + /// Re-exported from `reth_rpc_eth_types`. + pub mod eth { + pub use reth_rpc_eth_types::*; + } + } + /// Re-exported from `reth_rpc_api`. pub mod api { pub use reth_rpc_api::*; @@ -151,10 +168,10 @@ pub mod rpc { /// Re-exported from `reth_rpc::rpc`. pub mod result { - pub use reth_rpc::result::*; + pub use reth_rpc_server_types::result::*; } - /// Re-exported from `reth_rpc::eth`. + /// Re-exported from `reth_rpc_types_compat`. pub mod compat { pub use reth_rpc_types_compat::*; } diff --git a/bin/reth/src/taiko.rs b/bin/reth/src/taiko.rs new file mode 100644 index 000000000000..b88d5aa525bf --- /dev/null +++ b/bin/reth/src/taiko.rs @@ -0,0 +1,32 @@ +#![allow(missing_docs, rustdoc::missing_crate_level_docs)] + +use reth::cli::Cli; + +// We use jemalloc for performance reasons +#[cfg(all(feature = "jemalloc", unix))] +#[global_allocator] +static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; + +#[cfg(not(feature = "taiko"))] +compile_error!("Cannot build the `taiko-reth` binary with the `taiko` feature flag disabled. Did you mean to build `reth`?"); + +#[cfg(feature = "taiko")] +fn main() { + use reth_node_taiko::TaikoNode; + + reth::sigsegv_handler::install(); + + // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. + if std::env::var_os("RUST_BACKTRACE").is_none() { + std::env::set_var("RUST_BACKTRACE", "1"); + } + + if let Err(err) = Cli::parse_args().run(|builder, _| async move { + let handle = builder.launch_node(TaikoNode::new()).await?; + + handle.node_exit_future.await + }) { + eprintln!("Error: {err:?}"); + std::process::exit(1); + } +} diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 499b6dd97f9a..ad1a54633674 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -72,6 +72,7 @@ - [`reth debug replay-engine`](./cli/reth/debug/replay-engine.md) - [`reth recover`](./cli/reth/recover.md) - [`reth recover storage-tries`](./cli/reth/recover/storage-tries.md) + - [`reth prune`](./cli/reth/prune.md) - [Developers](./developers/developers.md) - [Execution Extensions](./developers/exex/exex.md) - [How do ExExes work?](./developers/exex/how-it-works.md) diff --git a/book/cli/SUMMARY.md b/book/cli/SUMMARY.md index 089de1b65a67..9f9d0fdb1dc3 100644 --- a/book/cli/SUMMARY.md +++ b/book/cli/SUMMARY.md @@ -43,4 +43,5 @@ - [`reth debug replay-engine`](./reth/debug/replay-engine.md) - [`reth recover`](./reth/recover.md) - [`reth recover storage-tries`](./reth/recover/storage-tries.md) + - [`reth prune`](./reth/prune.md) diff --git a/book/cli/reth.md b/book/cli/reth.md index a4ba8f3d3d9c..b8ac550816d0 100644 --- a/book/cli/reth.md +++ b/book/cli/reth.md @@ -19,6 +19,7 @@ Commands: config Write config to stdout debug Various debug routines recover Scripts for node recovery + prune Prune according to the configuration without any limits help Print this message or the help of the given subcommand(s) Options: diff --git a/book/cli/reth/prune.md b/book/cli/reth/prune.md new file mode 100644 index 000000000000..77ea724abd88 --- /dev/null +++ b/book/cli/reth/prune.md @@ -0,0 +1,146 @@ +# reth prune + +Prune according to the configuration without any limits + +```bash +$ reth prune --help +Usage: reth prune [OPTIONS] + +Options: + --instance + Add a new instance of a node. + + Configures the ports of the node to avoid conflicts with the defaults. This is useful for running multiple nodes on the same machine. + + Max number of instances is 200. It is chosen in a way so that it's not possible to have port numbers that conflict with each other. + + Changes to the following port numbers: - `DISCOVERY_PORT`: default + `instance` - 1 - `AUTH_PORT`: default + `instance` * 100 - 100 - `HTTP_RPC_PORT`: default - `instance` + 1 - `WS_RPC_PORT`: default + `instance` * 2 - 2 + + [default: 1] + + -h, --help + Print help (see a summary with '-h') + +Datadir: + --datadir + The path to the data dir for all reth files and subdirectories. + + Defaults to the OS-specific data directory: + + - Linux: `$XDG_DATA_HOME/reth/` or `$HOME/.local/share/reth/` + - Windows: `{FOLDERID_RoamingAppData}/reth/` + - macOS: `$HOME/Library/Application Support/reth/` + + [default: default] + + --datadir.static_files + The absolute path to store static files in. + + --config + The path to the configuration file to use + + --chain + The chain this node is running. + Possible values are either a built-in chain or the path to a chain specification file. + + Built-in chains: + mainnet, sepolia, goerli, holesky, dev + + [default: mainnet] + +Database: + --db.log-level + Database logging level. Levels higher than "notice" require a debug build + + Possible values: + - fatal: Enables logging for critical conditions, i.e. assertion failures + - error: Enables logging for error conditions + - warn: Enables logging for warning conditions + - notice: Enables logging for normal but significant condition + - verbose: Enables logging for verbose informational + - debug: Enables logging for debug-level messages + - trace: Enables logging for trace debug-level messages + - extra: Enables logging for extra debug-level messages + + --db.exclusive + Open environment in exclusive/monopolistic mode. Makes it possible to open a database on an NFS volume + + [possible values: true, false] + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + [default: always] + + Possible values: + - always: Colors on + - auto: Colors on + - never: Colors off + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output +``` \ No newline at end of file diff --git a/book/cli/reth/stage/unwind.md b/book/cli/reth/stage/unwind.md index a1a538f3b1dc..3af76e1d567e 100644 --- a/book/cli/reth/stage/unwind.md +++ b/book/cli/reth/stage/unwind.md @@ -204,6 +204,9 @@ Networking: [default: 131072] + --offline + If this is enabled, then all stages except headers, bodies, and sender recovery will be unwound + Logging: --log.stdout.format The format to use for logs written to stdout diff --git a/book/intro.md b/book/intro.md index 9b57849eb53e..f945d694e6ce 100644 --- a/book/intro.md +++ b/book/intro.md @@ -76,7 +76,7 @@ Reth implements the specification of Ethereum as defined in the [ethereum/execut 1. We operate multiple nodes at the tip of Ethereum mainnet and various testnets. 1. We extensively unit test, fuzz test and document all our code, while also restricting PRs with aggressive lint rules. -We have completed an audit of the [Reth v1.0.0-rc.2](https://github.com/paradigmxyz/reth/releases/tag/v1.0.0-rc.2) with [Sigma Prime](https://sigmaprime.io/), the developers of [Lighthouse](https://github.com/sigp/lighthouse), the Rust Consensus Layer implementation. Find it [here](https://github.com/paradigmxyz/reth/blob/bf9cac7571f018fec581fe3647862dab527aeafb/audit/sigma_prime_audit_v1.pdf). +We have completed an audit of the [Reth v1.0.0-rc.2](https://github.com/paradigmxyz/reth/releases/tag/v1.0.0-rc.2) with [Sigma Prime](https://sigmaprime.io/), the developers of [Lighthouse](https://github.com/sigp/lighthouse), the Rust Consensus Layer implementation. Find it [here](https://github.com/paradigmxyz/reth/blob/main/audit/sigma_prime_audit_v2.pdf). [Revm](https://github.com/bluealloy/revm) (the EVM used in Reth) underwent an audit with [Guido Vranken](https://twitter.com/guidovranken) (#1 [Ethereum Bug Bounty](https://ethereum.org/en/bug-bounty)). We will publish the results soon. diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 5d73a1a78e06..66ed04478540 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -15,8 +15,8 @@ use reth_evm::execute::BlockExecutorProvider; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, ForkBlock, GotExpected, Hardfork, Receipt, SealedBlock, - SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, + BlockHash, BlockNumHash, BlockNumber, EthereumHardfork, ForkBlock, GotExpected, Receipt, + SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, B256, U256, }; use reth_provider::{ BlockExecutionWriter, BlockNumReader, BlockWriter, CanonStateNotification, @@ -402,7 +402,7 @@ where .externals .provider_factory .chain_spec() - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(parent_td, U256::ZERO) { return Err(BlockExecutionError::Validation(BlockValidationError::BlockPreMerge { @@ -1043,7 +1043,7 @@ where .externals .provider_factory .chain_spec() - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(td, U256::ZERO) { return Err(CanonicalError::from(BlockValidationError::BlockPreMerge { diff --git a/crates/chainspec/Cargo.toml b/crates/chainspec/Cargo.toml index 682289145aab..f473acc4b20a 100644 --- a/crates/chainspec/Cargo.toml +++ b/crates/chainspec/Cargo.toml @@ -26,6 +26,7 @@ alloy-trie.workspace = true # misc once_cell.workspace = true +serde = { workspace = true, optional = true } serde_json.workspace = true derive_more.workspace = true @@ -42,7 +43,8 @@ rand.workspace = true [features] default = ["std"] optimism = [ - "reth-ethereum-forks/optimism" + "reth-ethereum-forks/optimism", + "serde" ] std = [] arbitrary = [ diff --git a/crates/chainspec/src/lib.rs b/crates/chainspec/src/lib.rs index 8dd598abdfb4..55648b006fe3 100644 --- a/crates/chainspec/src/lib.rs +++ b/crates/chainspec/src/lib.rs @@ -26,15 +26,18 @@ extern crate alloc; /// The chain info module. mod info; -/// Network related constants -pub mod net; - /// The chain spec module. mod spec; /// Chain specific constants pub(crate) mod constants; +#[cfg(feature = "taiko")] +mod taiko; + +#[cfg(feature = "taiko")] +pub use spec::{TAIKO_INTERNAL_L2_A, TAIKO_TESTNET}; + /// Re-export for convenience pub use reth_ethereum_forks::*; diff --git a/crates/chainspec/src/net.rs b/crates/chainspec/src/net.rs deleted file mode 100644 index 922a7df574ca..000000000000 --- a/crates/chainspec/src/net.rs +++ /dev/null @@ -1,250 +0,0 @@ -pub use reth_network_peers::{NodeRecord, NodeRecordParseError, TrustedPeer}; - -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; - -// Ethereum bootnodes come from -// OP bootnodes come from - -/// Ethereum Foundation Go Bootnodes -pub static MAINNET_BOOTNODES : [&str; 4] = [ - "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001 - "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001 - "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel - "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn -]; - -/// Ethereum Foundation Sepolia Bootnodes -pub static SEPOLIA_BOOTNODES : [&str; 5] = [ - "enode://4e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476f8fb1cbe914af0d9aef0d51665c214cf653c651c4bbd9d5550a934f241f1682b@138.197.51.181:30303", // sepolia-bootnode-1-nyc3 - "enode://143e11fb766781d22d92a2e33f8f104cddae4411a122295ed1fdb6638de96a6ce65f5b7c964ba3763bba27961738fef7d3ecc739268f3e5e771fb4c87b6234ba@146.190.1.103:30303", // sepolia-bootnode-1-sfo3 - "enode://8b61dc2d06c3f96fddcbebb0efb29d60d3598650275dc469c22229d3e5620369b0d3dedafd929835fe7f489618f19f456fe7c0df572bf2d914a9f4e006f783a9@170.64.250.88:30303", // sepolia-bootnode-1-syd1 - "enode://10d62eff032205fcef19497f35ca8477bea0eadfff6d769a147e895d8b2b8f8ae6341630c645c30f5df6e67547c03494ced3d9c5764e8622a26587b083b028e8@139.59.49.206:30303", // sepolia-bootnode-1-blr1 - "enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303", // sepolia-bootnode-1-ams3 -]; - -/// Görli Bootnodes -pub static GOERLI_BOOTNODES : [&str; 7] = [ - // Upstream bootnodes - "enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", - "enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303", - "enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313", - "enode://b5948a2d3e9d486c4d75bf32713221c2bd6cf86463302339299bd227dc2e276cd5a1c7ca4f43a0e9122fe9af884efed563bd2a1fd28661f3b5f5ad7bf1de5949@18.218.250.66:30303", - - // Ethereum Foundation bootnode - "enode://a61215641fb8714a373c80edbfa0ea8878243193f57c96eeb44d0bc019ef295abd4e044fd619bfc4c59731a73fb79afe84e9ab6da0c743ceb479cbb6d263fa91@3.11.147.67:30303", - - // Goerli Initiative bootnodes - "enode://d4f764a48ec2a8ecf883735776fdefe0a3949eb0ca476bd7bc8d0954a9defe8fea15ae5da7d40b5d2d59ce9524a99daedadf6da6283fca492cc80b53689fb3b3@46.4.99.122:32109", - "enode://d2b720352e8216c9efc470091aa91ddafc53e222b32780f505c817ceef69e01d5b0b0797b69db254c586f493872352f5a022b4d8479a00fc92ec55f9ad46a27e@88.99.70.182:30303", -]; - -/// Ethereum Foundation Holesky Bootnodes -pub static HOLESKY_BOOTNODES : [&str; 2] = [ - "enode://ac906289e4b7f12df423d654c5a962b6ebe5b3a74cc9e06292a85221f9a64a6f1cfdd6b714ed6dacef51578f92b34c60ee91e9ede9c7f8fadc4d347326d95e2b@146.190.13.128:30303", - "enode://a3435a0155a3e837c02f5e7f5662a2f1fbc25b48e4dc232016e1c51b544cb5b4510ef633ea3278c0e970fa8ad8141e2d4d0f9f95456c537ff05fdf9b31c15072@178.128.136.233:30303", -]; - -#[cfg(feature = "optimism")] -/// OP stack mainnet boot nodes. -pub static OP_BOOTNODES: &[&str] = &[ - // OP Labs - "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305", - "enode://dd751a9ef8912be1bfa7a5e34e2c3785cc5253110bd929f385e07ba7ac19929fb0e0c5d93f77827291f4da02b2232240fbc47ea7ce04c46e333e452f8656b667@34.65.107.0:30305", - "enode://c5d289b56a77b6a2342ca29956dfd07aadf45364dde8ab20d1dc4efd4d1bc6b4655d902501daea308f4d8950737a4e93a4dfedd17b49cd5760ffd127837ca965@34.65.202.239:30305", - // Base - "enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301", - "enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301", - "enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301", - "enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301", - "enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301" -]; - -#[cfg(feature = "optimism")] -/// OP stack testnet boot nodes. -pub static OP_TESTNET_BOOTNODES: &[&str] = &[ - // OP Labs - "enode://2bd2e657bb3c8efffb8ff6db9071d9eb7be70d7c6d7d980ff80fc93b2629675c5f750bc0a5ef27cd788c2e491b8795a7e9a4a6e72178c14acc6753c0e5d77ae4@34.65.205.244:30305", - "enode://db8e1cab24624cc62fc35dbb9e481b88a9ef0116114cd6e41034c55b5b4f18755983819252333509bd8e25f6b12aadd6465710cd2e956558faf17672cce7551f@34.65.173.88:30305", - "enode://bfda2e0110cfd0f4c9f7aa5bf5ec66e6bd18f71a2db028d36b8bf8b0d6fdb03125c1606a6017b31311d96a36f5ef7e1ad11604d7a166745e6075a715dfa67f8a@34.65.229.245:30305", - // Base - "enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301", - "enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301", -]; - -/// Returns parsed mainnet nodes -pub fn mainnet_nodes() -> Vec { - parse_nodes(&MAINNET_BOOTNODES[..]) -} - -/// Returns parsed goerli nodes -pub fn goerli_nodes() -> Vec { - parse_nodes(&GOERLI_BOOTNODES[..]) -} - -/// Returns parsed sepolia nodes -pub fn sepolia_nodes() -> Vec { - parse_nodes(&SEPOLIA_BOOTNODES[..]) -} - -/// Returns parsed holesky nodes -pub fn holesky_nodes() -> Vec { - parse_nodes(&HOLESKY_BOOTNODES[..]) -} - -#[cfg(feature = "optimism")] -/// Returns parsed op-stack mainnet nodes -pub fn op_nodes() -> Vec { - parse_nodes(OP_BOOTNODES) -} - -#[cfg(feature = "optimism")] -/// Returns parsed op-stack testnet nodes -pub fn op_testnet_nodes() -> Vec { - parse_nodes(OP_TESTNET_BOOTNODES) -} - -#[cfg(feature = "optimism")] -/// Returns parsed op-stack base mainnet nodes -pub fn base_nodes() -> Vec { - parse_nodes(OP_BOOTNODES) -} - -#[cfg(feature = "optimism")] -/// Returns parsed op-stack base testnet nodes -pub fn base_testnet_nodes() -> Vec { - parse_nodes(OP_TESTNET_BOOTNODES) -} - -/// Parses all the nodes -pub fn parse_nodes(nodes: impl IntoIterator>) -> Vec { - nodes.into_iter().map(|s| s.as_ref().parse().unwrap()).collect() -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_rlp::Decodable; - use rand::{thread_rng, Rng, RngCore}; - use std::net::{IpAddr, Ipv4Addr}; - - #[test] - fn test_mapped_ipv6() { - let mut rng = thread_rng(); - - let v4: Ipv4Addr = "0.0.0.0".parse().unwrap(); - let v6 = v4.to_ipv6_mapped(); - - let record = NodeRecord { - address: v6.into(), - tcp_port: rng.gen(), - udp_port: rng.gen(), - id: rng.gen(), - }; - - assert!(record.clone().convert_ipv4_mapped()); - assert_eq!(record.into_ipv4_mapped().address, IpAddr::from(v4)); - } - - #[test] - fn test_mapped_ipv4() { - let mut rng = thread_rng(); - let v4: Ipv4Addr = "0.0.0.0".parse().unwrap(); - - let record = NodeRecord { - address: v4.into(), - tcp_port: rng.gen(), - udp_port: rng.gen(), - id: rng.gen(), - }; - - assert!(!record.clone().convert_ipv4_mapped()); - assert_eq!(record.into_ipv4_mapped().address, IpAddr::from(v4)); - } - - #[test] - fn test_noderecord_codec_ipv4() { - let mut rng = thread_rng(); - for _ in 0..100 { - let mut ip = [0u8; 4]; - rng.fill_bytes(&mut ip); - let record = NodeRecord { - address: IpAddr::V4(ip.into()), - tcp_port: rng.gen(), - udp_port: rng.gen(), - id: rng.gen(), - }; - - let decoded = NodeRecord::decode(&mut alloy_rlp::encode(record).as_slice()).unwrap(); - assert_eq!(record, decoded); - } - } - - #[test] - fn test_noderecord_codec_ipv6() { - let mut rng = thread_rng(); - for _ in 0..100 { - let mut ip = [0u8; 16]; - rng.fill_bytes(&mut ip); - let record = NodeRecord { - address: IpAddr::V6(ip.into()), - tcp_port: rng.gen(), - udp_port: rng.gen(), - id: rng.gen(), - }; - - let decoded = NodeRecord::decode(&mut alloy_rlp::encode(record).as_slice()).unwrap(); - assert_eq!(record, decoded); - } - } - - #[test] - fn test_url_parse() { - let url = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301"; - let node: NodeRecord = url.parse().unwrap(); - assert_eq!(node, NodeRecord { - address: IpAddr::V4([10,3,58,6].into()), - tcp_port: 30303, - udp_port: 30301, - id: "6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0".parse().unwrap(), - }) - } - - #[test] - fn test_node_display() { - let url = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303"; - let node: NodeRecord = url.parse().unwrap(); - assert_eq!(url, &format!("{node}")); - } - - #[test] - fn test_node_display_discport() { - let url = "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301"; - let node: NodeRecord = url.parse().unwrap(); - assert_eq!(url, &format!("{node}")); - } - - #[test] - fn test_node_serialize() { - let node = NodeRecord{ - address: IpAddr::V4([10, 3, 58, 6].into()), - tcp_port: 30303u16, - udp_port: 30301u16, - id: "6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0".parse().unwrap(), - }; - let ser = serde_json::to_string::(&node).expect("couldn't serialize"); - assert_eq!(ser, "\"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301\"") - } - - #[test] - fn test_node_deserialize() { - let url = "\"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@10.3.58.6:30303?discport=30301\""; - let node: NodeRecord = serde_json::from_str(url).expect("couldn't deserialize"); - assert_eq!(node, NodeRecord{ - address: IpAddr::V4([10, 3, 58, 6].into()), - tcp_port: 30303u16, - udp_port: 30301u16, - id: "6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0".parse().unwrap(), - }) - } -} diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index bf16a88f0913..999222cc902e 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "taiko")] +use super::taiko::{get_taiko_genesis, TaikoNamedChain}; use crate::constants::MAINNET_DEPOSIT_CONTRACT; #[cfg(not(feature = "std"))] use alloc::{ @@ -14,20 +16,17 @@ use alloy_trie::EMPTY_ROOT_HASH; use derive_more::From; use once_cell::sync::Lazy; use reth_ethereum_forks::{ - chains::ethereum::{GOERLI_HARDFORKS, HOLESKY_HARDFORKS, MAINNET_HARDFORKS, SEPOLIA_HARDFORKS}, - DisplayHardforks, ForkCondition, ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, + ChainHardforks, DisplayHardforks, EthereumHardfork, EthereumHardforks, ForkCondition, + ForkFilter, ForkFilterKey, ForkHash, ForkId, Hardfork, Head, DEV_HARDFORKS, }; use reth_network_peers::NodeRecord; use reth_primitives_traits::{ - constants::{ - EIP1559_INITIAL_BASE_FEE, EMPTY_OMMER_ROOT_HASH, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, - EMPTY_WITHDRAWALS, - }, + constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_WITHDRAWALS}, Header, SealedHeader, }; use reth_trie_common::root::state_root_ref_unhashed; #[cfg(feature = "std")] -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; #[cfg(feature = "optimism")] use crate::constants::optimism::{ @@ -36,11 +35,11 @@ use crate::constants::optimism::{ }; pub use alloy_eips::eip1559::BaseFeeParams; #[cfg(feature = "optimism")] -use reth_ethereum_forks::chains::optimism::*; - -#[cfg(feature = "optimism")] -use crate::net::{base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes}; -use crate::net::{goerli_nodes, holesky_nodes, mainnet_nodes, sepolia_nodes}; +use reth_ethereum_forks::OptimismHardfork; +use reth_network_peers::{ + base_nodes, base_testnet_nodes, goerli_nodes, holesky_nodes, mainnet_nodes, op_nodes, + op_testnet_nodes, sepolia_nodes, +}; /// The Ethereum mainnet spec pub static MAINNET: Lazy> = Lazy::new(|| { @@ -56,7 +55,7 @@ pub static MAINNET: Lazy> = Lazy::new(|| { 15537394, U256::from(58_750_003_716_598_352_816_469u128), )), - hardforks: MAINNET_HARDFORKS.into(), + hardforks: EthereumHardfork::mainnet().into(), // https://etherscan.io/tx/0xe75fb554e433e03763a1560646ee22dcb74e5274b34c5ad644e7c0f619a7e1d0 deposit_contract: Some(DepositContract::new( address!("00000000219ab540356cbb839cbe05303d7705fa"), @@ -80,7 +79,7 @@ pub static GOERLI: Lazy> = Lazy::new(|| { )), // paris_block_and_final_difficulty: Some((7382818, U256::from(10_790_000))), - hardforks: GOERLI_HARDFORKS.into(), + hardforks: EthereumHardfork::goerli().into(), // https://goerli.etherscan.io/tx/0xa3c07dc59bfdb1bfc2d50920fed2ef2c1c4e0a09fe2325dbc14e07702f965a78 deposit_contract: Some(DepositContract::new( address!("ff50ed3d0ec03ac01d4c79aad74928bff48a7b2b"), @@ -104,7 +103,7 @@ pub static SEPOLIA: Lazy> = Lazy::new(|| { )), // paris_block_and_final_difficulty: Some((1450409, U256::from(17_000_018_015_853_232u128))), - hardforks: SEPOLIA_HARDFORKS.into(), + hardforks: EthereumHardfork::sepolia().into(), // https://sepolia.etherscan.io/tx/0x025ecbf81a2f1220da6285d1701dc89fb5a956b62562ee922e1a9efd73eb4b14 deposit_contract: Some(DepositContract::new( address!("7f02c3e3c98b133055b8b348b2ac625669ed295d"), @@ -127,7 +126,7 @@ pub static HOLESKY: Lazy> = Lazy::new(|| { "b5f7f912443c940f21fd611f12828d75b534364ed9e95ca4e307729a4661bde4" )), paris_block_and_final_difficulty: Some((0, U256::from(1))), - hardforks: HOLESKY_HARDFORKS.into(), + hardforks: EthereumHardfork::holesky().into(), deposit_contract: Some(DepositContract::new( address!("4242424242424242424242424242424242424242"), 0, @@ -152,32 +151,7 @@ pub static DEV: Lazy> = Lazy::new(|| { "2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BTreeMap::from([ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::from(0) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(0)), - (Hardfork::Cancun, ForkCondition::Timestamp(0)), - #[cfg(feature = "optimism")] - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - #[cfg(feature = "optimism")] - (Hardfork::Bedrock, ForkCondition::Block(0)), - #[cfg(feature = "optimism")] - (Hardfork::Ecotone, ForkCondition::Timestamp(0)), - ]), + hardforks: DEV_HARDFORKS.clone(), base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), deposit_contract: None, // TODO: do we even have? ..Default::default() @@ -198,11 +172,11 @@ pub static OP_MAINNET: Lazy> = Lazy::new(|| { "7ca38a1916c42007829c55e69d3e9a73265554b586a499015373241b8a3fa48b" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OP_MAINNET_HARDFORKS.into(), + hardforks: OptimismHardfork::op_mainnet(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -223,11 +197,11 @@ pub static OP_SEPOLIA: Lazy> = Lazy::new(|| { "102de6ffb001480cc9b8b548fd05c34cd4f46ae4aa91759393db90ea0409887d" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: OP_SEPOLIA_HARDFORKS.into(), + hardforks: OptimismHardfork::op_sepolia(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_SEPOLIA_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_SEPOLIA_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_SEPOLIA_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_SEPOLIA_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -248,11 +222,11 @@ pub static BASE_SEPOLIA: Lazy> = Lazy::new(|| { "0dcc9e089e30b90ddfc55be9a37dd15bc551aeee999d2e2b51414c54eaf934e4" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BASE_SEPOLIA_HARDFORKS.into(), + hardforks: OptimismHardfork::base_sepolia(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, BASE_SEPOLIA_BASE_FEE_PARAMS), - (Hardfork::Canyon, BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), BASE_SEPOLIA_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), BASE_SEPOLIA_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -273,11 +247,11 @@ pub static BASE_MAINNET: Lazy> = Lazy::new(|| { "f712aa9241cc24369b143cf6dce85f0902a9731e70d66818a3a5845b296c73dd" )), paris_block_and_final_difficulty: Some((0, U256::from(0))), - hardforks: BASE_MAINNET_HARDFORKS.into(), + hardforks: OptimismHardfork::base_mainnet(), base_fee_params: BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, OP_BASE_FEE_PARAMS), - (Hardfork::Canyon, OP_CANYON_BASE_FEE_PARAMS), + (EthereumHardfork::London.boxed(), OP_BASE_FEE_PARAMS), + (OptimismHardfork::Canyon.boxed(), OP_CANYON_BASE_FEE_PARAMS), ] .into(), ), @@ -287,6 +261,44 @@ pub static BASE_MAINNET: Lazy> = Lazy::new(|| { .into() }); +/// The Taiko internal L2 A spec +#[cfg(feature = "taiko")] +pub static TAIKO_INTERNAL_L2_A: Lazy> = Lazy::new(|| { + ChainSpec { + chain: TaikoNamedChain::TaikoInternalL2A.into(), + genesis: get_taiko_genesis(TaikoNamedChain::TaikoInternalL2A), + hardforks: BTreeMap::from([ + (Hardfork::Shanghai, ForkCondition::Block(0)), + (Hardfork::Cancun, ForkCondition::Never), + ]), + base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams { + max_change_denominator: 8, + elasticity_multiplier: 2, + }), + ..Default::default() + } + .into() +}); + +/// The Taiko testnet spec +#[cfg(feature = "taiko")] +pub static TAIKO_TESTNET: Lazy> = Lazy::new(|| { + ChainSpec { + chain: TaikoNamedChain::Katla.into(), + genesis: get_taiko_genesis(TaikoNamedChain::Katla), + hardforks: BTreeMap::from([ + (Hardfork::Shanghai, ForkCondition::Block(0)), + (Hardfork::Cancun, ForkCondition::Never), + ]), + base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams { + max_change_denominator: 8, + elasticity_multiplier: 2, + }), + ..Default::default() + } + .into() +}); + /// A wrapper around [`BaseFeeParams`] that allows for specifying constant or dynamic EIP-1559 /// parameters based on the active [Hardfork]. #[derive(Clone, Debug, PartialEq, Eq)] @@ -298,6 +310,12 @@ pub enum BaseFeeParamsKind { Variable(ForkBaseFeeParams), } +impl Default for BaseFeeParamsKind { + fn default() -> Self { + BaseFeeParams::ethereum().into() + } +} + impl From for BaseFeeParamsKind { fn from(params: BaseFeeParams) -> Self { Self::Constant(params) @@ -313,7 +331,15 @@ impl From for BaseFeeParamsKind { /// A type alias to a vector of tuples of [Hardfork] and [`BaseFeeParams`], sorted by [Hardfork] /// activation order. This is used to specify dynamic EIP-1559 parameters for chains like Optimism. #[derive(Clone, Debug, PartialEq, Eq, From)] -pub struct ForkBaseFeeParams(Vec<(Hardfork, BaseFeeParams)>); +pub struct ForkBaseFeeParams(Vec<(Box, BaseFeeParams)>); + +impl std::ops::Deref for ChainSpec { + type Target = ChainHardforks; + + fn deref(&self) -> &Self::Target { + &self.hardforks + } +} /// An Ethereum chain specification. /// @@ -336,12 +362,12 @@ pub struct ChainSpec { /// The genesis block pub genesis: Genesis, - /// The block at which [`Hardfork::Paris`] was activated and the final difficulty at this - /// block. + /// The block at which [`EthereumHardfork::Paris`] was activated and the final difficulty at + /// this block. pub paris_block_and_final_difficulty: Option<(u64, U256)>, /// The active hard forks and their activation conditions - pub hardforks: BTreeMap, + pub hardforks: ChainHardforks, /// The deposit contract deployed for `PoS` pub deposit_contract: Option, @@ -398,7 +424,7 @@ impl ChainSpec { #[inline] #[cfg(feature = "optimism")] pub fn is_optimism(&self) -> bool { - self.chain.is_optimism() || self.hardforks.contains_key(&Hardfork::Bedrock) + self.chain.is_optimism() || self.hardforks.get(OptimismHardfork::Bedrock).is_some() } /// Returns `true` if this chain contains Optimism configuration. @@ -429,7 +455,7 @@ impl ChainSpec { // If shanghai is activated, initialize the header with an empty withdrawals hash, and // empty withdrawals list. let withdrawals_root = self - .fork(Hardfork::Shanghai) + .fork(EthereumHardfork::Shanghai) .active_at_timestamp(self.genesis.timestamp) .then_some(EMPTY_WITHDRAWALS); @@ -454,12 +480,6 @@ impl ChainSpec { }; Header { - parent_hash: B256::ZERO, - number: 0, - transactions_root: EMPTY_TRANSACTIONS, - ommers_hash: EMPTY_OMMER_ROOT_HASH, - receipts_root: EMPTY_RECEIPTS, - logs_bloom: Default::default(), gas_limit: self.genesis.gas_limit as u64, difficulty: self.genesis.difficulty, nonce: self.genesis.nonce, @@ -468,13 +488,13 @@ impl ChainSpec { timestamp: self.genesis.timestamp, mix_hash: self.genesis.mix_hash, beneficiary: self.genesis.coinbase, - gas_used: Default::default(), base_fee_per_gas, withdrawals_root, parent_beacon_block_root, blob_gas_used, excess_blob_gas, requests_root, + ..Default::default() } } @@ -490,7 +510,7 @@ impl ChainSpec { self.genesis.base_fee_per_gas.map(|fee| fee as u64).unwrap_or(EIP1559_INITIAL_BASE_FEE); // If London is activated at genesis, we set the initial base fee as per EIP-1559. - self.fork(Hardfork::London).active_at_block(0).then_some(genesis_base_fee) + self.hardforks.fork(EthereumHardfork::London).active_at_block(0).then_some(genesis_base_fee) } /// Get the [`BaseFeeParams`] for the chain at the given timestamp. @@ -502,7 +522,7 @@ impl ChainSpec { // first one that corresponds to a hardfork that is active at the // given timestamp. for (fork, params) in bf_params.iter().rev() { - if self.is_fork_active_at_timestamp(*fork, timestamp) { + if self.hardforks.is_fork_active_at_timestamp(fork.clone(), timestamp) { return *params } } @@ -521,7 +541,7 @@ impl ChainSpec { // first one that corresponds to a hardfork that is active at the // given timestamp. for (fork, params) in bf_params.iter().rev() { - if self.is_fork_active_at_block(*fork, block_number) { + if self.hardforks.is_fork_active_at_block(fork.clone(), block_number) { return *params } } @@ -558,130 +578,55 @@ impl ChainSpec { } /// Get the fork filter for the given hardfork - pub fn hardfork_fork_filter(&self, fork: Hardfork) -> Option { - match self.fork(fork) { + pub fn hardfork_fork_filter(&self, fork: H) -> Option { + match self.hardforks.fork(fork.clone()) { ForkCondition::Never => None, - _ => Some(self.fork_filter(self.satisfy(self.fork(fork)))), + _ => Some(self.fork_filter(self.satisfy(self.hardforks.fork(fork)))), } } - /// Returns the forks in this specification and their activation conditions. - pub const fn hardforks(&self) -> &BTreeMap { - &self.hardforks - } - /// Returns the hardfork display helper. pub fn display_hardforks(&self) -> DisplayHardforks { DisplayHardforks::new( - self.hardforks(), + &self.hardforks, self.paris_block_and_final_difficulty.map(|(block, _)| block), ) } /// Get the fork id for the given hardfork. #[inline] - pub fn hardfork_fork_id(&self, fork: Hardfork) -> Option { - match self.fork(fork) { + pub fn hardfork_fork_id(&self, fork: H) -> Option { + let condition = self.hardforks.fork(fork); + match condition { ForkCondition::Never => None, - _ => Some(self.fork_id(&self.satisfy(self.fork(fork)))), + _ => Some(self.fork_id(&self.satisfy(condition))), } } - /// Convenience method to get the fork id for [`Hardfork::Shanghai`] from a given chainspec. + /// Convenience method to get the fork id for [`EthereumHardfork::Shanghai`] from a given + /// chainspec. #[inline] pub fn shanghai_fork_id(&self) -> Option { - self.hardfork_fork_id(Hardfork::Shanghai) + self.hardfork_fork_id(EthereumHardfork::Shanghai) } - /// Convenience method to get the fork id for [`Hardfork::Cancun`] from a given chainspec. + /// Convenience method to get the fork id for [`EthereumHardfork::Cancun`] from a given + /// chainspec. #[inline] pub fn cancun_fork_id(&self) -> Option { - self.hardfork_fork_id(Hardfork::Cancun) + self.hardfork_fork_id(EthereumHardfork::Cancun) } /// Convenience method to get the latest fork id from the chainspec. Panics if chainspec has no /// hardforks. #[inline] pub fn latest_fork_id(&self) -> ForkId { - self.hardfork_fork_id(*self.hardforks().last_key_value().unwrap().0).unwrap() - } - - /// Get the fork condition for the given fork. - pub fn fork(&self, fork: Hardfork) -> ForkCondition { - self.hardforks.get(&fork).copied().unwrap_or(ForkCondition::Never) - } - - /// Get an iterator of all hardforks with their respective activation conditions. - pub fn forks_iter(&self) -> impl Iterator + '_ { - self.hardforks.iter().map(|(f, b)| (*f, *b)) - } - - /// Convenience method to check if a fork is active at a given timestamp. - #[inline] - pub fn is_fork_active_at_timestamp(&self, fork: Hardfork, timestamp: u64) -> bool { - self.fork(fork).active_at_timestamp(timestamp) - } - - /// Convenience method to check if a fork is active at a given block number - #[inline] - pub fn is_fork_active_at_block(&self, fork: Hardfork, block_number: u64) -> bool { - self.fork(fork).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::Shanghai`] is active at a given timestamp. - #[inline] - pub fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Shanghai, timestamp) - } - - /// Convenience method to check if [`Hardfork::Cancun`] is active at a given timestamp. - #[inline] - pub fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Cancun, timestamp) - } - - /// Convenience method to check if [`Hardfork::Prague`] is active at a given timestamp. - #[inline] - pub fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool { - self.is_fork_active_at_timestamp(Hardfork::Prague, timestamp) - } - - /// Convenience method to check if [`Hardfork::Byzantium`] is active at a given block number. - #[inline] - pub fn is_byzantium_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Byzantium).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::SpuriousDragon`] is active at a given block - /// number. - #[inline] - pub fn is_spurious_dragon_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::SpuriousDragon).active_at_block(block_number) - } - - /// Convenience method to check if [`Hardfork::Homestead`] is active at a given block number. - #[inline] - pub fn is_homestead_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Homestead).active_at_block(block_number) - } - - /// The Paris hardfork (merge) is activated via block number. If we have knowledge of the block, - /// this function will return true if the block number is greater than or equal to the Paris - /// (merge) block. - pub fn is_paris_active_at_block(&self, block_number: u64) -> Option { - self.paris_block_and_final_difficulty.map(|(paris_block, _)| block_number >= paris_block) - } - - /// Convenience method to check if [`Hardfork::Bedrock`] is active at a given block number. - #[cfg(feature = "optimism")] - #[inline] - pub fn is_bedrock_active_at_block(&self, block_number: u64) -> bool { - self.fork(Hardfork::Bedrock).active_at_block(block_number) + self.hardfork_fork_id(self.hardforks.last().unwrap().0).unwrap() } /// Creates a [`ForkFilter`] for the block described by [Head]. pub fn fork_filter(&self, head: Head) -> ForkFilter { - let forks = self.forks_iter().filter_map(|(_, condition)| { + let forks = self.hardforks.forks_iter().filter_map(|(_, condition)| { // We filter out TTD-based forks w/o a pre-known block since those do not show up in the // fork filter. Some(match condition { @@ -701,11 +646,11 @@ impl ChainSpec { let mut current_applied = 0; // handle all block forks before handling timestamp based forks. see: https://eips.ethereum.org/EIPS/eip-6122 - for (_, cond) in self.forks_iter() { + for (_, cond) in self.hardforks.forks_iter() { // handle block based forks and the sepolia merge netsplit block edge case (TTD // ForkCondition with Some(block)) - if let ForkCondition::Block(block) | - ForkCondition::TTD { fork_block: Some(block), .. } = cond + if let ForkCondition::Block(block) + | ForkCondition::TTD { fork_block: Some(block), .. } = cond { if cond.active_at_head(head) { if block != current_applied { @@ -715,7 +660,7 @@ impl ChainSpec { } else { // we can return here because this block fork is not active, so we set the // `next` value - return ForkId { hash: forkhash, next: block } + return ForkId { hash: forkhash, next: block }; } } } @@ -723,7 +668,7 @@ impl ChainSpec { // timestamp are ALWAYS applied after the merge. // // this filter ensures that no block-based forks are returned - for timestamp in self.forks_iter().filter_map(|(_, cond)| { + for timestamp in self.hardforks.forks_iter().filter_map(|(_, cond)| { cond.as_timestamp().filter(|time| time > &self.genesis.timestamp) }) { let cond = ForkCondition::Timestamp(timestamp); @@ -736,7 +681,7 @@ impl ChainSpec { // can safely return here because we have already handled all block forks and // have handled all active timestamp forks, and set the next value to the // timestamp that is known but not active yet - return ForkId { hash: forkhash, next: timestamp } + return ForkId { hash: forkhash, next: timestamp }; } } @@ -751,7 +696,7 @@ impl ChainSpec { // to satisfy every timestamp ForkCondition, we find the last ForkCondition::Block // if one exists, and include its block_num in the returned Head if let Some(last_block_num) = self.last_block_fork_before_merge_or_timestamp() { - return Head { timestamp, number: last_block_num, ..Default::default() } + return Head { timestamp, number: last_block_num, ..Default::default() }; } Head { timestamp, ..Default::default() } } @@ -767,7 +712,7 @@ impl ChainSpec { /// /// Note: this returns None if the `ChainSpec` is not configured with a TTD/Timestamp fork. pub(crate) fn last_block_fork_before_merge_or_timestamp(&self) -> Option { - let mut hardforks_iter = self.forks_iter().peekable(); + let mut hardforks_iter = self.hardforks.forks_iter().peekable(); while let Some((_, curr_cond)) = hardforks_iter.next() { if let Some((_, next_cond)) = hardforks_iter.peek() { // peek and find the first occurrence of ForkCondition::TTD (merge) , or in @@ -779,17 +724,17 @@ impl ChainSpec { ForkCondition::TTD { fork_block, .. } => { // handle Sepolia merge netsplit case if fork_block.is_some() { - return *fork_block + return *fork_block; } // ensure curr_cond is indeed ForkCondition::Block and return block_num if let ForkCondition::Block(block_num) = curr_cond { - return Some(block_num) + return Some(block_num); } } ForkCondition::Timestamp(_) => { // ensure curr_cond is indeed ForkCondition::Block and return block_num if let ForkCondition::Block(block_num) = curr_cond { - return Some(block_num) + return Some(block_num); } } ForkCondition::Block(_) | ForkCondition::Never => continue, @@ -813,13 +758,9 @@ impl ChainSpec { C::Goerli => Some(goerli_nodes()), C::Sepolia => Some(sepolia_nodes()), C::Holesky => Some(holesky_nodes()), - #[cfg(feature = "optimism")] C::Base => Some(base_nodes()), - #[cfg(feature = "optimism")] C::Optimism => Some(op_nodes()), - #[cfg(feature = "optimism")] C::BaseGoerli | C::BaseSepolia => Some(base_testnet_nodes()), - #[cfg(feature = "optimism")] C::OptimismSepolia | C::OptimismGoerli | C::OptimismKovan => Some(op_testnet_nodes()), _ => None, } @@ -833,37 +774,37 @@ impl From for ChainSpec { // Block-based hardforks let hardfork_opts = [ - (Hardfork::Homestead, genesis.config.homestead_block), - (Hardfork::Dao, genesis.config.dao_fork_block), - (Hardfork::Tangerine, genesis.config.eip150_block), - (Hardfork::SpuriousDragon, genesis.config.eip155_block), - (Hardfork::Byzantium, genesis.config.byzantium_block), - (Hardfork::Constantinople, genesis.config.constantinople_block), - (Hardfork::Petersburg, genesis.config.petersburg_block), - (Hardfork::Istanbul, genesis.config.istanbul_block), - (Hardfork::MuirGlacier, genesis.config.muir_glacier_block), - (Hardfork::Berlin, genesis.config.berlin_block), - (Hardfork::London, genesis.config.london_block), - (Hardfork::ArrowGlacier, genesis.config.arrow_glacier_block), - (Hardfork::GrayGlacier, genesis.config.gray_glacier_block), + (EthereumHardfork::Homestead.boxed(), genesis.config.homestead_block), + (EthereumHardfork::Dao.boxed(), genesis.config.dao_fork_block), + (EthereumHardfork::Tangerine.boxed(), genesis.config.eip150_block), + (EthereumHardfork::SpuriousDragon.boxed(), genesis.config.eip155_block), + (EthereumHardfork::Byzantium.boxed(), genesis.config.byzantium_block), + (EthereumHardfork::Constantinople.boxed(), genesis.config.constantinople_block), + (EthereumHardfork::Petersburg.boxed(), genesis.config.petersburg_block), + (EthereumHardfork::Istanbul.boxed(), genesis.config.istanbul_block), + (EthereumHardfork::MuirGlacier.boxed(), genesis.config.muir_glacier_block), + (EthereumHardfork::Berlin.boxed(), genesis.config.berlin_block), + (EthereumHardfork::London.boxed(), genesis.config.london_block), + (EthereumHardfork::ArrowGlacier.boxed(), genesis.config.arrow_glacier_block), + (EthereumHardfork::GrayGlacier.boxed(), genesis.config.gray_glacier_block), #[cfg(feature = "optimism")] - (Hardfork::Bedrock, optimism_genesis_info.bedrock_block), + (OptimismHardfork::Bedrock.boxed(), optimism_genesis_info.bedrock_block), ]; let mut hardforks = hardfork_opts - .iter() - .filter_map(|(hardfork, opt)| opt.map(|block| (*hardfork, ForkCondition::Block(block)))) - .collect::>(); + .into_iter() + .filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block)))) + .collect::>(); // Paris let paris_block_and_final_difficulty = if let Some(ttd) = genesis.config.terminal_total_difficulty { - hardforks.insert( - Hardfork::Paris, + hardforks.push(( + EthereumHardfork::Paris.boxed(), ForkCondition::TTD { total_difficulty: ttd, fork_block: genesis.config.merge_netsplit_block, }, - ); + )); genesis.config.merge_netsplit_block.map(|block| (block, ttd)) } else { @@ -872,28 +813,45 @@ impl From for ChainSpec { // Time-based hardforks let time_hardfork_opts = [ - (Hardfork::Shanghai, genesis.config.shanghai_time), - (Hardfork::Cancun, genesis.config.cancun_time), - (Hardfork::Prague, genesis.config.prague_time), + (EthereumHardfork::Shanghai.boxed(), genesis.config.shanghai_time), + (EthereumHardfork::Cancun.boxed(), genesis.config.cancun_time), + (EthereumHardfork::Prague.boxed(), genesis.config.prague_time), #[cfg(feature = "optimism")] - (Hardfork::Regolith, optimism_genesis_info.regolith_time), + (OptimismHardfork::Regolith.boxed(), optimism_genesis_info.regolith_time), #[cfg(feature = "optimism")] - (Hardfork::Canyon, optimism_genesis_info.canyon_time), + (OptimismHardfork::Canyon.boxed(), optimism_genesis_info.canyon_time), #[cfg(feature = "optimism")] - (Hardfork::Ecotone, optimism_genesis_info.ecotone_time), + (OptimismHardfork::Ecotone.boxed(), optimism_genesis_info.ecotone_time), #[cfg(feature = "optimism")] - (Hardfork::Fjord, optimism_genesis_info.fjord_time), + (OptimismHardfork::Fjord.boxed(), optimism_genesis_info.fjord_time), ]; let time_hardforks = time_hardfork_opts - .iter() + .into_iter() .filter_map(|(hardfork, opt)| { - opt.map(|time| (*hardfork, ForkCondition::Timestamp(time))) + opt.map(|time| (hardfork, ForkCondition::Timestamp(time))) }) - .collect::>(); + .collect::>(); hardforks.extend(time_hardforks); + // Uses ethereum or optimism main chains to find proper order + #[cfg(not(feature = "optimism"))] + let mainnet_hardforks: ChainHardforks = EthereumHardfork::mainnet().into(); + #[cfg(not(feature = "optimism"))] + let mainnet_order = mainnet_hardforks.forks_iter(); + #[cfg(feature = "optimism")] + let mainnet_hardforks = OptimismHardfork::op_mainnet(); + #[cfg(feature = "optimism")] + let mainnet_order = mainnet_hardforks.forks_iter(); + + let mut ordered_hardforks = Vec::with_capacity(hardforks.len()); + for (hardfork, _) in mainnet_order { + if let Some(pos) = hardforks.iter().position(|(e, _)| **e == *hardfork) { + ordered_hardforks.push(hardforks[pos].clone()); + } + } + // NOTE: in full node, we prune all receipts except the deposit contract's. We do not // have the deployment block in the genesis file, so we use block zero. We use the same // deposit topic as the mainnet contract if we have the deposit contract address in the @@ -906,7 +864,7 @@ impl From for ChainSpec { chain: genesis.config.chain_id.into(), genesis, genesis_hash: None, - hardforks, + hardforks: ChainHardforks::new(hardforks), paris_block_and_final_difficulty, deposit_contract, #[cfg(feature = "optimism")] @@ -921,7 +879,7 @@ impl From for ChainSpec { pub struct ChainSpecBuilder { chain: Option, genesis: Option, - hardforks: BTreeMap, + hardforks: ChainHardforks, } impl ChainSpecBuilder { @@ -933,7 +891,9 @@ impl ChainSpecBuilder { hardforks: MAINNET.hardforks.clone(), } } +} +impl ChainSpecBuilder { /// Set the chain ID pub const fn chain(mut self, chain: Chain) -> Self { self.chain = Some(chain); @@ -947,14 +907,14 @@ impl ChainSpecBuilder { } /// Add the given fork with the given activation condition to the spec. - pub fn with_fork(mut self, fork: Hardfork, condition: ForkCondition) -> Self { + pub fn with_fork(mut self, fork: EthereumHardfork, condition: ForkCondition) -> Self { self.hardforks.insert(fork, condition); self } /// Remove the given fork from the spec. - pub fn without_fork(mut self, fork: Hardfork) -> Self { - self.hardforks.remove(&fork); + pub fn without_fork(mut self, fork: EthereumHardfork) -> Self { + self.hardforks.remove(fork); self } @@ -963,77 +923,77 @@ impl ChainSpecBuilder { /// Does not set the merge netsplit block. pub fn paris_at_ttd(self, ttd: U256) -> Self { self.with_fork( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { total_difficulty: ttd, fork_block: None }, ) } /// Enable Frontier at genesis. pub fn frontier_activated(mut self) -> Self { - self.hardforks.insert(Hardfork::Frontier, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Frontier, ForkCondition::Block(0)); self } /// Enable Homestead at genesis. pub fn homestead_activated(mut self) -> Self { self = self.frontier_activated(); - self.hardforks.insert(Hardfork::Homestead, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Homestead, ForkCondition::Block(0)); self } /// Enable Tangerine at genesis. pub fn tangerine_whistle_activated(mut self) -> Self { self = self.homestead_activated(); - self.hardforks.insert(Hardfork::Tangerine, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Tangerine, ForkCondition::Block(0)); self } /// Enable Spurious Dragon at genesis. pub fn spurious_dragon_activated(mut self) -> Self { self = self.tangerine_whistle_activated(); - self.hardforks.insert(Hardfork::SpuriousDragon, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::SpuriousDragon, ForkCondition::Block(0)); self } /// Enable Byzantium at genesis. pub fn byzantium_activated(mut self) -> Self { self = self.spurious_dragon_activated(); - self.hardforks.insert(Hardfork::Byzantium, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Byzantium, ForkCondition::Block(0)); self } /// Enable Constantinople at genesis. pub fn constantinople_activated(mut self) -> Self { self = self.byzantium_activated(); - self.hardforks.insert(Hardfork::Constantinople, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Constantinople, ForkCondition::Block(0)); self } /// Enable Petersburg at genesis. pub fn petersburg_activated(mut self) -> Self { self = self.constantinople_activated(); - self.hardforks.insert(Hardfork::Petersburg, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Petersburg, ForkCondition::Block(0)); self } /// Enable Istanbul at genesis. pub fn istanbul_activated(mut self) -> Self { self = self.petersburg_activated(); - self.hardforks.insert(Hardfork::Istanbul, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Istanbul, ForkCondition::Block(0)); self } /// Enable Berlin at genesis. pub fn berlin_activated(mut self) -> Self { self = self.istanbul_activated(); - self.hardforks.insert(Hardfork::Berlin, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::Berlin, ForkCondition::Block(0)); self } /// Enable London at genesis. pub fn london_activated(mut self) -> Self { self = self.berlin_activated(); - self.hardforks.insert(Hardfork::London, ForkCondition::Block(0)); + self.hardforks.insert(EthereumHardfork::London, ForkCondition::Block(0)); self } @@ -1041,7 +1001,7 @@ impl ChainSpecBuilder { pub fn paris_activated(mut self) -> Self { self = self.london_activated(); self.hardforks.insert( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, ); self @@ -1050,14 +1010,14 @@ impl ChainSpecBuilder { /// Enable Shanghai at genesis. pub fn shanghai_activated(mut self) -> Self { self = self.paris_activated(); - self.hardforks.insert(Hardfork::Shanghai, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0)); self } /// Enable Cancun at genesis. pub fn cancun_activated(mut self) -> Self { self = self.shanghai_activated(); - self.hardforks.insert(Hardfork::Cancun, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)); self } @@ -1065,7 +1025,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn bedrock_activated(mut self) -> Self { self = self.paris_activated(); - self.hardforks.insert(Hardfork::Bedrock, ForkCondition::Block(0)); + self.hardforks.insert(OptimismHardfork::Bedrock, ForkCondition::Block(0)); self } @@ -1073,7 +1033,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn regolith_activated(mut self) -> Self { self = self.bedrock_activated(); - self.hardforks.insert(Hardfork::Regolith, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Regolith, ForkCondition::Timestamp(0)); self } @@ -1082,8 +1042,8 @@ impl ChainSpecBuilder { pub fn canyon_activated(mut self) -> Self { self = self.regolith_activated(); // Canyon also activates changes from L1's Shanghai hardfork - self.hardforks.insert(Hardfork::Shanghai, ForkCondition::Timestamp(0)); - self.hardforks.insert(Hardfork::Canyon, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Shanghai, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Canyon, ForkCondition::Timestamp(0)); self } @@ -1091,8 +1051,8 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn ecotone_activated(mut self) -> Self { self = self.canyon_activated(); - self.hardforks.insert(Hardfork::Cancun, ForkCondition::Timestamp(0)); - self.hardforks.insert(Hardfork::Ecotone, ForkCondition::Timestamp(0)); + self.hardforks.insert(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Ecotone, ForkCondition::Timestamp(0)); self } @@ -1100,7 +1060,7 @@ impl ChainSpecBuilder { #[cfg(feature = "optimism")] pub fn fjord_activated(mut self) -> Self { self = self.ecotone_activated(); - self.hardforks.insert(Hardfork::Fjord, ForkCondition::Timestamp(0)); + self.hardforks.insert(OptimismHardfork::Fjord, ForkCondition::Timestamp(0)); self } @@ -1112,9 +1072,9 @@ impl ChainSpecBuilder { /// [`Self::genesis`]) pub fn build(self) -> ChainSpec { let paris_block_and_final_difficulty = { - self.hardforks.get(&Hardfork::Paris).and_then(|cond| { + self.hardforks.get(EthereumHardfork::Paris).and_then(|cond| { if let ForkCondition::TTD { fork_block, total_difficulty } = cond { - fork_block.map(|fork_block| (fork_block, *total_difficulty)) + fork_block.map(|fork_block| (fork_block, total_difficulty)) } else { None } @@ -1160,100 +1120,84 @@ impl DepositContract { } } +/// Genesis info for Optimism. #[cfg(feature = "optimism")] +#[derive(Default, Debug, serde::Deserialize)] +#[serde(rename_all = "camelCase")] struct OptimismGenesisInfo { bedrock_block: Option, regolith_time: Option, canyon_time: Option, ecotone_time: Option, fjord_time: Option, + #[serde(skip)] base_fee_params: BaseFeeParamsKind, } +#[cfg(feature = "optimism")] +#[derive(Debug, Eq, PartialEq, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +struct OptimismBaseFeeInfo { + eip1559_elasticity: Option, + eip1559_denominator: Option, + eip1559_denominator_canyon: Option, +} + #[cfg(feature = "optimism")] impl OptimismGenesisInfo { fn extract_from(genesis: &Genesis) -> Self { - let optimism_config = - genesis.config.extra_fields.get("optimism").and_then(|value| value.as_object()); + let mut optimism_genesis_info: Self = + genesis.config.extra_fields.deserialize_as().unwrap_or_default(); - let eip1559_elasticity = optimism_config - .and_then(|config| config.get("eip1559Elasticity")) - .and_then(|value| value.as_u64()); - - let eip1559_denominator = optimism_config - .and_then(|config| config.get("eip1559Denominator")) - .and_then(|value| value.as_u64()); - - let eip1559_denominator_canyon = optimism_config - .and_then(|config| config.get("eip1559DenominatorCanyon")) - .and_then(|value| value.as_u64()); - - let base_fee_params = if let (Some(elasticity), Some(denominator)) = - (eip1559_elasticity, eip1559_denominator) + if let Some(Ok(optimism_base_fee_info)) = + genesis.config.extra_fields.get_deserialized::("optimism") { - if let Some(canyon_denominator) = eip1559_denominator_canyon { - BaseFeeParamsKind::Variable( - vec![ - ( - Hardfork::London, - BaseFeeParams::new(denominator as u128, elasticity as u128), - ), - ( - Hardfork::Canyon, - BaseFeeParams::new(canyon_denominator as u128, elasticity as u128), - ), - ] - .into(), - ) - } else { - BaseFeeParams::new(denominator as u128, elasticity as u128).into() - } - } else { - BaseFeeParams::ethereum().into() - }; + if let (Some(elasticity), Some(denominator)) = ( + optimism_base_fee_info.eip1559_elasticity, + optimism_base_fee_info.eip1559_denominator, + ) { + let base_fee_params = if let Some(canyon_denominator) = + optimism_base_fee_info.eip1559_denominator_canyon + { + BaseFeeParamsKind::Variable( + vec![ + ( + EthereumHardfork::London.boxed(), + BaseFeeParams::new(denominator as u128, elasticity as u128), + ), + ( + OptimismHardfork::Canyon.boxed(), + BaseFeeParams::new(canyon_denominator as u128, elasticity as u128), + ), + ] + .into(), + ) + } else { + BaseFeeParams::new(denominator as u128, elasticity as u128).into() + }; - Self { - bedrock_block: genesis - .config - .extra_fields - .get("bedrockBlock") - .and_then(|value| value.as_u64()), - regolith_time: genesis - .config - .extra_fields - .get("regolithTime") - .and_then(|value| value.as_u64()), - canyon_time: genesis - .config - .extra_fields - .get("canyonTime") - .and_then(|value| value.as_u64()), - ecotone_time: genesis - .config - .extra_fields - .get("ecotoneTime") - .and_then(|value| value.as_u64()), - fjord_time: genesis - .config - .extra_fields - .get("fjordTime") - .and_then(|value| value.as_u64()), - base_fee_params, + optimism_genesis_info.base_fee_params = base_fee_params; + } } + + optimism_genesis_info } } #[cfg(test)] mod tests { + use super::*; use alloy_chains::Chain; use alloy_genesis::{ChainConfig, GenesisAccount}; + use alloy_primitives::{b256, hex}; + use core::ops::Deref; use reth_ethereum_forks::{ForkCondition, ForkHash, ForkId, Head}; use reth_trie_common::TrieAccount; - - use super::*; - use alloy_primitives::{b256, hex}; use std::{collections::HashMap, str::FromStr}; + #[cfg(feature = "optimism")] + use reth_ethereum_forks::OptimismHardforks; + fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) { for (block, expected_id) in cases { let computed_id = spec.fork_id(block); @@ -1265,14 +1209,14 @@ mod tests { } } - fn test_hardfork_fork_ids(spec: &ChainSpec, cases: &[(Hardfork, ForkId)]) { + fn test_hardfork_fork_ids(spec: &ChainSpec, cases: &[(EthereumHardfork, ForkId)]) { for (hardfork, expected_id) in cases { if let Some(computed_id) = spec.hardfork_fork_id(*hardfork) { assert_eq!( expected_id, &computed_id, "Expected fork ID {expected_id:?}, computed fork ID {computed_id:?} for hardfork {hardfork}" ); - if matches!(hardfork, Hardfork::Shanghai) { + if matches!(hardfork, EthereumHardfork::Shanghai) { if let Some(shangai_id) = spec.shanghai_fork_id() { assert_eq!( expected_id, &shangai_id, @@ -1318,8 +1262,8 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(Genesis::default()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Shanghai, ForkCondition::Never) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Never) .build(); assert_eq!( spec.display_hardforks().to_string(), @@ -1334,21 +1278,21 @@ Post-merge hard forks (timestamp based): let spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(Genesis::default()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(0)) - .with_fork(Hardfork::Tangerine, ForkCondition::Block(0)) - .with_fork(Hardfork::SpuriousDragon, ForkCondition::Block(0)) - .with_fork(Hardfork::Byzantium, ForkCondition::Block(0)) - .with_fork(Hardfork::Constantinople, ForkCondition::Block(0)) - .with_fork(Hardfork::Istanbul, ForkCondition::Block(0)) - .with_fork(Hardfork::MuirGlacier, ForkCondition::Block(0)) - .with_fork(Hardfork::Berlin, ForkCondition::Block(0)) - .with_fork(Hardfork::London, ForkCondition::Block(0)) - .with_fork(Hardfork::ArrowGlacier, ForkCondition::Block(0)) - .with_fork(Hardfork::GrayGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Tangerine, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::SpuriousDragon, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Byzantium, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Constantinople, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Istanbul, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::MuirGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Berlin, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::London, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::ArrowGlacier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::GrayGlacier, ForkCondition::Block(0)) .build(); - assert_eq!(spec.hardforks().len(), 12, "12 forks should be active."); + assert_eq!(spec.deref().len(), 12, "12 forks should be active."); assert_eq!( spec.fork_id(&Head { number: 1, ..Default::default() }), ForkId { hash: ForkHash::from(spec.genesis_hash()), next: 0 }, @@ -1362,16 +1306,16 @@ Post-merge hard forks (timestamp based): let unique_spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(1)) .build(); let duplicate_spec = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(1)) - .with_fork(Hardfork::Tangerine, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(1)) + .with_fork(EthereumHardfork::Tangerine, ForkCondition::Block(1)) .build(); assert_eq!( @@ -1388,9 +1332,9 @@ Post-merge hard forks (timestamp based): let happy_path_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let happy_path_head = happy_path_case.satisfy(ForkCondition::Timestamp(11313123)); let happy_path_expected = Head { number: 73, timestamp: 11313123, ..Default::default() }; @@ -1402,10 +1346,10 @@ Post-merge hard forks (timestamp based): let multiple_timestamp_fork_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(11313398)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(11313398)) .build(); let multi_timestamp_head = multiple_timestamp_fork_case.satisfy(ForkCondition::Timestamp(11313398)); @@ -1419,7 +1363,7 @@ Post-merge hard forks (timestamp based): let no_block_fork_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let no_block_fork_head = no_block_fork_case.satisfy(ForkCondition::Timestamp(11313123)); let no_block_fork_expected = Head { number: 0, timestamp: 11313123, ..Default::default() }; @@ -1431,16 +1375,16 @@ Post-merge hard forks (timestamp based): let fork_cond_ttd_blocknum_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis.clone()) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) .with_fork( - Hardfork::Paris, + EthereumHardfork::Paris, ForkCondition::TTD { fork_block: Some(101), total_difficulty: U256::from(10_790_000), }, ) - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(11313123)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(11313123)) .build(); let fork_cond_ttd_blocknum_head = fork_cond_ttd_blocknum_case.satisfy(ForkCondition::Timestamp(11313123)); @@ -1457,8 +1401,8 @@ Post-merge hard forks (timestamp based): let fork_cond_block_only_case = ChainSpec::builder() .chain(Chain::mainnet()) .genesis(empty_genesis) - .with_fork(Hardfork::Frontier, ForkCondition::Block(0)) - .with_fork(Hardfork::Homestead, ForkCondition::Block(73)) + .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) + .with_fork(EthereumHardfork::Homestead, ForkCondition::Block(73)) .build(); let fork_cond_block_only_head = fork_cond_block_only_case.satisfy(ForkCondition::Block(73)); let fork_cond_block_only_expected = Head { number: 73, ..Default::default() }; @@ -1486,63 +1430,69 @@ Post-merge hard forks (timestamp based): &MAINNET, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xfc, 0x64, 0xec, 0x04]), next: 1150000 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0x97, 0xc2, 0xc3, 0x4c]), next: 1920000 }, ), - (Hardfork::Dao, ForkId { hash: ForkHash([0x91, 0xd1, 0xf9, 0x48]), next: 2463000 }), ( - Hardfork::Tangerine, + EthereumHardfork::Dao, + ForkId { hash: ForkHash([0x91, 0xd1, 0xf9, 0x48]), next: 2463000 }, + ), + ( + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0x7a, 0x64, 0xda, 0x13]), next: 2675000 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0x3e, 0xdd, 0x5b, 0x10]), next: 4370000 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xa0, 0x0b, 0xc3, 0x24]), next: 7280000 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0x66, 0x8d, 0xb0, 0xaf]), next: 9069000 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0x66, 0x8d, 0xb0, 0xaf]), next: 9069000 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0x87, 0x9d, 0x6e, 0x30]), next: 9200000 }, ), ( - Hardfork::MuirGlacier, + EthereumHardfork::MuirGlacier, ForkId { hash: ForkHash([0xe0, 0x29, 0xe9, 0x91]), next: 12244000 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0x0e, 0xb4, 0x40, 0xf6]), next: 12965000 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xb7, 0x15, 0x07, 0x7d]), next: 13773000 }, ), ( - Hardfork::ArrowGlacier, + EthereumHardfork::ArrowGlacier, ForkId { hash: ForkHash([0x20, 0xc3, 0x27, 0xfc]), next: 15050000 }, ), ( - Hardfork::GrayGlacier, + EthereumHardfork::GrayGlacier, ForkId { hash: ForkHash([0xf0, 0xaf, 0xd0, 0xe3]), next: 1681338455 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xdc, 0xe9, 0x6c, 0x2d]), next: 1710338135 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x9f, 0x3d, 0x22, 0x54]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x9f, 0x3d, 0x22, 0x54]), next: 0 }, + ), ], ); } @@ -1553,50 +1503,53 @@ Post-merge hard forks (timestamp based): &GOERLI, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Tangerine, + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0xa3, 0xf5, 0xab, 0x08]), next: 1561651 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0xc2, 0x5e, 0xfa, 0x5c]), next: 4460644 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0x75, 0x7a, 0x1c, 0x47]), next: 5062605 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xb8, 0xc6, 0x29, 0x9d]), next: 1678832736 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xf9, 0x84, 0x3a, 0xbf]), next: 1705473120 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x70, 0xcc, 0x14, 0xe2]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x70, 0xcc, 0x14, 0xe2]), next: 0 }, + ), ], ); } @@ -1607,54 +1560,57 @@ Post-merge hard forks (timestamp based): &SEPOLIA, &[ ( - Hardfork::Frontier, + EthereumHardfork::Frontier, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Homestead, + EthereumHardfork::Homestead, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Tangerine, + EthereumHardfork::Tangerine, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::SpuriousDragon, + EthereumHardfork::SpuriousDragon, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Byzantium, + EthereumHardfork::Byzantium, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Constantinople, + EthereumHardfork::Constantinople, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Petersburg, + EthereumHardfork::Petersburg, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Istanbul, + EthereumHardfork::Istanbul, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Berlin, + EthereumHardfork::Berlin, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::London, + EthereumHardfork::London, ForkId { hash: ForkHash([0xfe, 0x33, 0x66, 0xe7]), next: 1735371 }, ), ( - Hardfork::Paris, + EthereumHardfork::Paris, ForkId { hash: ForkHash([0xb9, 0x6c, 0xbd, 0x13]), next: 1677557088 }, ), ( - Hardfork::Shanghai, + EthereumHardfork::Shanghai, ForkId { hash: ForkHash([0xf7, 0xf9, 0xbc, 0x08]), next: 1706655072 }, ), - (Hardfork::Cancun, ForkId { hash: ForkHash([0x88, 0xcf, 0x81, 0xd9]), next: 0 }), + ( + EthereumHardfork::Cancun, + ForkId { hash: ForkHash([0x88, 0xcf, 0x81, 0xd9]), next: 0 }, + ), ], ); } @@ -2155,8 +2111,8 @@ Post-merge hard forks (timestamp based): cancun_time: u64, ) -> ChainSpec { builder - .with_fork(Hardfork::Shanghai, ForkCondition::Timestamp(shanghai_time)) - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(cancun_time)) + .with_fork(EthereumHardfork::Shanghai, ForkCondition::Timestamp(shanghai_time)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(cancun_time)) .build() } @@ -2211,14 +2167,14 @@ Post-merge hard forks (timestamp based): let terminal_block_ttd = U256::from(58750003716598352816469_u128); let terminal_block_difficulty = U256::from(11055787484078698_u128); assert!(!chainspec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(terminal_block_ttd, terminal_block_difficulty)); // Check that Paris is active on first PoS block #15537394. let first_pos_block_ttd = U256::from(58750003716598352816469_u128); let first_pos_difficulty = U256::ZERO; assert!(chainspec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(first_pos_block_ttd, first_pos_difficulty)); } @@ -2294,55 +2250,64 @@ Post-merge hard forks (timestamp based): // assert a bunch of hardforks that should be set assert_eq!( - chainspec.hardforks.get(&Hardfork::Homestead).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Homestead).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Tangerine).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Tangerine).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::SpuriousDragon).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::SpuriousDragon).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Byzantium).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Byzantium).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Constantinople).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Constantinople).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::Petersburg).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Petersburg).unwrap(), + ForkCondition::Block(0) ); - assert_eq!(chainspec.hardforks.get(&Hardfork::Istanbul).unwrap(), &ForkCondition::Block(0)); assert_eq!( - chainspec.hardforks.get(&Hardfork::MuirGlacier).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Istanbul).unwrap(), + ForkCondition::Block(0) ); - assert_eq!(chainspec.hardforks.get(&Hardfork::Berlin).unwrap(), &ForkCondition::Block(0)); - assert_eq!(chainspec.hardforks.get(&Hardfork::London).unwrap(), &ForkCondition::Block(0)); assert_eq!( - chainspec.hardforks.get(&Hardfork::ArrowGlacier).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::MuirGlacier).unwrap(), + ForkCondition::Block(0) ); assert_eq!( - chainspec.hardforks.get(&Hardfork::GrayGlacier).unwrap(), - &ForkCondition::Block(0) + chainspec.hardforks.get(EthereumHardfork::Berlin).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::London).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::ArrowGlacier).unwrap(), + ForkCondition::Block(0) + ); + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::GrayGlacier).unwrap(), + ForkCondition::Block(0) ); // including time based hardforks assert_eq!( - chainspec.hardforks.get(&Hardfork::Shanghai).unwrap(), - &ForkCondition::Timestamp(0) + chainspec.hardforks.get(EthereumHardfork::Shanghai).unwrap(), + ForkCondition::Timestamp(0) ); // including time based hardforks assert_eq!( - chainspec.hardforks.get(&Hardfork::Cancun).unwrap(), - &ForkCondition::Timestamp(1) + chainspec.hardforks.get(EthereumHardfork::Cancun).unwrap(), + ForkCondition::Timestamp(1) ); // alloc key -> expected rlp mapping @@ -2438,14 +2403,14 @@ Post-merge hard forks (timestamp based): hex!("9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360").into(); assert_eq!(chainspec.genesis_header().state_root, expected_state_root); let hard_forks = vec![ - Hardfork::Byzantium, - Hardfork::Homestead, - Hardfork::Istanbul, - Hardfork::Petersburg, - Hardfork::Constantinople, + EthereumHardfork::Byzantium, + EthereumHardfork::Homestead, + EthereumHardfork::Istanbul, + EthereumHardfork::Petersburg, + EthereumHardfork::Constantinople, ]; - for ref fork in hard_forks { - assert_eq!(chainspec.hardforks.get(fork).unwrap(), &ForkCondition::Block(0)); + for fork in hard_forks { + assert_eq!(chainspec.hardforks.get(fork).unwrap(), ForkCondition::Block(0)); } let expected_hash: B256 = @@ -2694,7 +2659,7 @@ Post-merge hard forks (timestamp based): #[test] fn holesky_paris_activated_at_genesis() { assert!(HOLESKY - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(HOLESKY.genesis.difficulty, HOLESKY.genesis.difficulty)); } @@ -2748,13 +2713,16 @@ Post-merge hard forks (timestamp based): chain: Chain::mainnet(), genesis: Genesis::default(), genesis_hash: None, - hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Frontier.boxed(), + ForkCondition::Never, + )]), paris_block_and_final_difficulty: None, deposit_contract: None, ..Default::default() }; - assert_eq!(spec.hardfork_fork_id(Hardfork::Frontier), None); + assert_eq!(spec.hardfork_fork_id(EthereumHardfork::Frontier), None); } #[test] @@ -2763,13 +2731,16 @@ Post-merge hard forks (timestamp based): chain: Chain::mainnet(), genesis: Genesis::default(), genesis_hash: None, - hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Shanghai.boxed(), + ForkCondition::Never, + )]), paris_block_and_final_difficulty: None, deposit_contract: None, ..Default::default() }; - assert_eq!(spec.hardfork_fork_filter(Hardfork::Shanghai), None); + assert_eq!(spec.hardfork_fork_filter(EthereumHardfork::Shanghai), None); } #[test] @@ -2887,17 +2858,17 @@ Post-merge hard forks (timestamp based): BaseFeeParamsKind::Constant(BaseFeeParams::new(70, 60)) ); - assert!(!chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 0)); + assert!(!chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 0)); - assert!(chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 10)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 20)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 30)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 40)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 50)); + assert!(chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 10)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 30)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 40)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 50)); } #[cfg(feature = "optimism")] @@ -2948,23 +2919,98 @@ Post-merge hard forks (timestamp based): chain_spec.base_fee_params, BaseFeeParamsKind::Variable( vec![ - (Hardfork::London, BaseFeeParams::new(70, 60)), - (Hardfork::Canyon, BaseFeeParams::new(80, 60)), + (EthereumHardfork::London.boxed(), BaseFeeParams::new(70, 60)), + (OptimismHardfork::Canyon.boxed(), BaseFeeParams::new(80, 60)), ] .into() ) ); - assert!(!chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 0)); - assert!(!chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 0)); - - assert!(chain_spec.is_fork_active_at_block(Hardfork::Bedrock, 10)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, 20)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, 30)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, 40)); - assert!(chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, 50)); + assert!(!chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 0)); + assert!(!chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 0)); + + assert!(chain_spec.is_fork_active_at_block(OptimismHardfork::Bedrock, 10)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, 30)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, 40)); + assert!(chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, 50)); + } + + #[cfg(feature = "optimism")] + #[test] + fn parse_genesis_optimism_with_variable_base_fee_params() { + let geth_genesis = r#" + { + "config": { + "chainId": 8453, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "mergeNetsplitBlock": 0, + "bedrockBlock": 0, + "regolithTime": 15, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "optimism": { + "eip1559Elasticity": 6, + "eip1559Denominator": 50 + } + } + } + "#; + let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); + let chainspec = ChainSpec::from(genesis.clone()); + + let actual_chain_id = genesis.config.chain_id; + assert_eq!(actual_chain_id, 8453); + + assert_eq!( + chainspec.hardforks.get(EthereumHardfork::Istanbul), + Some(ForkCondition::Block(0)) + ); + + let actual_bedrock_block = genesis.config.extra_fields.get("bedrockBlock"); + assert_eq!(actual_bedrock_block, Some(serde_json::Value::from(0)).as_ref()); + let actual_canyon_timestamp = genesis.config.extra_fields.get("canyonTime"); + assert_eq!(actual_canyon_timestamp, None); + + assert!(genesis.config.terminal_total_difficulty_passed); + + let optimism_object = genesis.config.extra_fields.get("optimism").unwrap(); + let optimism_base_fee_info = + serde_json::from_value::(optimism_object.clone()).unwrap(); + + assert_eq!( + optimism_base_fee_info, + OptimismBaseFeeInfo { + eip1559_elasticity: Some(6), + eip1559_denominator: Some(50), + eip1559_denominator_canyon: None, + } + ); + assert_eq!( + chainspec.base_fee_params, + BaseFeeParamsKind::Constant(BaseFeeParams { + max_change_denominator: 50, + elasticity_multiplier: 6, + }) + ); + + assert!(chainspec.is_fork_active_at_block(OptimismHardfork::Bedrock, 0)); + + assert!(chainspec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, 20)); } } diff --git a/crates/chainspec/src/taiko.rs b/crates/chainspec/src/taiko.rs new file mode 100644 index 000000000000..ee568b9bf961 --- /dev/null +++ b/crates/chainspec/src/taiko.rs @@ -0,0 +1,116 @@ +use std::collections::BTreeMap; + +use alloy_chains::Chain; +use alloy_genesis::{ChainConfig, Genesis, GenesisAccount}; +use revm_primitives::{Address, Bytes, FixedBytes, U256}; + +/// Taiko Chain Configuration, sets the chain_id to the internal devnet L2A by default. +pub fn taiko_base_config() -> ChainConfig { + ChainConfig { + chain_id: TaikoNamedChain::TaikoInternalL2A as u64, + homestead_block: Some(0), + dao_fork_block: None, + dao_fork_support: false, + eip150_block: Some(0), + eip150_hash: None, + eip155_block: Some(0), + eip158_block: Some(0), + byzantium_block: Some(0), + constantinople_block: Some(0), + petersburg_block: Some(0), + istanbul_block: Some(0), + muir_glacier_block: Some(0), + berlin_block: Some(0), + london_block: Some(0), + arrow_glacier_block: Some(0), + gray_glacier_block: Some(0), + merge_netsplit_block: None, + shanghai_time: Some(0), + cancun_time: Some(0), + terminal_total_difficulty: Some(U256::ZERO), + terminal_total_difficulty_passed: true, + ethash: None, + clique: None, + extra_fields: Default::default(), + prague_time: None, + parlia: None, + deposit_contract_address: None, + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, strum::IntoStaticStr)] // Into<&'static str>, AsRef, fmt::Display and serde::Serialize +#[derive(strum::VariantNames)] // NamedChain::VARIANTS +#[derive(strum::VariantArray)] // NamedChain::VARIANTS +#[derive(strum::EnumString)] // FromStr, TryFrom<&str> +#[derive(strum::EnumIter)] // NamedChain::iter +#[derive(strum::EnumCount)] // NamedChain::COUNT +#[derive(num_enum::TryFromPrimitive)] // TryFrom +#[cfg_attr(feature = "serde", derive(serde::Deserialize))] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[strum(serialize_all = "kebab-case")] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[repr(u64)] +pub enum TaikoNamedChain { + #[cfg_attr(feature = "serde", serde(alias = "taiko-internal-l2a"))] + TaikoInternalL2A = 167001, + #[cfg_attr(feature = "serde", serde(alias = "taiko-internal-l2b"))] + TaikoInternalL2B = 167002, + #[cfg_attr(feature = "serde", serde(alias = "snaefellsjokull"))] + Snaefellsjokull = 167003, + #[cfg_attr(feature = "serde", serde(alias = "askja"))] + Askja = 167004, + #[cfg_attr(feature = "serde", serde(alias = "grimsvotn"))] + Grimsvotn = 167005, + #[cfg_attr(feature = "serde", serde(alias = "eldfell"))] + Eldfell = 167006, + #[cfg_attr(feature = "serde", serde(alias = "jolnir"))] + Jolnir = 167007, + #[cfg_attr(feature = "serde", serde(alias = "katla"))] + Katla = 167008, +} + +impl From for Chain { + fn from(val: TaikoNamedChain) -> Self { + Chain::from_id_unchecked(val as u64) + } +} + +pub fn get_taiko_genesis(chain: TaikoNamedChain) -> Genesis { + let alloc_str = match chain { + TaikoNamedChain::TaikoInternalL2A => { + include_str!("../../res/genesis/taiko/internal_l2a.json") + } + TaikoNamedChain::TaikoInternalL2B => { + include_str!("../../res/genesis/taiko/internal_l2b.json") + } + TaikoNamedChain::Snaefellsjokull => { + include_str!("../../res/genesis/taiko/snaefellsjokull.json") + } + TaikoNamedChain::Askja => include_str!("../../res/genesis/taiko/askja.json"), + TaikoNamedChain::Grimsvotn => include_str!("../../res/genesis/taiko/grimsvotn.json"), + TaikoNamedChain::Eldfell => include_str!("../../res/genesis/taiko/eldfell.json"), + TaikoNamedChain::Jolnir => include_str!("../../res/genesis/taiko/jolnir.json"), + TaikoNamedChain::Katla => include_str!("../../res/genesis/taiko/katla.json"), + }; + + let alloc: BTreeMap = + serde_json::from_str(alloc_str).expect("Invalid alloc json"); + let mut config = taiko_base_config(); + config.chain_id = chain as u64; + + Genesis { + config, + alloc, + nonce: 0, + timestamp: 0, + extra_data: Bytes::new(), + gas_limit: 15_000_000, + difficulty: U256::from(0), + mix_hash: FixedBytes::ZERO, + coinbase: Address::ZERO, + base_fee_per_gas: Some(10_000_000), + excess_blob_gas: None, + blob_gas_used: Some(0), + number: Some(0), + } +} diff --git a/crates/cli/cli/Cargo.toml b/crates/cli/cli/Cargo.toml new file mode 100644 index 000000000000..c2aa22e70e71 --- /dev/null +++ b/crates/cli/cli/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "reth-cli" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] + + +[dependencies] +# reth +reth-cli-runner.workspace = true + +# misc +clap.workspace = true diff --git a/crates/cli/cli/src/lib.rs b/crates/cli/cli/src/lib.rs new file mode 100644 index 000000000000..ccaa900edbd7 --- /dev/null +++ b/crates/cli/cli/src/lib.rs @@ -0,0 +1,68 @@ +//! Cli abstraction for reth based nodes. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +use std::{borrow::Cow, ffi::OsString}; + +use reth_cli_runner::CliRunner; + +use clap::{Error, Parser}; + +/// Reth based node cli. +/// +/// This trait is supposed to be implemented by the main struct of the CLI. +/// +/// It provides commonly used functionality for running commands and information about the CL, such +/// as the name and version. +pub trait RethCli: Sized { + /// The name of the implementation, eg. `reth`, `op-reth`, etc. + fn name(&self) -> Cow<'static, str>; + + /// The version of the node, such as `reth/v1.0.0` + fn version(&self) -> Cow<'static, str>; + + /// Parse args from iterator from [`std::env::args_os()`]. + fn parse_args() -> Result + where + Self: Parser + Sized, + { + ::try_parse_from(std::env::args_os()) + } + + /// Parse args from the given iterator. + fn try_parse_from(itr: I) -> Result + where + Self: Parser + Sized, + I: IntoIterator, + T: Into + Clone, + { + ::try_parse_from(itr) + } + + /// Executes a command. + fn with_runner(self, f: F) -> R + where + F: FnOnce(Self, CliRunner) -> R, + { + let runner = CliRunner::default(); + + f(self, runner) + } + + /// Parses and executes a command. + fn execute(f: F) -> Result + where + Self: Parser + Sized, + F: FnOnce(Self, CliRunner) -> R, + { + let cli = Self::parse_args()?; + + Ok(cli.with_runner(f)) + } +} diff --git a/crates/cli/commands/Cargo.toml b/crates/cli/commands/Cargo.toml new file mode 100644 index 000000000000..d12abefcd8b0 --- /dev/null +++ b/crates/cli/commands/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "reth-cli-commands" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] diff --git a/crates/cli/commands/src/lib.rs b/crates/cli/commands/src/lib.rs new file mode 100644 index 000000000000..33983bb856db --- /dev/null +++ b/crates/cli/commands/src/lib.rs @@ -0,0 +1,9 @@ +//! Commonly used reth CLI commands. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 527f5b1538ed..91dcfc772e9c 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -12,8 +12,9 @@ workspace = true [dependencies] # reth -reth-network.workspace = true +reth-network-types = { workspace = true, features = ["serde"] } reth-prune-types.workspace = true +reth-stages-types.workspace = true # serde serde.workspace = true diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index f458ef41646f..fa498f66c9c8 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -1,7 +1,8 @@ //! Configuration files. -use reth_network::{PeersConfig, SessionsConfig}; +use reth_network_types::{PeersConfig, SessionsConfig}; use reth_prune_types::PruneModes; +use reth_stages_types::ExecutionStageThresholds; use serde::{Deserialize, Deserializer, Serialize}; use std::{ ffi::OsStr, @@ -53,7 +54,7 @@ impl Config { } /// Sets the pruning configuration. - pub fn update_prune_confing(&mut self, prune_config: PruneConfig) { + pub fn update_prune_config(&mut self, prune_config: PruneConfig) { self.prune = Some(prune_config); } } @@ -216,6 +217,17 @@ impl Default for ExecutionConfig { } } +impl From for ExecutionStageThresholds { + fn from(config: ExecutionConfig) -> Self { + Self { + max_blocks: config.max_blocks, + max_changes: config.max_changes, + max_cumulative_gas: config.max_cumulative_gas, + max_duration: config.max_duration, + } + } +} + /// Hashing stage configuration. #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Eq, Serialize)] #[serde(default)] diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index ba6c67487e20..2fd93e7caab6 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -16,7 +16,7 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use reth_beacon_consensus::BeaconEngineMessage; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_engine_primitives::EngineTypes; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index bf74df0f7598..fa7dc18178c4 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -80,3 +80,8 @@ optimism = [ "reth-blockchain-tree/optimism", "reth-rpc/optimism", ] +taiko = [ + "reth-primitives/taiko", + "reth-payload-builder/taiko", + "reth-payload-validator/taiko", +] diff --git a/crates/consensus/beacon/src/engine/forkchoice.rs b/crates/consensus/beacon/src/engine/forkchoice.rs index afd19f6079eb..491d0ff8aade 100644 --- a/crates/consensus/beacon/src/engine/forkchoice.rs +++ b/crates/consensus/beacon/src/engine/forkchoice.rs @@ -3,7 +3,7 @@ use reth_rpc_types::engine::{ForkchoiceState, PayloadStatusEnum}; /// The struct that keeps track of the received forkchoice state and their status. #[derive(Debug, Clone, Default)] -pub(crate) struct ForkchoiceStateTracker { +pub struct ForkchoiceStateTracker { /// The latest forkchoice state that we received. /// /// Caution: this can be invalid. @@ -76,7 +76,7 @@ impl ForkchoiceStateTracker { } /// Returns the last received `ForkchoiceState` to which we need to sync. - pub(crate) const fn sync_target_state(&self) -> Option { + pub const fn sync_target_state(&self) -> Option { self.last_syncing } @@ -139,9 +139,12 @@ impl From for ForkchoiceStatus { /// A helper type to check represent hashes of a [`ForkchoiceState`] #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum ForkchoiceStateHash { +pub enum ForkchoiceStateHash { + /// Head hash of the [`ForkchoiceState`]. Head(B256), + /// Safe hash of the [`ForkchoiceState`]. Safe(B256), + /// Finalized hash of the [`ForkchoiceState`]. Finalized(B256), } diff --git a/crates/consensus/beacon/src/engine/handle.rs b/crates/consensus/beacon/src/engine/handle.rs index 0f0d9e1da80b..c11a9ccab6e3 100644 --- a/crates/consensus/beacon/src/engine/handle.rs +++ b/crates/consensus/beacon/src/engine/handle.rs @@ -13,6 +13,9 @@ use reth_rpc_types::engine::{ use reth_tokio_util::{EventSender, EventStream}; use tokio::sync::{mpsc::UnboundedSender, oneshot}; +#[cfg(feature = "taiko")] +use reth_payload_builder::TaikoExecutionPayload; + /// A _shareable_ beacon consensus frontend type. Used to interact with the spawned beacon consensus /// engine task. /// @@ -45,7 +48,8 @@ where /// See also pub async fn new_payload( &self, - payload: ExecutionPayload, + #[cfg(not(feature = "taiko"))] payload: ExecutionPayload, + #[cfg(feature = "taiko")] payload: TaikoExecutionPayload, cancun_fields: Option, ) -> Result { let (tx, rx) = oneshot::channel(); diff --git a/crates/consensus/beacon/src/engine/invalid_headers.rs b/crates/consensus/beacon/src/engine/invalid_headers.rs index 2a37c60014da..ebce1faf92dc 100644 --- a/crates/consensus/beacon/src/engine/invalid_headers.rs +++ b/crates/consensus/beacon/src/engine/invalid_headers.rs @@ -14,7 +14,8 @@ use tracing::warn; const INVALID_HEADER_HIT_EVICTION_THRESHOLD: u8 = 128; /// Keeps track of invalid headers. -pub(crate) struct InvalidHeaderCache { +#[derive(Debug)] +pub struct InvalidHeaderCache { /// This maps a header hash to a reference to its invalid ancestor. headers: LruMap, /// Metrics for the cache. @@ -34,7 +35,7 @@ impl InvalidHeaderCache { /// /// If this is called, the hit count for the entry is incremented. /// If the hit count exceeds the threshold, the entry is evicted and `None` is returned. - pub(crate) fn get(&mut self, hash: &B256) -> Option> { + pub fn get(&mut self, hash: &B256) -> Option> { { let entry = self.headers.get(hash)?; entry.hit_count += 1; @@ -49,7 +50,7 @@ impl InvalidHeaderCache { } /// Inserts an invalid block into the cache, with a given invalid ancestor. - pub(crate) fn insert_with_invalid_ancestor( + pub fn insert_with_invalid_ancestor( &mut self, header_hash: B256, invalid_ancestor: Arc
, diff --git a/crates/consensus/beacon/src/engine/message.rs b/crates/consensus/beacon/src/engine/message.rs index 052b275c181d..3e7bcae9aff2 100644 --- a/crates/consensus/beacon/src/engine/message.rs +++ b/crates/consensus/beacon/src/engine/message.rs @@ -3,6 +3,8 @@ use futures::{future::Either, FutureExt}; use reth_engine_primitives::EngineTypes; use reth_errors::RethResult; use reth_payload_builder::error::PayloadBuilderError; +#[cfg(feature = "taiko")] +use reth_payload_builder::TaikoExecutionPayload; use reth_rpc_types::engine::{ CancunPayloadFields, ExecutionPayload, ForkChoiceUpdateResult, ForkchoiceState, ForkchoiceUpdateError, ForkchoiceUpdated, PayloadId, PayloadStatus, PayloadStatusEnum, @@ -142,7 +144,10 @@ pub enum BeaconEngineMessage { /// Message with new payload. NewPayload { /// The execution payload received by Engine API. + #[cfg(not(feature = "taiko"))] payload: ExecutionPayload, + #[cfg(feature = "taiko")] + payload: TaikoExecutionPayload, /// The cancun-related newPayload fields, if any. cancun_fields: Option, /// The sender for returning payload status result. diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index 3391a1de95e5..bb2b486096b4 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -15,13 +15,15 @@ use reth_network_p2p::{ use reth_payload_builder::PayloadBuilderHandle; use reth_payload_primitives::{PayloadAttributes, PayloadBuilderAttributes}; use reth_payload_validator::ExecutionPayloadValidator; +#[cfg(feature = "taiko")] +use reth_payload_builder::{TaikoExecutionPayload, TaikoPayloadAttributes}; use reth_primitives::{ constants::EPOCH_SLOTS, BlockNumHash, BlockNumber, Head, Header, SealedBlock, SealedHeader, B256, }; use reth_provider::{ - BlockIdReader, BlockReader, BlockSource, CanonChainTracker, ChainSpecProvider, ProviderError, - StageCheckpointReader, + BlockIdReader, BlockReader, BlockSource, CanonChainTracker, ChainSpecProvider, L1OriginWriter, + ProviderError, StageCheckpointReader, }; use reth_rpc_types::engine::{ CancunPayloadFields, ExecutionPayload, ForkchoiceState, PayloadStatus, PayloadStatusEnum, @@ -53,7 +55,7 @@ pub use error::{ }; mod invalid_headers; -use invalid_headers::InvalidHeaderCache; +pub use invalid_headers::InvalidHeaderCache; mod event; pub use event::{BeaconConsensusEngineEvent, ConsensusEngineLiveSyncProgress}; @@ -62,13 +64,12 @@ mod handle; pub use handle::BeaconConsensusEngineHandle; mod forkchoice; -pub use forkchoice::ForkchoiceStatus; -use forkchoice::{ForkchoiceStateHash, ForkchoiceStateTracker}; +pub use forkchoice::{ForkchoiceStateHash, ForkchoiceStateTracker, ForkchoiceStatus}; mod metrics; use metrics::EngineMetrics; -pub(crate) mod sync; +pub mod sync; use sync::{EngineSyncController, EngineSyncEvent}; /// Hooks for running during the main loop of @@ -165,7 +166,8 @@ where + BlockReader + BlockIdReader + CanonChainTracker - + StageCheckpointReader, + + StageCheckpointReader + + L1OriginWriter, EngineT: EngineTypes, { /// Controls syncing triggered by engine updates. @@ -227,6 +229,7 @@ where + CanonChainTracker + StageCheckpointReader + ChainSpecProvider + + L1OriginWriter + 'static, Client: HeadersClient + BodiesClient + Clone + Unpin + 'static, EngineT: EngineTypes + Unpin + 'static, @@ -460,7 +463,7 @@ where current_head_num=?head.number, "[Optimism] Allowing beacon reorg to old head" ); - return true + return true; } // 2. Client software MAY skip an update of the forkchoice state and MUST NOT begin a @@ -604,7 +607,7 @@ where inconsistent_stage_checkpoint = stage_checkpoint, "Pipeline sync progress is inconsistent" ); - return Ok(self.blockchain.block_hash(first_stage_checkpoint)?) + return Ok(self.blockchain.block_hash(first_stage_checkpoint)?); } } @@ -682,7 +685,7 @@ where if !state.finalized_block_hash.is_zero() { // we don't have the block yet and the distance exceeds the allowed // threshold - return Some(state.finalized_block_hash) + return Some(state.finalized_block_hash); } // OPTIMISTIC SYNCING @@ -851,10 +854,10 @@ where // // This ensures that the finalized block is consistent with the head block, i.e. the // finalized block is an ancestor of the head block. - if !state.finalized_block_hash.is_zero() && - !self.blockchain.is_canonical(state.finalized_block_hash)? + if !state.finalized_block_hash.is_zero() + && !self.blockchain.is_canonical(state.finalized_block_hash)? { - return Ok(Some(OnForkChoiceUpdated::invalid_state())) + return Ok(Some(OnForkChoiceUpdated::invalid_state())); } // Finalized block is consistent, so update it in the canon chain tracker. @@ -865,10 +868,10 @@ where // // This ensures that the safe block is consistent with the head block, i.e. the safe // block is an ancestor of the head block. - if !state.safe_block_hash.is_zero() && - !self.blockchain.is_canonical(state.safe_block_hash)? + if !state.safe_block_hash.is_zero() + && !self.blockchain.is_canonical(state.safe_block_hash)? { - return Ok(Some(OnForkChoiceUpdated::invalid_state())) + return Ok(Some(OnForkChoiceUpdated::invalid_state())); } // Safe block is consistent, so update it in the canon chain tracker. @@ -929,7 +932,7 @@ where if !safe_block_hash.is_zero() { if self.blockchain.safe_block_hash()? == Some(safe_block_hash) { // nothing to update - return Ok(()) + return Ok(()); } let safe = self @@ -949,7 +952,7 @@ where if !finalized_block_hash.is_zero() { if self.blockchain.finalized_block_hash()? == Some(finalized_block_hash) { // nothing to update - return Ok(()) + return Ok(()); } let finalized = self @@ -1073,7 +1076,8 @@ where #[instrument(level = "trace", skip(self, payload, cancun_fields), fields(block_hash = ?payload.block_hash(), block_number = %payload.block_number(), is_pipeline_idle = %self.sync.is_pipeline_idle()), target = "consensus::engine")] fn on_new_payload( &mut self, - payload: ExecutionPayload, + #[cfg(not(feature = "taiko"))] payload: ExecutionPayload, + #[cfg(feature = "taiko")] payload: TaikoExecutionPayload, cancun_fields: Option, ) -> Result, BeaconOnNewPayloadError> { self.metrics.new_payload_messages.increment(1); @@ -1161,7 +1165,7 @@ where // begin a payload build process. In such an event, the forkchoiceState update MUST NOT // be rolled back. if attrs.timestamp() <= head.timestamp { - return OnForkChoiceUpdated::invalid_payload_attributes() + return OnForkChoiceUpdated::invalid_payload_attributes(); } // 8. Client software MUST begin a payload build process building on top of @@ -1249,15 +1253,15 @@ where latest_valid_hash = Some(block_hash); PayloadStatusEnum::Valid } - InsertPayloadOk::Inserted(BlockStatus::Disconnected { .. }) | - InsertPayloadOk::AlreadySeen(BlockStatus::Disconnected { .. }) => { + InsertPayloadOk::Inserted(BlockStatus::Disconnected { .. }) + | InsertPayloadOk::AlreadySeen(BlockStatus::Disconnected { .. }) => { // check if the block's parent is already marked as invalid if let Some(status) = self.check_invalid_ancestor_with_head(block.parent_hash, block.hash()).map_err( |error| InsertBlockError::new(block, InsertBlockErrorKind::Provider(error)), )? { - return Ok(status) + return Ok(status); } // not known to be invalid, but we don't know anything else @@ -1293,7 +1297,7 @@ where // threshold self.sync.set_pipeline_sync_target(target.into()); // we can exit early here because the pipeline will take care of syncing - return + return; } // continue downloading the missing parent @@ -1424,7 +1428,7 @@ where } EngineSyncEvent::PipelineTaskDropped => { error!(target: "consensus::engine", "Failed to receive spawned pipeline"); - return Err(BeaconConsensusEngineError::PipelineChannelClosed) + return Err(BeaconConsensusEngineError::PipelineChannelClosed); } }; @@ -1441,7 +1445,7 @@ where warn!(target: "consensus::engine", invalid_hash=?bad_block.hash(), invalid_number=?bad_block.number, "Bad block detected in unwind"); // update the `invalid_headers` cache with the new invalid header self.invalid_headers.insert(*bad_block); - return Ok(()) + return Ok(()); } let sync_target_state = match self.forkchoice_state_tracker.sync_target_state() { @@ -1450,7 +1454,7 @@ where // This is only possible if the node was run with `debug.tip` // argument and without CL. warn!(target: "consensus::engine", "No fork choice state available"); - return Ok(()) + return Ok(()); } }; @@ -1491,7 +1495,7 @@ where head = %sync_target_state.head_block_hash, "Current head has an invalid ancestor" ); - return Ok(()) + return Ok(()); } // get the block number of the finalized block, if we have it @@ -1793,6 +1797,7 @@ where + CanonChainTracker + StageCheckpointReader + ChainSpecProvider + + L1OriginWriter + Unpin + 'static, EngineT: EngineTypes + Unpin + 'static, @@ -1813,7 +1818,7 @@ where this.hooks.poll_active_db_write_hook(cx, this.current_engine_hook_context()?)? { this.on_hook_result(result)?; - continue + continue; } // Process any blockchain tree action result as set forth during engine message @@ -1872,12 +1877,12 @@ where this.blockchain.on_transition_configuration_exchanged(); } } - continue + continue; } // Both running hook with db write access and engine messages are pending, // proceed to other polls - break + break; } // process sync events if any @@ -1909,13 +1914,13 @@ where // ensure we're polling until pending while also checking for new engine // messages before polling the next hook - continue 'main + continue 'main; } } // incoming engine messages and sync events are drained, so we can yield back // control - return Poll::Pending + return Poll::Pending; } } } @@ -2064,7 +2069,7 @@ mod tests { result, Err(BeaconConsensusEngineError::Pipeline(n)) if matches!(*n.as_ref(), PipelineError::Stage(StageError::ChannelClosed)) ); - break + break; } Err(TryRecvError::Empty) => { let _ = env @@ -2492,7 +2497,7 @@ mod tests { use super::*; use alloy_genesis::Genesis; use reth_db::test_utils::create_test_static_files_dir; - use reth_primitives::{Hardfork, U256}; + use reth_primitives::{EthereumHardfork, U256}; use reth_provider::{ providers::StaticFileProvider, test_utils::blocks::BlockchainTestData, }; @@ -2721,9 +2726,9 @@ mod tests { async fn payload_pre_merge() { let data = BlockchainTestData::default(); let mut block1 = data.blocks[0].0.block.clone(); - block1 - .header - .set_difficulty(MAINNET.fork(Hardfork::Paris).ttd().unwrap() - U256::from(1)); + block1.header.set_difficulty( + MAINNET.fork(EthereumHardfork::Paris).ttd().unwrap() - U256::from(1), + ); block1 = block1.unseal().seal_slow(); let (block2, exec_result2) = data.blocks[1].clone(); let mut block2 = block2.unseal().block; diff --git a/crates/consensus/common/src/calc.rs b/crates/consensus/common/src/calc.rs index 27320700b33e..feb7bff0d908 100644 --- a/crates/consensus/common/src/calc.rs +++ b/crates/consensus/common/src/calc.rs @@ -1,4 +1,4 @@ -use reth_chainspec::{Chain, ChainSpec, Hardfork}; +use reth_chainspec::{Chain, ChainSpec, EthereumHardfork}; use reth_primitives::{constants::ETH_TO_WEI, BlockNumber, U256}; /// Calculates the base block reward. @@ -26,7 +26,7 @@ pub fn base_block_reward( block_difficulty: U256, total_difficulty: U256, ) -> Option { - if chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) || + if chain_spec.fork(EthereumHardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) || chain_spec.chain == Chain::goerli() { None @@ -39,9 +39,9 @@ pub fn base_block_reward( /// /// Caution: The caller must ensure that the block number is before the merge. pub fn base_block_reward_pre_merge(chain_spec: &ChainSpec, block_number: BlockNumber) -> u128 { - if chain_spec.fork(Hardfork::Constantinople).active_at_block(block_number) { + if chain_spec.fork(EthereumHardfork::Constantinople).active_at_block(block_number) { ETH_TO_WEI * 2 - } else if chain_spec.fork(Hardfork::Byzantium).active_at_block(block_number) { + } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_block(block_number) { ETH_TO_WEI * 3 } else { ETH_TO_WEI * 5 diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index 31bde166ece0..a2ebd3f6c545 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -1,6 +1,6 @@ //! Collection of methods for block validation. -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ constants::{ @@ -8,7 +8,7 @@ use reth_primitives::{ MAXIMUM_EXTRA_DATA_SIZE, }, eip4844::calculate_excess_blob_gas, - GotExpected, Hardfork, Header, SealedBlock, SealedHeader, + EthereumHardfork, GotExpected, Header, SealedBlock, SealedHeader, }; /// Gas used needs to be less than gas limit. Gas used is going to be checked after execution. @@ -29,7 +29,7 @@ pub fn validate_header_base_fee( header: &SealedHeader, chain_spec: &ChainSpec, ) -> Result<(), ConsensusError> { - if chain_spec.fork(Hardfork::London).active_at_block(header.number) && + if chain_spec.is_fork_active_at_block(EthereumHardfork::London, header.number) && header.base_fee_per_gas.is_none() { return Err(ConsensusError::BaseFeeMissing) @@ -152,8 +152,9 @@ pub fn validate_4844_header_standalone(header: &SealedHeader) -> Result<(), Cons /// This must be 32 bytes or fewer; formally Hx. #[inline] pub fn validate_header_extradata(header: &Header) -> Result<(), ConsensusError> { - if header.extra_data.len() > MAXIMUM_EXTRA_DATA_SIZE { - Err(ConsensusError::ExtraDataExceedsMax { len: header.extra_data.len() }) + let extradata_len = header.extra_data.len(); + if extradata_len > MAXIMUM_EXTRA_DATA_SIZE { + Err(ConsensusError::ExtraDataExceedsMax { len: extradata_len }) } else { Ok(()) } @@ -192,11 +193,11 @@ pub fn validate_against_parent_eip1559_base_fee( parent: &SealedHeader, chain_spec: &ChainSpec, ) -> Result<(), ConsensusError> { - if chain_spec.fork(Hardfork::London).active_at_block(header.number) { + if chain_spec.fork(EthereumHardfork::London).active_at_block(header.number) { let base_fee = header.base_fee_per_gas.ok_or(ConsensusError::BaseFeeMissing)?; let expected_base_fee = - if chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + if chain_spec.fork(EthereumHardfork::London).transitions_at_block(header.number) { reth_primitives::constants::EIP1559_INITIAL_BASE_FEE } else { // This BaseFeeMissing will not happen as previous blocks are checked to have diff --git a/crates/e2e-test-utils/Cargo.toml b/crates/e2e-test-utils/Cargo.toml index 2855ecc51c40..a610d5569684 100644 --- a/crates/e2e-test-utils/Cargo.toml +++ b/crates/e2e-test-utils/Cargo.toml @@ -21,6 +21,7 @@ reth-provider.workspace = true reth-node-builder.workspace = true reth-tokio-util.workspace = true reth-stages-types.workspace = true +reth-network-peers.workspace = true jsonrpsee.workspace = true diff --git a/crates/e2e-test-utils/src/network.rs b/crates/e2e-test-utils/src/network.rs index b575d7001dda..e5791afd76f8 100644 --- a/crates/e2e-test-utils/src/network.rs +++ b/crates/e2e-test-utils/src/network.rs @@ -1,6 +1,9 @@ use futures_util::StreamExt; -use reth::network::{NetworkEvent, NetworkEvents, NetworkHandle, PeersInfo}; -use reth_chainspec::net::NodeRecord; +use reth::{ + network::{NetworkEvent, NetworkEvents, NetworkHandle, PeersInfo}, + rpc::types::PeerId, +}; +use reth_network_peers::NodeRecord; use reth_tokio_util::EventStream; use reth_tracing::tracing::info; @@ -23,7 +26,7 @@ impl NetworkTestContext { match self.network_events.next().await { Some(NetworkEvent::PeerAdded(_)) => (), - _ => panic!("Expected a peer added event"), + ev => panic!("Expected a peer added event, got: {ev:?}"), } } @@ -32,13 +35,17 @@ impl NetworkTestContext { self.network.local_node_record() } - /// Expects a session to be established - pub async fn expect_session(&mut self) { - match self.network_events.next().await { - Some(NetworkEvent::SessionEstablished { remote_addr, .. }) => { - info!(?remote_addr, "Session established") + /// Awaits the next event for an established session. + pub async fn next_session_established(&mut self) -> Option { + while let Some(ev) = self.network_events.next().await { + match ev { + NetworkEvent::SessionEstablished { peer_id, .. } => { + info!("Session established with peer: {:?}", peer_id); + return Some(peer_id) + } + _ => continue, } - _ => panic!("Expected session established event"), } + None } } diff --git a/crates/e2e-test-utils/src/node.rs b/crates/e2e-test-utils/src/node.rs index 524a5d5562be..684e0f401c1b 100644 --- a/crates/e2e-test-utils/src/node.rs +++ b/crates/e2e-test-utils/src/node.rs @@ -52,11 +52,11 @@ where }) } + /// Establish a connection to the node pub async fn connect(&mut self, node: &mut NodeTestContext) { self.network.add_peer(node.network.record()).await; - node.network.add_peer(self.network.record()).await; - node.network.expect_session().await; - self.network.expect_session().await; + node.network.next_session_established().await; + self.network.next_session_established().await; } /// Advances the chain `length` blocks. diff --git a/crates/e2e-test-utils/src/rpc.rs b/crates/e2e-test-utils/src/rpc.rs index 09f161a91dc7..b05d5df895a0 100644 --- a/crates/e2e-test-utils/src/rpc.rs +++ b/crates/e2e-test-utils/src/rpc.rs @@ -1,8 +1,13 @@ use alloy_consensus::TxEnvelope; use alloy_network::eip2718::Decodable2718; -use reth::{api::FullNodeComponents, builder::rpc::RpcRegistry, rpc::api::DebugApiServer}; +use reth::{ + builder::{rpc::RpcRegistry, FullNodeComponents}, + rpc::{ + api::{eth::helpers::EthTransactions, DebugApiServer}, + server_types::eth::EthResult, + }, +}; use reth_primitives::{Bytes, B256}; -use reth_rpc::eth::{error::EthResult, EthTransactions}; pub struct RpcTestContext { pub inner: RpcRegistry, diff --git a/crates/engine-primitives/Cargo.toml b/crates/engine/primitives/Cargo.toml similarity index 100% rename from crates/engine-primitives/Cargo.toml rename to crates/engine/primitives/Cargo.toml diff --git a/crates/engine-primitives/src/error.rs b/crates/engine/primitives/src/error.rs similarity index 100% rename from crates/engine-primitives/src/error.rs rename to crates/engine/primitives/src/error.rs diff --git a/crates/engine-primitives/src/lib.rs b/crates/engine/primitives/src/lib.rs similarity index 100% rename from crates/engine-primitives/src/lib.rs rename to crates/engine/primitives/src/lib.rs diff --git a/crates/engine/tree/Cargo.toml b/crates/engine/tree/Cargo.toml new file mode 100644 index 000000000000..bcc8ae34bddd --- /dev/null +++ b/crates/engine/tree/Cargo.toml @@ -0,0 +1,64 @@ +[package] +name = "reth-engine-tree" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +# reth +reth-beacon-consensus.workspace = true +reth-blockchain-tree.workspace = true +reth-blockchain-tree-api.workspace = true +reth-chainspec.workspace = true +reth-consensus.workspace = true +reth-db.workspace = true +reth-db-api.workspace = true +reth-engine-primitives.workspace = true +reth-errors.workspace = true +reth-ethereum-consensus.workspace = true +reth-evm.workspace = true +reth-network-p2p.workspace = true +reth-payload-builder.workspace = true +reth-payload-primitives.workspace = true +reth-payload-validator.workspace = true +reth-primitives.workspace = true +reth-provider.workspace = true +reth-prune.workspace = true +reth-revm.workspace = true +reth-rpc-types.workspace = true +reth-stages-api.workspace = true +reth-static-file.workspace = true +reth-tasks.workspace = true +reth-tokio-util.workspace = true +reth-trie.workspace = true +revm.workspace = true + +# common +futures.workspace = true +tokio = { workspace = true, features = ["macros", "sync"] } +tokio-stream = { workspace = true, features = ["sync"] } + + +# metrics +metrics.workspace = true +reth-metrics = { workspace = true, features = ["common"] } + +# misc +aquamarine.workspace = true +parking_lot.workspace = true +tracing.workspace = true + +[dev-dependencies] +# reth +reth-network-p2p = { workspace = true, features = ["test-utils"] } +reth-prune-types.workspace = true +reth-stages = { workspace = true, features = ["test-utils"] } +reth-tracing.workspace = true + +assert_matches.workspace = true \ No newline at end of file diff --git a/crates/engine/tree/src/backfill.rs b/crates/engine/tree/src/backfill.rs new file mode 100644 index 000000000000..ec0b4ef06cc7 --- /dev/null +++ b/crates/engine/tree/src/backfill.rs @@ -0,0 +1,342 @@ +//! It is expected that the node has two sync modes: +//! +//! - Backfill sync: Sync to a certain block height in stages, e.g. download data from p2p then +//! execute that range. +//! - Live sync: In this mode the nodes is keeping up with the latest tip and listens for new +//! requests from the consensus client. +//! +//! These modes are mutually exclusive and the node can only be in one mode at a time. + +use futures::FutureExt; +use reth_db_api::database::Database; +use reth_stages_api::{ControlFlow, Pipeline, PipelineError, PipelineTarget, PipelineWithResult}; +use reth_tasks::TaskSpawner; +use std::task::{ready, Context, Poll}; +use tokio::sync::oneshot; +use tracing::trace; + +/// Backfill sync mode functionality. +pub trait BackfillSync: Send + Sync { + /// Performs a backfill action. + fn on_action(&mut self, action: BackfillAction); + + /// Polls the pipeline for completion. + fn poll(&mut self, cx: &mut Context<'_>) -> Poll; +} + +/// The backfill actions that can be performed. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BackfillAction { + /// Start backfilling with the given target. + Start(PipelineTarget), +} + +/// The events that can be emitted on backfill sync. +#[derive(Debug)] +pub enum BackfillEvent { + /// Backfill sync idle. + Idle, + /// Backfill sync started. + Started(PipelineTarget), + /// Backfill sync finished. + /// + /// If this is returned, backfill sync is idle. + Finished(Result), + /// Sync task was dropped after it was started, unable to receive it because + /// channel closed. This would indicate a panicked task. + TaskDropped(String), +} + +/// Pipeline sync. +#[derive(Debug)] +pub struct PipelineSync +where + DB: Database, +{ + /// The type that can spawn the pipeline task. + pipeline_task_spawner: Box, + /// The current state of the pipeline. + /// The pipeline is used for large ranges. + pipeline_state: PipelineState, + /// Pending target block for the pipeline to sync + pending_pipeline_target: Option, +} + +impl PipelineSync +where + DB: Database + 'static, +{ + /// Create a new instance. + pub fn new(pipeline: Pipeline, pipeline_task_spawner: Box) -> Self { + Self { + pipeline_task_spawner, + pipeline_state: PipelineState::Idle(Some(pipeline)), + pending_pipeline_target: None, + } + } + + /// Returns `true` if a pipeline target is queued and will be triggered on the next `poll`. + #[allow(dead_code)] + const fn is_pipeline_sync_pending(&self) -> bool { + self.pending_pipeline_target.is_some() && self.pipeline_state.is_idle() + } + + /// Returns `true` if the pipeline is idle. + const fn is_pipeline_idle(&self) -> bool { + self.pipeline_state.is_idle() + } + + /// Returns `true` if the pipeline is active. + const fn is_pipeline_active(&self) -> bool { + !self.is_pipeline_idle() + } + + /// Sets a new target to sync the pipeline to. + /// + /// But ensures the target is not the zero hash. + fn set_pipeline_sync_target(&mut self, target: PipelineTarget) { + if target.sync_target().is_some_and(|target| target.is_zero()) { + trace!( + target: "consensus::engine::sync", + "Pipeline target cannot be zero hash." + ); + // precaution to never sync to the zero hash + return + } + self.pending_pipeline_target = Some(target); + } + + /// This will spawn the pipeline if it is idle and a target is set or if the pipeline is set to + /// run continuously. + fn try_spawn_pipeline(&mut self) -> Option { + match &mut self.pipeline_state { + PipelineState::Idle(pipeline) => { + let target = self.pending_pipeline_target.take()?; + let (tx, rx) = oneshot::channel(); + + let pipeline = pipeline.take().expect("exists"); + self.pipeline_task_spawner.spawn_critical_blocking( + "pipeline task", + Box::pin(async move { + let result = pipeline.run_as_fut(Some(target)).await; + let _ = tx.send(result); + }), + ); + self.pipeline_state = PipelineState::Running(rx); + + Some(BackfillEvent::Started(target)) + } + PipelineState::Running(_) => None, + } + } + + /// Advances the pipeline state. + /// + /// This checks for the result in the channel, or returns pending if the pipeline is idle. + fn poll_pipeline(&mut self, cx: &mut Context<'_>) -> Poll { + let res = match self.pipeline_state { + PipelineState::Idle(_) => return Poll::Pending, + PipelineState::Running(ref mut fut) => { + ready!(fut.poll_unpin(cx)) + } + }; + let ev = match res { + Ok((_, result)) => BackfillEvent::Finished(result), + Err(why) => { + // failed to receive the pipeline + BackfillEvent::TaskDropped(why.to_string()) + } + }; + Poll::Ready(ev) + } +} + +impl BackfillSync for PipelineSync +where + DB: Database + 'static, +{ + fn on_action(&mut self, event: BackfillAction) { + match event { + BackfillAction::Start(target) => self.set_pipeline_sync_target(target), + } + } + + fn poll(&mut self, cx: &mut Context<'_>) -> Poll { + // try to spawn a pipeline if a target is set + if let Some(event) = self.try_spawn_pipeline() { + return Poll::Ready(event) + } + + // make sure we poll the pipeline if it's active, and return any ready pipeline events + if !self.is_pipeline_idle() { + // advance the pipeline + if let Poll::Ready(event) = self.poll_pipeline(cx) { + return Poll::Ready(event) + } + } + + Poll::Pending + } +} + +/// The possible pipeline states within the sync controller. +/// +/// [`PipelineState::Idle`] means that the pipeline is currently idle. +/// [`PipelineState::Running`] means that the pipeline is currently running. +/// +/// NOTE: The differentiation between these two states is important, because when the pipeline is +/// running, it acquires the write lock over the database. This means that we cannot forward to the +/// blockchain tree any messages that would result in database writes, since it would result in a +/// deadlock. +#[derive(Debug)] +enum PipelineState { + /// Pipeline is idle. + Idle(Option>), + /// Pipeline is running and waiting for a response + Running(oneshot::Receiver>), +} + +impl PipelineState { + /// Returns `true` if the state matches idle. + const fn is_idle(&self) -> bool { + matches!(self, Self::Idle(_)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_utils::insert_headers_into_client; + use assert_matches::assert_matches; + use futures::poll; + use reth_chainspec::{ChainSpec, ChainSpecBuilder, MAINNET}; + use reth_db::{mdbx::DatabaseEnv, test_utils::TempDatabase}; + use reth_network_p2p::test_utils::TestFullBlockClient; + use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, BlockNumber, Header, B256}; + use reth_provider::{ + test_utils::create_test_provider_factory_with_chain_spec, ExecutionOutcome, + }; + use reth_prune_types::PruneModes; + use reth_stages::{test_utils::TestStages, ExecOutput, StageError}; + use reth_stages_api::StageCheckpoint; + use reth_static_file::StaticFileProducer; + use reth_tasks::TokioTaskExecutor; + use std::{collections::VecDeque, future::poll_fn, sync::Arc}; + use tokio::sync::watch; + + struct TestHarness { + pipeline_sync: PipelineSync>>, + tip: B256, + } + + impl TestHarness { + fn new(total_blocks: usize, pipeline_done_after: u64) -> Self { + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(MAINNET.chain) + .genesis(MAINNET.genesis.clone()) + .paris_activated() + .build(), + ); + + // force the pipeline to be "done" after 5 blocks + let pipeline = TestPipelineBuilder::new() + .with_pipeline_exec_outputs(VecDeque::from([Ok(ExecOutput { + checkpoint: StageCheckpoint::new(BlockNumber::from(pipeline_done_after)), + done: true, + })])) + .build(chain_spec); + + let pipeline_sync = PipelineSync::new(pipeline, Box::::default()); + let client = TestFullBlockClient::default(); + let header = Header { + base_fee_per_gas: Some(7), + gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, + ..Default::default() + } + .seal_slow(); + insert_headers_into_client(&client, header, 0..total_blocks); + + let tip = client.highest_block().expect("there should be blocks here").hash(); + + Self { pipeline_sync, tip } + } + } + + struct TestPipelineBuilder { + pipeline_exec_outputs: VecDeque>, + executor_results: Vec, + } + + impl TestPipelineBuilder { + /// Create a new [`TestPipelineBuilder`]. + const fn new() -> Self { + Self { pipeline_exec_outputs: VecDeque::new(), executor_results: Vec::new() } + } + + /// Set the pipeline execution outputs to use for the test consensus engine. + fn with_pipeline_exec_outputs( + mut self, + pipeline_exec_outputs: VecDeque>, + ) -> Self { + self.pipeline_exec_outputs = pipeline_exec_outputs; + self + } + + /// Set the executor results to use for the test consensus engine. + #[allow(dead_code)] + fn with_executor_results(mut self, executor_results: Vec) -> Self { + self.executor_results = executor_results; + self + } + + /// Builds the pipeline. + fn build(self, chain_spec: Arc) -> Pipeline>> { + reth_tracing::init_test_tracing(); + + // Setup pipeline + let (tip_tx, _tip_rx) = watch::channel(B256::default()); + let pipeline = Pipeline::builder() + .add_stages(TestStages::new(self.pipeline_exec_outputs, Default::default())) + .with_tip_sender(tip_tx); + + let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec); + + let static_file_producer = + StaticFileProducer::new(provider_factory.clone(), PruneModes::default()); + + pipeline.build(provider_factory, static_file_producer) + } + } + + #[tokio::test] + async fn pipeline_started_and_finished() { + const TOTAL_BLOCKS: usize = 10; + const PIPELINE_DONE_AFTER: u64 = 5; + let TestHarness { mut pipeline_sync, tip } = + TestHarness::new(TOTAL_BLOCKS, PIPELINE_DONE_AFTER); + + let sync_future = poll_fn(|cx| pipeline_sync.poll(cx)); + let next_event = poll!(sync_future); + + // sync target not set, pipeline not started + assert_matches!(next_event, Poll::Pending); + + pipeline_sync.on_action(BackfillAction::Start(PipelineTarget::Sync(tip))); + + let sync_future = poll_fn(|cx| pipeline_sync.poll(cx)); + let next_event = poll!(sync_future); + + // sync target set, pipeline started + assert_matches!(next_event, Poll::Ready(BackfillEvent::Started(target)) => { + assert_eq!(target.sync_target().unwrap(), tip); + }); + + // the next event should be the pipeline finishing in a good state + let sync_future = poll_fn(|cx| pipeline_sync.poll(cx)); + let next_ready = sync_future.await; + assert_matches!(next_ready, BackfillEvent::Finished(result) => { + assert_matches!(result, Ok(control_flow) => assert_eq!(control_flow, ControlFlow::Continue { block_number: PIPELINE_DONE_AFTER })); + }); + } +} diff --git a/crates/engine/tree/src/chain.rs b/crates/engine/tree/src/chain.rs new file mode 100644 index 000000000000..97c6d615c118 --- /dev/null +++ b/crates/engine/tree/src/chain.rs @@ -0,0 +1,218 @@ +use crate::backfill::{BackfillAction, BackfillEvent, BackfillSync}; +use futures::Stream; +use reth_stages_api::PipelineTarget; +use std::{ + pin::Pin, + task::{Context, Poll}, +}; + +/// The type that drives the chain forward. +/// +/// A state machine that orchestrates the components responsible for advancing the chain +/// +/// +/// ## Control flow +/// +/// The [`ChainOrchestrator`] is responsible for controlling the pipeline sync and additional hooks. +/// It polls the given `handler`, which is responsible for advancing the chain, how is up to the +/// handler. However, due to database restrictions (e.g. exclusive write access), following +/// invariants apply: +/// - If the handler requests a backfill run (e.g. [`BackfillAction::Start`]), the handler must +/// ensure that while the pipeline is running, no other write access is granted. +/// - At any time the [`ChainOrchestrator`] can request exclusive write access to the database +/// (e.g. if pruning is required), but will not do so until the handler has acknowledged the +/// request for write access. +/// +/// The [`ChainOrchestrator`] polls the [`ChainHandler`] to advance the chain and handles the +/// emitted events. Requests and events are passed to the [`ChainHandler`] via +/// [`ChainHandler::on_event`]. +#[must_use = "Stream does nothing unless polled"] +#[derive(Debug)] +pub struct ChainOrchestrator +where + T: ChainHandler, + P: BackfillSync, +{ + /// The handler for advancing the chain. + handler: T, + /// Controls pipeline sync. + pipeline: P, +} + +impl ChainOrchestrator +where + T: ChainHandler + Unpin, + P: BackfillSync + Unpin, +{ + /// Creates a new [`ChainOrchestrator`] with the given handler and pipeline. + pub const fn new(handler: T, pipeline: P) -> Self { + Self { handler, pipeline } + } + + /// Returns the handler + pub const fn handler(&self) -> &T { + &self.handler + } + + /// Returns a mutable reference to the handler + pub fn handler_mut(&mut self) -> &mut T { + &mut self.handler + } + + /// Internal function used to advance the chain. + /// + /// Polls the `ChainOrchestrator` for the next event. + #[tracing::instrument(level = "debug", name = "ChainOrchestrator::poll", skip(self, cx))] + fn poll_next_event(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + + // This loop polls the components + // + // 1. Polls the pipeline to completion, if active. + // 2. Advances the chain by polling the handler. + 'outer: loop { + // try to poll the pipeline to completion, if active + match this.pipeline.poll(cx) { + Poll::Ready(pipeline_event) => match pipeline_event { + BackfillEvent::Idle => {} + BackfillEvent::Started(_) => { + // notify handler that pipeline started + this.handler.on_event(FromOrchestrator::PipelineStarted); + return Poll::Ready(ChainEvent::PipelineStarted); + } + BackfillEvent::Finished(res) => { + return match res { + Ok(event) => { + tracing::debug!(?event, "pipeline finished"); + // notify handler that pipeline finished + this.handler.on_event(FromOrchestrator::PipelineFinished); + Poll::Ready(ChainEvent::PipelineFinished) + } + Err(err) => { + tracing::error!( %err, "pipeline failed"); + Poll::Ready(ChainEvent::FatalError) + } + } + } + BackfillEvent::TaskDropped(err) => { + tracing::error!( %err, "pipeline task dropped"); + return Poll::Ready(ChainEvent::FatalError); + } + }, + Poll::Pending => {} + } + + // poll the handler for the next event + match this.handler.poll(cx) { + Poll::Ready(handler_event) => { + match handler_event { + HandlerEvent::Pipeline(target) => { + // trigger pipeline and start polling it + this.pipeline.on_action(BackfillAction::Start(target)); + continue 'outer + } + HandlerEvent::Event(ev) => { + // bubble up the event + return Poll::Ready(ChainEvent::Handler(ev)); + } + } + } + Poll::Pending => { + // no more events to process + break 'outer + } + } + } + + Poll::Pending + } +} + +impl Stream for ChainOrchestrator +where + T: ChainHandler + Unpin, + P: BackfillSync + Unpin, +{ + type Item = ChainEvent; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.as_mut().poll_next_event(cx).map(Some) + } +} + +/// Represents the sync mode the chain is operating in. +#[derive(Debug, Default)] +enum SyncMode { + #[default] + Handler, + Backfill, +} + +/// Event emitted by the [`ChainOrchestrator`] +/// +/// These are meant to be used for observability and debugging purposes. +#[derive(Debug)] +pub enum ChainEvent { + /// Pipeline sync started + PipelineStarted, + /// Pipeline sync finished + PipelineFinished, + /// Fatal error + FatalError, + /// Event emitted by the handler + Handler(T), +} + +/// A trait that advances the chain by handling actions. +/// +/// This is intended to be implement the chain consensus logic, for example `engine` API. +pub trait ChainHandler: Send + Sync { + /// Event generated by this handler that orchestrator can bubble up; + type Event: Send; + + /// Informs the handler about an event from the [`ChainOrchestrator`]. + fn on_event(&mut self, event: FromOrchestrator); + + /// Polls for actions that [`ChainOrchestrator`] should handle. + fn poll(&mut self, cx: &mut Context<'_>) -> Poll>; +} + +/// Events/Requests that the [`ChainHandler`] can emit to the [`ChainOrchestrator`]. +#[derive(Clone, Debug)] +pub enum HandlerEvent { + /// Request to start a pipeline sync + Pipeline(PipelineTarget), + /// Other event emitted by the handler + Event(T), +} + +/// Internal events issued by the [`ChainOrchestrator`]. +#[derive(Clone, Debug)] +pub enum FromOrchestrator { + /// Invoked when pipeline sync finished + PipelineFinished, + /// Invoked when pipeline started + PipelineStarted, +} + +/// Represents the state of the chain. +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +pub enum OrchestratorState { + /// Orchestrator has exclusive write access to the database. + PipelineActive, + /// Node is actively processing the chain. + #[default] + Idle, +} + +impl OrchestratorState { + /// Returns `true` if the state is [`OrchestratorState::PipelineActive`]. + pub const fn is_pipeline_active(&self) -> bool { + matches!(self, Self::PipelineActive) + } + + /// Returns `true` if the state is [`OrchestratorState::Idle`]. + pub const fn is_idle(&self) -> bool { + matches!(self, Self::Idle) + } +} diff --git a/crates/engine/tree/src/download.rs b/crates/engine/tree/src/download.rs new file mode 100644 index 000000000000..12b2bd189288 --- /dev/null +++ b/crates/engine/tree/src/download.rs @@ -0,0 +1,414 @@ +//! Handler that can download blocks on demand (e.g. from the network). + +use crate::{engine::DownloadRequest, metrics::BlockDownloaderMetrics}; +use futures::FutureExt; +use reth_consensus::Consensus; +use reth_network_p2p::{ + bodies::client::BodiesClient, + full_block::{FetchFullBlockFuture, FetchFullBlockRangeFuture, FullBlockClient}, + headers::client::HeadersClient, +}; +use reth_primitives::{SealedBlock, SealedBlockWithSenders, B256}; +use std::{ + cmp::{Ordering, Reverse}, + collections::{binary_heap::PeekMut, BinaryHeap, HashSet}, + sync::Arc, + task::{Context, Poll}, +}; +use tracing::trace; + +/// A trait that can download blocks on demand. +pub trait BlockDownloader: Send + Sync { + /// Handle an action. + fn on_action(&mut self, event: DownloadAction); + + /// Advance in progress requests if any + fn poll(&mut self, cx: &mut Context<'_>) -> Poll; +} + +/// Actions that can be performed by the block downloader. +#[derive(Debug)] +pub enum DownloadAction { + /// Stop downloading blocks. + Clear, + /// Download given blocks + Download(DownloadRequest), +} + +/// Outcome of downloaded blocks. +#[derive(Debug)] +pub enum DownloadOutcome { + /// Downloaded blocks. + Blocks(Vec), +} + +/// Basic [`BlockDownloader`]. +pub struct BasicBlockDownloader +where + Client: HeadersClient + BodiesClient + Clone + Unpin + 'static, +{ + /// A downloader that can download full blocks from the network. + full_block_client: FullBlockClient, + /// In-flight full block requests in progress. + inflight_full_block_requests: Vec>, + /// In-flight full block _range_ requests in progress. + inflight_block_range_requests: Vec>, + /// Buffered blocks from downloads - this is a min-heap of blocks, using the block number for + /// ordering. This means the blocks will be popped from the heap with ascending block numbers. + set_buffered_blocks: BinaryHeap>, + /// Engine download metrics. + metrics: BlockDownloaderMetrics, +} + +impl BasicBlockDownloader +where + Client: HeadersClient + BodiesClient + Clone + Unpin + 'static, +{ + /// Create a new instance + pub(crate) fn new(client: Client, consensus: Arc) -> Self { + Self { + full_block_client: FullBlockClient::new(client, consensus), + inflight_full_block_requests: Vec::new(), + inflight_block_range_requests: Vec::new(), + set_buffered_blocks: BinaryHeap::new(), + metrics: BlockDownloaderMetrics::default(), + } + } + + /// Clears the stored inflight requests. + fn clear(&mut self) { + self.inflight_full_block_requests.clear(); + self.inflight_block_range_requests.clear(); + self.set_buffered_blocks.clear(); + self.update_block_download_metrics(); + } + + /// Processes a download request. + fn download(&mut self, request: DownloadRequest) { + match request { + DownloadRequest::BlockSet(hashes) => self.download_block_set(hashes), + DownloadRequest::BlockRange(hash, count) => self.download_block_range(hash, count), + } + } + + /// Processes a block set download request. + fn download_block_set(&mut self, hashes: HashSet) { + for hash in hashes { + self.download_full_block(hash); + } + } + + /// Processes a block range download request. + fn download_block_range(&mut self, hash: B256, count: u64) { + if count == 1 { + self.download_full_block(hash); + } else { + trace!( + target: "consensus::engine", + ?hash, + ?count, + "start downloading full block range." + ); + + let request = self.full_block_client.get_full_block_range(hash, count); + self.inflight_block_range_requests.push(request); + } + } + + /// Starts requesting a full block from the network. + /// + /// Returns `true` if the request was started, `false` if there's already a request for the + /// given hash. + fn download_full_block(&mut self, hash: B256) -> bool { + if self.is_inflight_request(hash) { + return false + } + trace!( + target: "consensus::engine::sync", + ?hash, + "Start downloading full block" + ); + + let request = self.full_block_client.get_full_block(hash); + self.inflight_full_block_requests.push(request); + + self.update_block_download_metrics(); + + true + } + + /// Returns true if there's already a request for the given hash. + fn is_inflight_request(&self, hash: B256) -> bool { + self.inflight_full_block_requests.iter().any(|req| *req.hash() == hash) + } + + /// Sets the metrics for the active downloads + fn update_block_download_metrics(&self) { + self.metrics.active_block_downloads.set(self.inflight_full_block_requests.len() as f64); + // TODO: full block range metrics + } +} + +impl BlockDownloader for BasicBlockDownloader +where + Client: HeadersClient + BodiesClient + Clone + Unpin + 'static, +{ + /// Handles incoming download actions. + fn on_action(&mut self, event: DownloadAction) { + match event { + DownloadAction::Clear => self.clear(), + DownloadAction::Download(request) => self.download(request), + } + } + + /// Advances the download process. + fn poll(&mut self, cx: &mut Context<'_>) -> Poll { + // advance all full block requests + for idx in (0..self.inflight_full_block_requests.len()).rev() { + let mut request = self.inflight_full_block_requests.swap_remove(idx); + if let Poll::Ready(block) = request.poll_unpin(cx) { + trace!(target: "consensus::engine", block=?block.num_hash(), "Received single full block, buffering"); + self.set_buffered_blocks.push(Reverse(block.into())); + } else { + // still pending + self.inflight_full_block_requests.push(request); + } + } + + // advance all full block range requests + for idx in (0..self.inflight_block_range_requests.len()).rev() { + let mut request = self.inflight_block_range_requests.swap_remove(idx); + if let Poll::Ready(blocks) = request.poll_unpin(cx) { + trace!(target: "consensus::engine", len=?blocks.len(), first=?blocks.first().map(|b| b.num_hash()), last=?blocks.last().map(|b| b.num_hash()), "Received full block range, buffering"); + self.set_buffered_blocks.extend( + blocks + .into_iter() + .map(|b| { + let senders = b.senders().unwrap_or_default(); + OrderedSealedBlockWithSenders(SealedBlockWithSenders { + block: b, + senders, + }) + }) + .map(Reverse), + ); + } else { + // still pending + self.inflight_block_range_requests.push(request); + } + } + + self.update_block_download_metrics(); + + if self.set_buffered_blocks.is_empty() { + return Poll::Pending; + } + + // drain all unique element of the block buffer if there are any + let mut downloaded_blocks: Vec = + Vec::with_capacity(self.set_buffered_blocks.len()); + while let Some(block) = self.set_buffered_blocks.pop() { + // peek ahead and pop duplicates + while let Some(peek) = self.set_buffered_blocks.peek_mut() { + if peek.0 .0.hash() == block.0 .0.hash() { + PeekMut::pop(peek); + } else { + break + } + } + downloaded_blocks.push(block.0.into()); + } + Poll::Ready(DownloadOutcome::Blocks(downloaded_blocks)) + } +} + +/// A wrapper type around [`SealedBlockWithSenders`] that implements the [Ord] +/// trait by block number. +#[derive(Debug, Clone, PartialEq, Eq)] +struct OrderedSealedBlockWithSenders(SealedBlockWithSenders); + +impl PartialOrd for OrderedSealedBlockWithSenders { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for OrderedSealedBlockWithSenders { + fn cmp(&self, other: &Self) -> Ordering { + self.0.number.cmp(&other.0.number) + } +} + +impl From for OrderedSealedBlockWithSenders { + fn from(block: SealedBlock) -> Self { + let senders = block.senders().unwrap_or_default(); + Self(SealedBlockWithSenders { block, senders }) + } +} + +impl From for SealedBlockWithSenders { + fn from(value: OrderedSealedBlockWithSenders) -> Self { + let senders = value.0.senders; + Self { block: value.0.block, senders } + } +} + +/// A [`BlockDownloader`] that does nothing. +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +pub struct NoopBlockDownloader; + +impl BlockDownloader for NoopBlockDownloader { + fn on_action(&mut self, _event: DownloadAction) {} + + fn poll(&mut self, _cx: &mut Context<'_>) -> Poll { + Poll::Pending + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_utils::insert_headers_into_client; + use assert_matches::assert_matches; + use reth_beacon_consensus::EthBeaconConsensus; + use reth_chainspec::{ChainSpecBuilder, MAINNET}; + use reth_network_p2p::test_utils::TestFullBlockClient; + use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, Header}; + use std::{future::poll_fn, sync::Arc}; + + struct TestHarness { + block_downloader: BasicBlockDownloader, + client: TestFullBlockClient, + } + + impl TestHarness { + fn new(total_blocks: usize) -> Self { + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(MAINNET.chain) + .genesis(MAINNET.genesis.clone()) + .paris_activated() + .build(), + ); + + let client = TestFullBlockClient::default(); + let header = Header { + base_fee_per_gas: Some(7), + gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, + ..Default::default() + } + .seal_slow(); + + insert_headers_into_client(&client, header, 0..total_blocks); + let consensus = Arc::new(EthBeaconConsensus::new(chain_spec)); + + let block_downloader = BasicBlockDownloader::new(client.clone(), consensus); + Self { block_downloader, client } + } + } + + #[tokio::test] + async fn block_downloader_range_request() { + const TOTAL_BLOCKS: usize = 10; + let TestHarness { mut block_downloader, client } = TestHarness::new(TOTAL_BLOCKS); + let tip = client.highest_block().expect("there should be blocks here"); + + // send block range download request + block_downloader.on_action(DownloadAction::Download(DownloadRequest::BlockRange( + tip.hash(), + tip.number, + ))); + + // ensure we have one in flight range request + assert_eq!(block_downloader.inflight_block_range_requests.len(), 1); + + // ensure the range request is made correctly + let first_req = block_downloader.inflight_block_range_requests.first().unwrap(); + assert_eq!(first_req.start_hash(), tip.hash()); + assert_eq!(first_req.count(), tip.number); + + // poll downloader + let sync_future = poll_fn(|cx| block_downloader.poll(cx)); + let next_ready = sync_future.await; + + assert_matches!(next_ready, DownloadOutcome::Blocks(blocks) => { + // ensure all blocks were obtained + assert_eq!(blocks.len(), TOTAL_BLOCKS); + + // ensure they are in ascending order + for num in 1..=TOTAL_BLOCKS { + assert_eq!(blocks[num-1].number, num as u64); + } + }); + } + + #[tokio::test] + async fn block_downloader_set_request() { + const TOTAL_BLOCKS: usize = 2; + let TestHarness { mut block_downloader, client } = TestHarness::new(TOTAL_BLOCKS); + + let tip = client.highest_block().expect("there should be blocks here"); + + // send block set download request + block_downloader.on_action(DownloadAction::Download(DownloadRequest::BlockSet( + HashSet::from([tip.hash(), tip.parent_hash]), + ))); + + // ensure we have TOTAL_BLOCKS in flight full block request + assert_eq!(block_downloader.inflight_full_block_requests.len(), TOTAL_BLOCKS); + + // poll downloader + let sync_future = poll_fn(|cx| block_downloader.poll(cx)); + let next_ready = sync_future.await; + + assert_matches!(next_ready, DownloadOutcome::Blocks(blocks) => { + // ensure all blocks were obtained + assert_eq!(blocks.len(), TOTAL_BLOCKS); + + // ensure they are in ascending order + for num in 1..=TOTAL_BLOCKS { + assert_eq!(blocks[num-1].number, num as u64); + } + }); + } + + #[tokio::test] + async fn block_downloader_clear_request() { + const TOTAL_BLOCKS: usize = 10; + let TestHarness { mut block_downloader, client } = TestHarness::new(TOTAL_BLOCKS); + + let tip = client.highest_block().expect("there should be blocks here"); + + // send block range download request + block_downloader.on_action(DownloadAction::Download(DownloadRequest::BlockRange( + tip.hash(), + tip.number, + ))); + + // send block set download request + let download_set = HashSet::from([tip.hash(), tip.parent_hash]); + block_downloader + .on_action(DownloadAction::Download(DownloadRequest::BlockSet(download_set.clone()))); + + // ensure we have one in flight range request + assert_eq!(block_downloader.inflight_block_range_requests.len(), 1); + + // ensure the range request is made correctly + let first_req = block_downloader.inflight_block_range_requests.first().unwrap(); + assert_eq!(first_req.start_hash(), tip.hash()); + assert_eq!(first_req.count(), tip.number); + + // ensure we have download_set.len() in flight full block request + assert_eq!(block_downloader.inflight_full_block_requests.len(), download_set.len()); + + // send clear request + block_downloader.on_action(DownloadAction::Clear); + + // ensure we have no in flight range request + assert_eq!(block_downloader.inflight_block_range_requests.len(), 0); + + // ensure we have no in flight full block request + assert_eq!(block_downloader.inflight_full_block_requests.len(), 0); + } +} diff --git a/crates/engine/tree/src/engine.rs b/crates/engine/tree/src/engine.rs new file mode 100644 index 000000000000..d77162e4cd0a --- /dev/null +++ b/crates/engine/tree/src/engine.rs @@ -0,0 +1,212 @@ +//! An engine API handler for the chain. + +use crate::{ + chain::{ChainHandler, FromOrchestrator, HandlerEvent}, + download::{BlockDownloader, DownloadAction, DownloadOutcome}, +}; +use futures::{Stream, StreamExt}; +use reth_beacon_consensus::BeaconEngineMessage; +use reth_engine_primitives::EngineTypes; +use reth_primitives::{SealedBlockWithSenders, B256}; +use std::{ + collections::HashSet, + task::{Context, Poll}, +}; +use tokio::sync::mpsc; + +/// Advances the chain based on incoming requests. +/// +/// This is a general purpose request handler with network access. +/// This type listens for incoming messages and processes them via the configured request handler. +/// +/// ## Overview +/// +/// This type is an orchestrator for incoming messages and responsible for delegating requests +/// received from the CL to the handler. +/// +/// It is responsible for handling the following: +/// - Downloading blocks on demand from the network if requested by the [`EngineApiRequestHandler`]. +/// +/// The core logic is part of the [`EngineRequestHandler`], which is responsible for processing the +/// incoming requests. +#[derive(Debug)] +pub struct EngineHandler { + /// Processes requests. + /// + /// This type is responsible for processing incoming requests. + handler: T, + /// Receiver for incoming requests that need to be processed. + incoming_requests: S, + /// A downloader to download blocks on demand. + downloader: D, +} + +impl EngineHandler { + /// Creates a new [`EngineHandler`] with the given handler and downloader. + pub const fn new(handler: T, downloader: D, incoming_requests: S) -> Self + where + T: EngineRequestHandler, + { + Self { handler, incoming_requests, downloader } + } +} + +impl ChainHandler for EngineHandler +where + T: EngineRequestHandler, + S: Stream + Send + Sync + Unpin + 'static, + D: BlockDownloader, +{ + type Event = T::Event; + + fn on_event(&mut self, event: FromOrchestrator) { + // delegate event to the handler + self.handler.on_event(event.into()); + } + + fn poll(&mut self, cx: &mut Context<'_>) -> Poll> { + loop { + // drain the handler first + while let Poll::Ready(ev) = self.handler.poll(cx) { + match ev { + RequestHandlerEvent::Idle => break, + RequestHandlerEvent::HandlerEvent(ev) => { + return match ev { + HandlerEvent::Pipeline(target) => { + // bubble up pipeline request + self.downloader.on_action(DownloadAction::Clear); + Poll::Ready(HandlerEvent::Pipeline(target)) + } + HandlerEvent::Event(ev) => { + // bubble up the event + Poll::Ready(HandlerEvent::Event(ev)) + } + } + } + RequestHandlerEvent::Download(req) => { + // delegate download request to the downloader + self.downloader.on_action(DownloadAction::Download(req)); + } + } + } + + // pop the next incoming request + if let Poll::Ready(Some(req)) = self.incoming_requests.poll_next_unpin(cx) { + // and delegate the request to the handler + self.handler.on_event(FromEngine::Request(req)); + // skip downloading in this iteration to allow the handler to process the request + continue + } + + // advance the downloader + if let Poll::Ready(DownloadOutcome::Blocks(blocks)) = self.downloader.poll(cx) { + // delegate the downloaded blocks to the handler + self.handler.on_event(FromEngine::DownloadedBlocks(blocks)); + continue + } + + return Poll::Pending + } + } +} + +/// A type that processes incoming requests (e.g. requests from the consensus layer, engine API) +pub trait EngineRequestHandler: Send + Sync { + /// Even type this handler can emit + type Event: Send; + /// The request type this handler can process. + type Request; + + /// Informs the handler about an event from the [`EngineHandler`]. + fn on_event(&mut self, event: FromEngine); + + /// Advances the handler. + fn poll(&mut self, cx: &mut Context<'_>) -> Poll>; +} + +/// An [`EngineRequestHandler`] that processes engine API requests by delegating to an execution +/// task. +/// +/// This type is responsible for advancing the chain during live sync (following the tip of the +/// chain). +/// +/// It advances the chain based on received engine API requests by delegating them to the tree +/// executor. +/// +/// There are two types of requests that can be processed: +/// +/// - `on_new_payload`: Executes the payload and inserts it into the tree. These are allowed to be +/// processed concurrently. +/// - `on_forkchoice_updated`: Updates the fork choice based on the new head. These require write +/// access to the database and are skipped if the handler can't acquire exclusive access to the +/// database. +/// +/// In case required blocks are missing, the handler will request them from the network, by emitting +/// a download request upstream. +#[derive(Debug)] +pub struct EngineApiRequestHandler { + /// channel to send messages to the tree to execute the payload. + to_tree: std::sync::mpsc::Sender>>, + /// channel to receive messages from the tree. + from_tree: mpsc::UnboundedReceiver, + // TODO add db controller +} + +impl EngineApiRequestHandler where T: EngineTypes {} + +impl EngineRequestHandler for EngineApiRequestHandler +where + T: EngineTypes, +{ + type Event = EngineApiEvent; + type Request = BeaconEngineMessage; + + fn on_event(&mut self, event: FromEngine) { + // delegate to the tree + let _ = self.to_tree.send(event); + } + + fn poll(&mut self, cx: &mut Context<'_>) -> Poll> { + todo!("poll tree and handle db") + } +} + +/// Events emitted by the engine API handler. +#[derive(Debug)] +pub enum EngineApiEvent {} + +#[derive(Debug)] +pub enum FromEngine { + /// Event from the top level orchestrator. + Event(FromOrchestrator), + /// Request from the engine + Request(Req), + /// Downloaded blocks from the network. + DownloadedBlocks(Vec), +} + +impl From for FromEngine { + fn from(event: FromOrchestrator) -> Self { + Self::Event(event) + } +} + +/// Requests produced by a [`EngineRequestHandler`]. +#[derive(Debug)] +pub enum RequestHandlerEvent { + /// The handler is idle. + Idle, + /// An event emitted by the handler. + HandlerEvent(HandlerEvent), + /// Request to download blocks. + Download(DownloadRequest), +} + +/// A request to download blocks from the network. +#[derive(Debug)] +pub enum DownloadRequest { + /// Download the given set of blocks. + BlockSet(HashSet), + /// Download the given range of blocks. + BlockRange(B256, u64), +} diff --git a/crates/engine/tree/src/lib.rs b/crates/engine/tree/src/lib.rs new file mode 100644 index 000000000000..52ef90e4b637 --- /dev/null +++ b/crates/engine/tree/src/lib.rs @@ -0,0 +1,31 @@ +//! This crate includes the core components for advancing a reth chain. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +// #![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![allow(missing_docs, dead_code, missing_debug_implementations, unused_variables)] // TODO rm + +/// Re-export of the blockchain tree API. +pub use reth_blockchain_tree_api::*; + +/// Support for backfill sync mode. +pub mod backfill; +/// The type that drives the chain forward. +pub mod chain; +/// Support for downloading blocks on demand for live sync. +pub mod download; +/// Engine Api chain handler support. +pub mod engine; +/// Metrics support. +pub mod metrics; +/// The background writer task for batch db writes. +pub mod persistence; +/// Support for interacting with the blockchain tree. +pub mod tree; + +#[cfg(test)] +mod test_utils; diff --git a/crates/engine/tree/src/metrics.rs b/crates/engine/tree/src/metrics.rs new file mode 100644 index 000000000000..9579affe690f --- /dev/null +++ b/crates/engine/tree/src/metrics.rs @@ -0,0 +1,9 @@ +use reth_metrics::{metrics::Gauge, Metrics}; + +/// Metrics for the `BasicBlockDownloader`. +#[derive(Metrics)] +#[metrics(scope = "consensus.engine.beacon")] +pub(crate) struct BlockDownloaderMetrics { + /// How many blocks are currently being downloaded. + pub(crate) active_block_downloads: Gauge, +} diff --git a/crates/engine/tree/src/persistence.rs b/crates/engine/tree/src/persistence.rs new file mode 100644 index 000000000000..e7bfadcc1bef --- /dev/null +++ b/crates/engine/tree/src/persistence.rs @@ -0,0 +1,139 @@ +#![allow(dead_code)] + +use crate::tree::ExecutedBlock; +use reth_db::database::Database; +use reth_errors::ProviderResult; +use reth_primitives::B256; +use reth_provider::ProviderFactory; +use std::sync::mpsc::{Receiver, Sender}; +use tokio::sync::oneshot; + +/// Writes parts of reth's in memory tree state to the database. +/// +/// This is meant to be a spawned task that listens for various incoming persistence operations, +/// performing those actions on disk, and returning the result in a channel. +/// +/// There are two types of operations this task can perform: +/// - Writing executed blocks to disk, returning the hash of the latest block that was inserted. +/// - Removing blocks from disk, returning the removed blocks. +/// +/// This should be spawned in its own thread with [`std::thread::spawn`], since this performs +/// blocking database operations in an endless loop. +#[derive(Debug)] +pub struct Persistence { + /// The db / static file provider to use + provider: ProviderFactory, + /// Incoming requests to persist stuff + incoming: Receiver, +} + +impl Persistence { + /// Create a new persistence task + const fn new(provider: ProviderFactory, incoming: Receiver) -> Self { + Self { provider, incoming } + } + + /// Writes the cloned tree state to the database + fn write(&self, _blocks: Vec) -> ProviderResult<()> { + let mut _rw = self.provider.provider_rw()?; + todo!("implement this") + } + + /// Removes the blocks above the give block number from the database, returning them. + fn remove_blocks_above(&self, _block_number: u64) -> Vec { + todo!("implement this") + } +} + +impl Persistence +where + DB: Database + 'static, +{ + /// Create a new persistence task, spawning it, and returning a [`PersistenceHandle`]. + fn spawn_new(provider: ProviderFactory) -> PersistenceHandle { + let (tx, rx) = std::sync::mpsc::channel(); + let task = Self::new(provider, rx); + std::thread::Builder::new() + .name("Persistence Task".to_string()) + .spawn(|| task.run()) + .unwrap(); + + PersistenceHandle::new(tx) + } +} + +impl Persistence +where + DB: Database, +{ + /// This is the main loop, that will listen to persistence events and perform the requested + /// database actions + fn run(self) { + // If the receiver errors then senders have disconnected, so the loop should then end. + while let Ok(action) = self.incoming.recv() { + match action { + PersistenceAction::RemoveBlocksAbove((new_tip_num, sender)) => { + // spawn blocking so we can poll the thread later + let output = self.remove_blocks_above(new_tip_num); + sender.send(output).unwrap(); + } + PersistenceAction::SaveBlocks((blocks, sender)) => { + if blocks.is_empty() { + todo!("return error or something"); + } + let last_block_hash = blocks.last().unwrap().block().hash(); + self.write(blocks).unwrap(); + sender.send(last_block_hash).unwrap(); + } + } + } + } +} + +/// A signal to the persistence task that part of the tree state can be persisted. +#[derive(Debug)] +pub enum PersistenceAction { + /// The section of tree state that should be persisted. These blocks are expected in order of + /// increasing block number. + SaveBlocks((Vec, oneshot::Sender)), + + /// Removes the blocks above the given block number from the database. + RemoveBlocksAbove((u64, oneshot::Sender>)), +} + +/// A handle to the persistence task +#[derive(Debug, Clone)] +pub struct PersistenceHandle { + /// The channel used to communicate with the persistence task + sender: Sender, +} + +impl PersistenceHandle { + /// Create a new [`PersistenceHandle`] from a [`Sender`]. + pub const fn new(sender: Sender) -> Self { + Self { sender } + } + + /// Tells the persistence task to save a certain list of finalized blocks. The blocks are + /// assumed to be ordered by block number. + /// + /// This returns the latest hash that has been saved, allowing removal of that block and any + /// previous blocks from in-memory data structures. + pub async fn save_blocks(&self, blocks: Vec) -> B256 { + let (tx, rx) = oneshot::channel(); + self.sender + .send(PersistenceAction::SaveBlocks((blocks, tx))) + .expect("should be able to send"); + rx.await.expect("todo: err handling") + } + + /// Tells the persistence task to remove blocks above a certain block number. The removed blocks + /// are returned by the task. + pub async fn remove_blocks_above(&self, block_num: u64) -> Vec { + let (tx, rx) = oneshot::channel(); + self.sender + .send(PersistenceAction::RemoveBlocksAbove((block_num, tx))) + .expect("should be able to send"); + rx.await.expect("todo: err handling") + } +} diff --git a/crates/engine/tree/src/test_utils.rs b/crates/engine/tree/src/test_utils.rs new file mode 100644 index 000000000000..eed483e29932 --- /dev/null +++ b/crates/engine/tree/src/test_utils.rs @@ -0,0 +1,21 @@ +use reth_network_p2p::test_utils::TestFullBlockClient; +use reth_primitives::{BlockBody, SealedHeader}; +use std::ops::Range; + +pub(crate) fn insert_headers_into_client( + client: &TestFullBlockClient, + genesis_header: SealedHeader, + range: Range, +) { + let mut sealed_header = genesis_header; + let body = BlockBody::default(); + for _ in range { + let (mut header, hash) = sealed_header.split(); + // update to the next header + header.parent_hash = hash; + header.number += 1; + header.timestamp += 1; + sealed_header = header.seal_slow(); + client.insert(sealed_header.clone(), body.clone()); + } +} diff --git a/crates/engine/tree/src/tree/memory_overlay.rs b/crates/engine/tree/src/tree/memory_overlay.rs new file mode 100644 index 000000000000..7e0e1d52e5be --- /dev/null +++ b/crates/engine/tree/src/tree/memory_overlay.rs @@ -0,0 +1,123 @@ +use super::ExecutedBlock; +use reth_errors::ProviderResult; +use reth_primitives::{Account, Address, BlockNumber, Bytecode, StorageKey, StorageValue, B256}; +use reth_provider::{AccountReader, BlockHashReader, StateProvider, StateRootProvider}; +use reth_trie::{updates::TrieUpdates, AccountProof}; +use revm::db::BundleState; + +/// A state provider that stores references to in-memory blocks along with their state as well as +/// the historical state provider for fallback lookups. +#[derive(Debug)] +pub struct MemoryOverlayStateProvider { + /// The collection of executed parent blocks. + in_memory: Vec, + /// Historical state provider for state lookups that are not found in in-memory blocks. + historical: H, +} + +impl MemoryOverlayStateProvider { + /// Create new memory overlay state provider. + pub const fn new(in_memory: Vec, historical: H) -> Self { + Self { in_memory, historical } + } +} + +impl BlockHashReader for MemoryOverlayStateProvider +where + H: BlockHashReader, +{ + fn block_hash(&self, number: BlockNumber) -> ProviderResult> { + for block in self.in_memory.iter().rev() { + if block.block.number == number { + return Ok(Some(block.block.hash())) + } + } + + self.historical.block_hash(number) + } + + fn canonical_hashes_range( + &self, + start: BlockNumber, + end: BlockNumber, + ) -> ProviderResult> { + let range = start..end; + let mut earliest_block_number = None; + let mut in_memory_hashes = Vec::new(); + for block in self.in_memory.iter().rev() { + if range.contains(&block.block.number) { + in_memory_hashes.insert(0, block.block.hash()); + earliest_block_number = Some(block.block.number); + } + } + + let mut hashes = + self.historical.canonical_hashes_range(start, earliest_block_number.unwrap_or(end))?; + hashes.append(&mut in_memory_hashes); + Ok(hashes) + } +} + +impl AccountReader for MemoryOverlayStateProvider +where + H: AccountReader + Send, +{ + fn basic_account(&self, address: Address) -> ProviderResult> { + for block in self.in_memory.iter().rev() { + if let Some(account) = block.execution_output.account(&address) { + return Ok(account) + } + } + + self.historical.basic_account(address) + } +} + +impl StateRootProvider for MemoryOverlayStateProvider +where + H: StateRootProvider + Send, +{ + fn state_root(&self, bundle_state: &BundleState) -> ProviderResult { + todo!() + } + + fn state_root_with_updates( + &self, + bundle_state: &BundleState, + ) -> ProviderResult<(B256, TrieUpdates)> { + todo!() + } +} + +impl StateProvider for MemoryOverlayStateProvider +where + H: StateProvider + Send, +{ + fn storage( + &self, + address: Address, + storage_key: StorageKey, + ) -> ProviderResult> { + for block in self.in_memory.iter().rev() { + if let Some(value) = block.execution_output.storage(&address, storage_key.into()) { + return Ok(Some(value)) + } + } + + self.historical.storage(address, storage_key) + } + + fn bytecode_by_hash(&self, code_hash: B256) -> ProviderResult> { + for block in self.in_memory.iter().rev() { + if let Some(contract) = block.execution_output.bytecode(&code_hash) { + return Ok(Some(contract)) + } + } + + self.historical.bytecode_by_hash(code_hash) + } + + fn proof(&self, address: Address, keys: &[B256]) -> ProviderResult { + todo!() + } +} diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs new file mode 100644 index 000000000000..e4cf33923cfd --- /dev/null +++ b/crates/engine/tree/src/tree/mod.rs @@ -0,0 +1,574 @@ +use crate::{backfill::BackfillAction, engine::DownloadRequest}; +use reth_beacon_consensus::{ForkchoiceStateTracker, InvalidHeaderCache, OnForkChoiceUpdated}; +use reth_blockchain_tree::{ + error::InsertBlockErrorKind, BlockAttachment, BlockBuffer, BlockStatus, +}; +use reth_blockchain_tree_api::{error::InsertBlockError, InsertPayloadOk}; +use reth_consensus::{Consensus, PostExecutionInput}; +use reth_engine_primitives::EngineTypes; +use reth_errors::{ConsensusError, ProviderResult}; +use reth_evm::execute::{BlockExecutorProvider, Executor}; +use reth_payload_primitives::PayloadTypes; +use reth_payload_validator::ExecutionPayloadValidator; +use reth_primitives::{ + Address, Block, BlockNumber, Receipts, Requests, SealedBlock, SealedBlockWithSenders, B256, + U256, +}; +use reth_provider::{BlockReader, ExecutionOutcome, StateProvider, StateProviderFactory}; +use reth_revm::database::StateProviderDatabase; +use reth_rpc_types::{ + engine::{ + CancunPayloadFields, ForkchoiceState, PayloadStatus, PayloadStatusEnum, + PayloadValidationError, + }, + ExecutionPayload, +}; +use reth_trie::{updates::TrieUpdates, HashedPostState}; +use std::{ + collections::{BTreeMap, HashMap}, + marker::PhantomData, + sync::Arc, +}; +use tracing::*; + +mod memory_overlay; +pub use memory_overlay::MemoryOverlayStateProvider; + +/// Represents an executed block stored in-memory. +#[derive(Clone, Debug)] +pub struct ExecutedBlock { + block: Arc, + senders: Arc>, + execution_output: Arc, + hashed_state: Arc, + trie: Arc, +} + +impl ExecutedBlock { + /// Returns a reference to the executed block. + pub(crate) fn block(&self) -> &SealedBlock { + &self.block + } +} + +/// Keeps track of the state of the tree. +#[derive(Debug)] +pub struct TreeState { + /// All executed blocks by hash. + blocks_by_hash: HashMap, + /// Executed blocks grouped by their respective block number. + blocks_by_number: BTreeMap>, +} + +impl TreeState { + fn block_by_hash(&self, hash: B256) -> Option> { + self.blocks_by_hash.get(&hash).map(|b| b.block.clone()) + } + + /// Insert executed block into the state. + fn insert_executed(&mut self, executed: ExecutedBlock) { + self.blocks_by_number.entry(executed.block.number).or_default().push(executed.clone()); + let existing = self.blocks_by_hash.insert(executed.block.hash(), executed); + debug_assert!(existing.is_none(), "inserted duplicate block"); + } + + /// Remove blocks before specified block number. + pub(crate) fn remove_before(&mut self, block_number: BlockNumber) { + while self + .blocks_by_number + .first_key_value() + .map(|entry| entry.0 < &block_number) + .unwrap_or_default() + { + let (_, to_remove) = self.blocks_by_number.pop_first().unwrap(); + for block in to_remove { + let block_hash = block.block.hash(); + let removed = self.blocks_by_hash.remove(&block_hash); + debug_assert!( + removed.is_some(), + "attempted to remove non-existing block {block_hash}" + ); + } + } + } +} + +/// Tracks the state of the engine api internals. +/// +/// This type is shareable. +#[derive(Debug)] +pub struct EngineApiTreeState { + /// Tracks the state of the blockchain tree. + tree_state: TreeState, + /// Tracks the received forkchoice state updates received by the CL. + forkchoice_state_tracker: ForkchoiceStateTracker, + /// Buffer of detached blocks. + buffer: BlockBuffer, + /// Tracks the header of invalid payloads that were rejected by the engine because they're + /// invalid. + invalid_headers: InvalidHeaderCache, +} + +/// The type responsible for processing engine API requests. +/// +/// TODO: design: should the engine handler functions also accept the response channel or return the +/// result and the caller redirects the response +pub trait EngineApiTreeHandler: Send + Sync { + /// The engine type that this handler is for. + type Engine: EngineTypes; + + /// Invoked when previously requested blocks were downloaded. + fn on_downloaded(&mut self, blocks: Vec) -> Option; + + /// When the Consensus layer receives a new block via the consensus gossip protocol, + /// the transactions in the block are sent to the execution layer in the form of a + /// [`ExecutionPayload`]. The Execution layer executes the transactions and validates the + /// state in the block header, then passes validation data back to Consensus layer, that + /// adds the block to the head of its own blockchain and attests to it. The block is then + /// broadcast over the consensus p2p network in the form of a "Beacon block". + /// + /// These responses should adhere to the [Engine API Spec for + /// `engine_newPayload`](https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#specification). + /// + /// This returns a [`PayloadStatus`] that represents the outcome of a processed new payload and + /// returns an error if an internal error occurred. + fn on_new_payload( + &mut self, + payload: ExecutionPayload, + cancun_fields: Option, + ) -> ProviderResult>; + + /// Invoked when we receive a new forkchoice update message. Calls into the blockchain tree + /// to resolve chain forks and ensure that the Execution Layer is working with the latest valid + /// chain. + /// + /// These responses should adhere to the [Engine API Spec for + /// `engine_forkchoiceUpdated`](https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#specification-1). + /// + /// Returns an error if an internal error occurred like a database error. + fn on_forkchoice_updated( + &mut self, + state: ForkchoiceState, + attrs: Option<::PayloadAttributes>, + ) -> TreeOutcome>; +} + +/// The outcome of a tree operation. +#[derive(Debug)] +pub struct TreeOutcome { + /// The outcome of the operation. + pub outcome: T, + /// An optional event to tell the caller to do something. + pub event: Option, +} + +impl TreeOutcome { + /// Create new tree outcome. + pub const fn new(outcome: T) -> Self { + Self { outcome, event: None } + } + + /// Set event on the outcome. + pub fn with_event(mut self, event: TreeEvent) -> Self { + self.event = Some(event); + self + } +} + +/// Events that can be emitted by the [`EngineApiTreeHandler`]. +#[derive(Debug)] +pub enum TreeEvent { + /// Tree action is needed. + TreeAction(TreeAction), + /// Backfill action is needed. + BackfillAction(BackfillAction), + /// Block download is needed. + Download(DownloadRequest), +} + +/// The actions that can be performed on the tree. +#[derive(Debug)] +pub enum TreeAction { + /// Make target canonical. + MakeCanonical(B256), +} + +#[derive(Debug)] +pub struct EngineApiTreeHandlerImpl { + provider: P, + executor_provider: E, + consensus: Arc, + payload_validator: ExecutionPayloadValidator, + state: EngineApiTreeState, + /// (tmp) The flag indicating whether the pipeline is active. + is_pipeline_active: bool, + _marker: PhantomData, +} + +impl EngineApiTreeHandlerImpl +where + P: BlockReader + StateProviderFactory, + E: BlockExecutorProvider, + T: EngineTypes, +{ + /// Return block from database or in-memory state by hash. + fn block_by_hash(&self, hash: B256) -> ProviderResult> { + // check database first + let mut block = self.provider.block_by_hash(hash)?; + if block.is_none() { + // Note: it's fine to return the unsealed block because the caller already has + // the hash + block = self + .state + .tree_state + .block_by_hash(hash) + // TODO: clone for compatibility. should we return an Arc here? + .map(|block| block.as_ref().clone().unseal()); + } + Ok(block) + } + + /// Return state provider with reference to in-memory blocks that overlay database state. + fn state_provider( + &self, + hash: B256, + ) -> ProviderResult>> { + let mut in_memory = Vec::new(); + let mut parent_hash = hash; + while let Some(executed) = self.state.tree_state.blocks_by_hash.get(&parent_hash) { + parent_hash = executed.block.parent_hash; + in_memory.insert(0, executed.clone()); + } + + let historical = self.provider.state_by_block_hash(parent_hash)?; + Ok(MemoryOverlayStateProvider::new(in_memory, historical)) + } + + /// Return the parent hash of the lowest buffered ancestor for the requested block, if there + /// are any buffered ancestors. If there are no buffered ancestors, and the block itself does + /// not exist in the buffer, this returns the hash that is passed in. + /// + /// Returns the parent hash of the block itself if the block is buffered and has no other + /// buffered ancestors. + fn lowest_buffered_ancestor_or(&self, hash: B256) -> B256 { + self.state + .buffer + .lowest_ancestor(&hash) + .map(|block| block.parent_hash) + .unwrap_or_else(|| hash) + } + + /// If validation fails, the response MUST contain the latest valid hash: + /// + /// - The block hash of the ancestor of the invalid payload satisfying the following two + /// conditions: + /// - It is fully validated and deemed VALID + /// - Any other ancestor of the invalid payload with a higher blockNumber is INVALID + /// - 0x0000000000000000000000000000000000000000000000000000000000000000 if the above + /// conditions are satisfied by a `PoW` block. + /// - null if client software cannot determine the ancestor of the invalid payload satisfying + /// the above conditions. + fn latest_valid_hash_for_invalid_payload( + &mut self, + parent_hash: B256, + ) -> ProviderResult> { + // Check if parent exists in side chain or in canonical chain. + if self.block_by_hash(parent_hash)?.is_some() { + return Ok(Some(parent_hash)) + } + + // iterate over ancestors in the invalid cache + // until we encounter the first valid ancestor + let mut current_hash = parent_hash; + let mut current_header = self.state.invalid_headers.get(¤t_hash); + while let Some(header) = current_header { + current_hash = header.parent_hash; + current_header = self.state.invalid_headers.get(¤t_hash); + + // If current_header is None, then the current_hash does not have an invalid + // ancestor in the cache, check its presence in blockchain tree + if current_header.is_none() && self.block_by_hash(current_hash)?.is_some() { + return Ok(Some(current_hash)) + } + } + Ok(None) + } + + /// Prepares the invalid payload response for the given hash, checking the + /// database for the parent hash and populating the payload status with the latest valid hash + /// according to the engine api spec. + fn prepare_invalid_response(&mut self, mut parent_hash: B256) -> ProviderResult { + // Edge case: the `latestValid` field is the zero hash if the parent block is the terminal + // PoW block, which we need to identify by looking at the parent's block difficulty + if let Some(parent) = self.block_by_hash(parent_hash)? { + if !parent.is_zero_difficulty() { + parent_hash = B256::ZERO; + } + } + + let valid_parent_hash = self.latest_valid_hash_for_invalid_payload(parent_hash)?; + Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid { + validation_error: PayloadValidationError::LinksToRejectedPayload.to_string(), + }) + .with_latest_valid_hash(valid_parent_hash.unwrap_or_default())) + } + + /// Checks if the given `check` hash points to an invalid header, inserting the given `head` + /// block into the invalid header cache if the `check` hash has a known invalid ancestor. + /// + /// Returns a payload status response according to the engine API spec if the block is known to + /// be invalid. + fn check_invalid_ancestor_with_head( + &mut self, + check: B256, + head: B256, + ) -> ProviderResult> { + // check if the check hash was previously marked as invalid + let Some(header) = self.state.invalid_headers.get(&check) else { return Ok(None) }; + + // populate the latest valid hash field + let status = self.prepare_invalid_response(header.parent_hash)?; + + // insert the head block into the invalid header cache + self.state.invalid_headers.insert_with_invalid_ancestor(head, header); + + Ok(Some(status)) + } + + /// Validate if block is correct and satisfies all the consensus rules that concern the header + /// and block body itself. + fn validate_block(&self, block: &SealedBlockWithSenders) -> Result<(), ConsensusError> { + if let Err(e) = self.consensus.validate_header_with_total_difficulty(block, U256::MAX) { + error!( + ?block, + "Failed to validate total difficulty for block {}: {e}", + block.header.hash() + ); + return Err(e) + } + + if let Err(e) = self.consensus.validate_header(block) { + error!(?block, "Failed to validate header {}: {e}", block.header.hash()); + return Err(e) + } + + if let Err(e) = self.consensus.validate_block_pre_execution(block) { + error!(?block, "Failed to validate block {}: {e}", block.header.hash()); + return Err(e) + } + + Ok(()) + } + + fn buffer_block_without_senders(&mut self, block: SealedBlock) -> Result<(), InsertBlockError> { + match block.try_seal_with_senders() { + Ok(block) => self.buffer_block(block), + Err(block) => Err(InsertBlockError::sender_recovery_error(block)), + } + } + + fn buffer_block(&mut self, block: SealedBlockWithSenders) -> Result<(), InsertBlockError> { + if let Err(err) = self.validate_block(&block) { + return Err(InsertBlockError::consensus_error(err, block.block)) + } + self.state.buffer.insert_block(block); + Ok(()) + } + + fn insert_block_without_senders( + &mut self, + block: SealedBlock, + ) -> Result { + match block.try_seal_with_senders() { + Ok(block) => self.insert_block(block), + Err(block) => Err(InsertBlockError::sender_recovery_error(block)), + } + } + + fn insert_block( + &mut self, + block: SealedBlockWithSenders, + ) -> Result { + self.insert_block_inner(block.clone()) + .map_err(|kind| InsertBlockError::new(block.block, kind)) + } + + fn insert_block_inner( + &mut self, + block: SealedBlockWithSenders, + ) -> Result { + if self.block_by_hash(block.hash())?.is_some() { + let attachment = BlockAttachment::Canonical; // TODO: remove or revise attachment + return Ok(InsertPayloadOk::AlreadySeen(BlockStatus::Valid(attachment))) + } + + // validate block consensus rules + self.validate_block(&block)?; + + let state_provider = self.state_provider(block.parent_hash).unwrap(); + let executor = self.executor_provider.executor(StateProviderDatabase::new(&state_provider)); + + let block_number = block.number; + let block_hash = block.hash(); + let block = block.unseal(); + let output = executor.execute((&block, U256::MAX).into()).unwrap(); + self.consensus.validate_block_post_execution( + &block, + PostExecutionInput::new(&output.receipts, &output.requests), + )?; + + let hashed_state = HashedPostState::from_bundle_state(&output.state.state); + + // TODO: compute and validate state root + let trie_output = TrieUpdates::default(); + + let executed = ExecutedBlock { + block: Arc::new(block.block.seal(block_hash)), + senders: Arc::new(block.senders), + execution_output: Arc::new(ExecutionOutcome::new( + output.state, + Receipts::from(output.receipts), + block_number, + vec![Requests::from(output.requests)], + )), + hashed_state: Arc::new(hashed_state), + trie: Arc::new(trie_output), + }; + self.state.tree_state.insert_executed(executed); + + let attachment = BlockAttachment::Canonical; // TODO: remove or revise attachment + Ok(InsertPayloadOk::Inserted(BlockStatus::Valid(attachment))) + } +} + +impl EngineApiTreeHandler for EngineApiTreeHandlerImpl +where + P: BlockReader + StateProviderFactory + Clone, + E: BlockExecutorProvider, + T: EngineTypes, +{ + type Engine = T; + + fn on_downloaded(&mut self, _blocks: Vec) -> Option { + todo!() + } + + fn on_new_payload( + &mut self, + payload: ExecutionPayload, + cancun_fields: Option, + ) -> ProviderResult> { + // Ensures that the given payload does not violate any consensus rules that concern the + // block's layout, like: + // - missing or invalid base fee + // - invalid extra data + // - invalid transactions + // - incorrect hash + // - the versioned hashes passed with the payload do not exactly match transaction + // versioned hashes + // - the block does not contain blob transactions if it is pre-cancun + // + // This validates the following engine API rule: + // + // 3. Given the expected array of blob versioned hashes client software **MUST** run its + // validation by taking the following steps: + // + // 1. Obtain the actual array by concatenating blob versioned hashes lists + // (`tx.blob_versioned_hashes`) of each [blob + // transaction](https://eips.ethereum.org/EIPS/eip-4844#new-transaction-type) included + // in the payload, respecting the order of inclusion. If the payload has no blob + // transactions the expected array **MUST** be `[]`. + // + // 2. Return `{status: INVALID, latestValidHash: null, validationError: errorMessage | + // null}` if the expected and the actual arrays don't match. + // + // This validation **MUST** be instantly run in all cases even during active sync process. + let parent_hash = payload.parent_hash(); + let block = match self + .payload_validator + .ensure_well_formed_payload(payload, cancun_fields.into()) + { + Ok(block) => block, + Err(error) => { + error!(target: "engine::tree", %error, "Invalid payload"); + // we need to convert the error to a payload status (response to the CL) + + let latest_valid_hash = + if error.is_block_hash_mismatch() || error.is_invalid_versioned_hashes() { + // Engine-API rules: + // > `latestValidHash: null` if the blockHash validation has failed () + // > `latestValidHash: null` if the expected and the actual arrays don't match () + None + } else { + self.latest_valid_hash_for_invalid_payload(parent_hash)? + }; + + let status = PayloadStatusEnum::from(error); + return Ok(TreeOutcome::new(PayloadStatus::new(status, latest_valid_hash))) + } + }; + + let block_hash = block.hash(); + let mut lowest_buffered_ancestor = self.lowest_buffered_ancestor_or(block_hash); + if lowest_buffered_ancestor == block_hash { + lowest_buffered_ancestor = block.parent_hash; + } + + // now check the block itself + if let Some(status) = + self.check_invalid_ancestor_with_head(lowest_buffered_ancestor, block_hash)? + { + return Ok(TreeOutcome::new(status)) + } + + let status = if self.is_pipeline_active { + self.buffer_block_without_senders(block).unwrap(); + PayloadStatus::from_status(PayloadStatusEnum::Syncing) + } else { + let mut latest_valid_hash = None; + let status = match self.insert_block_without_senders(block).unwrap() { + InsertPayloadOk::Inserted(BlockStatus::Valid(_)) | + InsertPayloadOk::AlreadySeen(BlockStatus::Valid(_)) => { + latest_valid_hash = Some(block_hash); + PayloadStatusEnum::Valid + } + InsertPayloadOk::Inserted(BlockStatus::Disconnected { .. }) | + InsertPayloadOk::AlreadySeen(BlockStatus::Disconnected { .. }) => { + // TODO: isn't this check redundant? + // check if the block's parent is already marked as invalid + // if let Some(status) = self + // .check_invalid_ancestor_with_head(block.parent_hash, block.hash()) + // .map_err(|error| { + // InsertBlockError::new(block, InsertBlockErrorKind::Provider(error)) + // })? + // { + // return Ok(status) + // } + + // not known to be invalid, but we don't know anything else + PayloadStatusEnum::Syncing + } + }; + PayloadStatus::new(status, latest_valid_hash) + }; + + let mut outcome = TreeOutcome::new(status); + if outcome.outcome.is_valid() { + if let Some(target) = self.state.forkchoice_state_tracker.sync_target_state() { + if target.head_block_hash == block_hash { + outcome = outcome + .with_event(TreeEvent::TreeAction(TreeAction::MakeCanonical(block_hash))); + } + } + } + Ok(outcome) + } + + fn on_forkchoice_updated( + &mut self, + state: ForkchoiceState, + attrs: Option<::PayloadAttributes>, + ) -> TreeOutcome> { + todo!() + } +} diff --git a/crates/engine/util/Cargo.toml b/crates/engine/util/Cargo.toml new file mode 100644 index 000000000000..26d504a745af --- /dev/null +++ b/crates/engine/util/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "reth-engine-util" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +# reth +reth-fs-util.workspace = true +reth-rpc.workspace = true +reth-rpc-types.workspace = true +reth-engine-primitives.workspace = true +reth-beacon-consensus.workspace = true + +# async +tokio-util.workspace = true +pin-project.workspace = true + +# misc +eyre.workspace = true + +# io +serde.workspace = true +serde_json.workspace = true + +# tracing +tracing.workspace = true + +# async +futures.workspace = true + +[features] +optimism = [ + "reth-rpc/optimism", + "reth-beacon-consensus/optimism", +] diff --git a/crates/node-core/src/engine/engine_store.rs b/crates/engine/util/src/engine_store.rs similarity index 96% rename from crates/node-core/src/engine/engine_store.rs rename to crates/engine/util/src/engine_store.rs index c6e2b65c5be0..9ce9cb4b43de 100644 --- a/crates/node-core/src/engine/engine_store.rs +++ b/crates/engine/util/src/engine_store.rs @@ -3,6 +3,8 @@ use futures::{Stream, StreamExt}; use reth_beacon_consensus::BeaconEngineMessage; use reth_engine_primitives::EngineTypes; +#[cfg(feature = "taiko")] +use reth_payload_builder::TaikoExecutionPayload; use reth_fs_util as fs; use reth_rpc_types::{ engine::{CancunPayloadFields, ForkchoiceState}, @@ -32,7 +34,10 @@ pub enum StoredEngineApiMessage { /// The on-disk representation of an `engine_newPayload` method call. NewPayload { /// The [`ExecutionPayload`] sent in the persisted call. + #[cfg(not(feature = "taiko"))] payload: ExecutionPayload, + #[cfg(feature = "taiko")] + payload: TaikoExecutionPayload, /// The Cancun-specific fields sent in the persisted call, if any. cancun_fields: Option, }, diff --git a/crates/node-core/src/engine/mod.rs b/crates/engine/util/src/lib.rs similarity index 100% rename from crates/node-core/src/engine/mod.rs rename to crates/engine/util/src/lib.rs diff --git a/crates/node-core/src/engine/skip_fcu.rs b/crates/engine/util/src/skip_fcu.rs similarity index 100% rename from crates/node-core/src/engine/skip_fcu.rs rename to crates/engine/util/src/skip_fcu.rs diff --git a/crates/node-core/src/engine/skip_new_payload.rs b/crates/engine/util/src/skip_new_payload.rs similarity index 100% rename from crates/node-core/src/engine/skip_new_payload.rs rename to crates/engine/util/src/skip_new_payload.rs diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index bcdbc6551a41..9bdc0c98c91e 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -23,11 +23,15 @@ crc = "3" # misc serde = { workspace = true, features = ["derive"], optional = true } thiserror-no-std = { workspace = true, default-features = false } +once_cell.workspace = true +dyn-clone.workspace = true +rustc-hash.workspace = true # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } +auto_impl.workspace = true [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } diff --git a/crates/ethereum-forks/src/chains/dev.rs b/crates/ethereum-forks/src/chains/dev.rs deleted file mode 100644 index 866be0dd4260..000000000000 --- a/crates/ethereum-forks/src/chains/dev.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::uint; - -/// Dev hardforks -pub const DEV_HARDFORKS: [(Hardfork, ForkCondition); 14] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(1561651)), - (Hardfork::Berlin, ForkCondition::Block(4460644)), - (Hardfork::London, ForkCondition::Block(5062605)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1678832736)), - (Hardfork::Cancun, ForkCondition::Timestamp(1705473120)), -]; diff --git a/crates/ethereum-forks/src/chains/ethereum.rs b/crates/ethereum-forks/src/chains/ethereum.rs deleted file mode 100644 index 6db4d95fcade..000000000000 --- a/crates/ethereum-forks/src/chains/ethereum.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::{uint, U256}; - -/// Ethereum mainnet hardforks -pub const MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 17] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(1150000)), - (Hardfork::Dao, ForkCondition::Block(1920000)), - (Hardfork::Tangerine, ForkCondition::Block(2463000)), - (Hardfork::SpuriousDragon, ForkCondition::Block(2675000)), - (Hardfork::Byzantium, ForkCondition::Block(4370000)), - (Hardfork::Constantinople, ForkCondition::Block(7280000)), - (Hardfork::Petersburg, ForkCondition::Block(7280000)), - (Hardfork::Istanbul, ForkCondition::Block(9069000)), - (Hardfork::MuirGlacier, ForkCondition::Block(9200000)), - (Hardfork::Berlin, ForkCondition::Block(12244000)), - (Hardfork::London, ForkCondition::Block(12965000)), - (Hardfork::ArrowGlacier, ForkCondition::Block(13773000)), - (Hardfork::GrayGlacier, ForkCondition::Block(15050000)), - ( - Hardfork::Paris, - ForkCondition::TTD { - fork_block: None, - total_difficulty: uint!(58_750_000_000_000_000_000_000_U256), - }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1681338455)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710338135)), -]; - -/// Ethereum Goerli hardforks -pub const GOERLI_HARDFORKS: [(Hardfork, ForkCondition); 14] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(1561651)), - (Hardfork::Berlin, ForkCondition::Block(4460644)), - (Hardfork::London, ForkCondition::Block(5062605)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1678832736)), - (Hardfork::Cancun, ForkCondition::Timestamp(1705473120)), -]; - -/// Ethereum Sepolia hardforks -pub const SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 15] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - ( - Hardfork::Paris, - ForkCondition::TTD { - fork_block: Some(1735371), - total_difficulty: uint!(17_000_000_000_000_000_U256), - }, - ), - (Hardfork::Shanghai, ForkCondition::Timestamp(1677557088)), - (Hardfork::Cancun, ForkCondition::Timestamp(1706655072)), -]; - -/// Ethereum Holesky hardforks -pub const HOLESKY_HARDFORKS: [(Hardfork, ForkCondition); 15] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Dao, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Shanghai, ForkCondition::Timestamp(1696000704)), - (Hardfork::Cancun, ForkCondition::Timestamp(1707305664)), -]; diff --git a/crates/ethereum-forks/src/chains/mod.rs b/crates/ethereum-forks/src/chains/mod.rs deleted file mode 100644 index ef775777f399..000000000000 --- a/crates/ethereum-forks/src/chains/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// Ethereum chains -pub mod ethereum; - -/// Optimism chains -#[cfg(feature = "optimism")] -pub mod optimism; - -/// Dev chain -pub mod dev; diff --git a/crates/ethereum-forks/src/chains/optimism.rs b/crates/ethereum-forks/src/chains/optimism.rs deleted file mode 100644 index 37af4a19ffe6..000000000000 --- a/crates/ethereum-forks/src/chains/optimism.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ForkCondition, Hardfork}; -use alloy_primitives::U256; - -/// Optimism mainnet hardforks -pub const OP_MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(3950000)), - (Hardfork::London, ForkCondition::Block(105235063)), - (Hardfork::ArrowGlacier, ForkCondition::Block(105235063)), - (Hardfork::GrayGlacier, ForkCondition::Block(105235063)), - ( - Hardfork::Paris, - ForkCondition::TTD { fork_block: Some(105235063), total_difficulty: U256::ZERO }, - ), - (Hardfork::Bedrock, ForkCondition::Block(105235063)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1704992401)), - (Hardfork::Canyon, ForkCondition::Timestamp(1704992401)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710374401)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1710374401)), - (Hardfork::Fjord, ForkCondition::Timestamp(1720627201)), -]; - -/// Optimism Sepolia hardforks -pub const OP_SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)), - (Hardfork::Canyon, ForkCondition::Timestamp(1699981200)), - (Hardfork::Cancun, ForkCondition::Timestamp(1708534800)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1708534800)), - (Hardfork::Fjord, ForkCondition::Timestamp(1716998400)), -]; - -/// Base Sepolia hardforks -pub const BASE_SEPOLIA_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1699981200)), - (Hardfork::Canyon, ForkCondition::Timestamp(1699981200)), - (Hardfork::Cancun, ForkCondition::Timestamp(1708534800)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1708534800)), - (Hardfork::Fjord, ForkCondition::Timestamp(1716998400)), -]; - -/// Base Mainnet hardforks -pub const BASE_MAINNET_HARDFORKS: [(Hardfork, ForkCondition); 21] = [ - (Hardfork::Frontier, ForkCondition::Block(0)), - (Hardfork::Homestead, ForkCondition::Block(0)), - (Hardfork::Tangerine, ForkCondition::Block(0)), - (Hardfork::SpuriousDragon, ForkCondition::Block(0)), - (Hardfork::Byzantium, ForkCondition::Block(0)), - (Hardfork::Constantinople, ForkCondition::Block(0)), - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(0)), - (Hardfork::MuirGlacier, ForkCondition::Block(0)), - (Hardfork::Berlin, ForkCondition::Block(0)), - (Hardfork::London, ForkCondition::Block(0)), - (Hardfork::ArrowGlacier, ForkCondition::Block(0)), - (Hardfork::GrayGlacier, ForkCondition::Block(0)), - (Hardfork::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), - (Hardfork::Bedrock, ForkCondition::Block(0)), - (Hardfork::Regolith, ForkCondition::Timestamp(0)), - (Hardfork::Shanghai, ForkCondition::Timestamp(1704992401)), - (Hardfork::Canyon, ForkCondition::Timestamp(1704992401)), - (Hardfork::Cancun, ForkCondition::Timestamp(1710374401)), - (Hardfork::Ecotone, ForkCondition::Timestamp(1710374401)), - (Hardfork::Fjord, ForkCondition::Timestamp(1720627201)), -]; diff --git a/crates/ethereum-forks/src/display.rs b/crates/ethereum-forks/src/display.rs index 3c1424083638..d8a2007e443e 100644 --- a/crates/ethereum-forks/src/display.rs +++ b/crates/ethereum-forks/src/display.rs @@ -6,9 +6,7 @@ use alloc::{ vec::Vec, }; -use crate::{ForkCondition, Hardfork}; -#[cfg(feature = "std")] -use std::collections::BTreeMap; +use crate::{hardforks::Hardforks, ForkCondition}; /// A container to pretty-print a hardfork. /// @@ -146,27 +144,22 @@ impl core::fmt::Display for DisplayHardforks { impl DisplayHardforks { /// Creates a new [`DisplayHardforks`] from an iterator of hardforks. - pub fn new( - hardforks: &BTreeMap, - known_paris_block: Option, - ) -> Self { + pub fn new(hardforks: &H, known_paris_block: Option) -> Self { let mut pre_merge = Vec::new(); let mut with_merge = Vec::new(); let mut post_merge = Vec::new(); - for (fork, condition) in hardforks { + for (fork, condition) in hardforks.forks_iter() { let mut display_fork = - DisplayFork { name: fork.to_string(), activated_at: *condition, eip: None }; + DisplayFork { name: fork.name().to_string(), activated_at: condition, eip: None }; match condition { ForkCondition::Block(_) => { pre_merge.push(display_fork); } ForkCondition::TTD { total_difficulty, .. } => { - display_fork.activated_at = ForkCondition::TTD { - fork_block: known_paris_block, - total_difficulty: *total_difficulty, - }; + display_fork.activated_at = + ForkCondition::TTD { fork_block: known_paris_block, total_difficulty }; with_merge.push(display_fork); } ForkCondition::Timestamp(_) => { diff --git a/crates/ethereum-forks/src/hardfork.rs b/crates/ethereum-forks/src/hardfork.rs deleted file mode 100644 index fa095dea5a18..000000000000 --- a/crates/ethereum-forks/src/hardfork.rs +++ /dev/null @@ -1,702 +0,0 @@ -use alloy_chains::Chain; -use core::{ - fmt, - fmt::{Display, Formatter}, - str::FromStr, -}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[cfg(not(feature = "std"))] -use alloc::{format, string::String}; - -/// Represents the consensus type of a blockchain fork. -/// -/// This enum defines two variants: `ProofOfWork` for hardforks that use a proof-of-work consensus -/// mechanism, and `ProofOfStake` for hardforks that use a proof-of-stake consensus mechanism. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum ConsensusType { - /// Indicates a proof-of-work consensus mechanism. - ProofOfWork, - /// Indicates a proof-of-stake consensus mechanism. - ProofOfStake, -} - -/// The name of an Ethereum hardfork. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[non_exhaustive] -pub enum Hardfork { - /// Frontier: . - Frontier, - /// Homestead: . - Homestead, - /// The DAO fork: . - Dao, - /// Tangerine: . - Tangerine, - /// Spurious Dragon: . - SpuriousDragon, - /// Byzantium: . - Byzantium, - /// Constantinople: . - Constantinople, - /// Petersburg: . - Petersburg, - /// Istanbul: . - Istanbul, - /// Muir Glacier: . - MuirGlacier, - /// Berlin: . - Berlin, - /// London: . - London, - /// Arrow Glacier: . - ArrowGlacier, - /// Gray Glacier: . - GrayGlacier, - /// Paris: . - Paris, - /// Bedrock: . - #[cfg(feature = "optimism")] - Bedrock, - /// Regolith: . - #[cfg(feature = "optimism")] - Regolith, - /// Shanghai: . - Shanghai, - /// Canyon: - /// . - #[cfg(feature = "optimism")] - Canyon, - // ArbOS11, - /// Cancun. - Cancun, - /// Ecotone: . - #[cfg(feature = "optimism")] - Ecotone, - // ArbOS20Atlas, - - // Upcoming - /// Prague: - Prague, - /// Fjord: - #[cfg(feature = "optimism")] - Fjord, -} - -impl Hardfork { - /// Retrieves the consensus type for the specified hardfork. - pub fn consensus_type(&self) -> ConsensusType { - if *self >= Self::Paris { - ConsensusType::ProofOfStake - } else { - ConsensusType::ProofOfWork - } - } - - /// Checks if the hardfork uses Proof of Stake consensus. - pub fn is_proof_of_stake(&self) -> bool { - matches!(self.consensus_type(), ConsensusType::ProofOfStake) - } - - /// Checks if the hardfork uses Proof of Work consensus. - pub fn is_proof_of_work(&self) -> bool { - matches!(self.consensus_type(), ConsensusType::ProofOfWork) - } - - /// Retrieves the activation block for the specified hardfork on the given chain. - pub fn activation_block(&self, chain: Chain) -> Option { - if chain == Chain::mainnet() { - return self.mainnet_activation_block() - } - if chain == Chain::sepolia() { - return self.sepolia_activation_block() - } - if chain == Chain::holesky() { - return self.holesky_activation_block() - } - - #[cfg(feature = "optimism")] - { - if chain == Chain::base_sepolia() { - return self.base_sepolia_activation_block() - } - if chain == Chain::base_mainnet() { - return self.base_mainnet_activation_block() - } - } - - None - } - - /// Retrieves the activation block for the specified hardfork on the Ethereum mainnet. - pub const fn mainnet_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier => Some(0), - Self::Homestead => Some(1150000), - Self::Dao => Some(1920000), - Self::Tangerine => Some(2463000), - Self::SpuriousDragon => Some(2675000), - Self::Byzantium => Some(4370000), - Self::Constantinople | Self::Petersburg => Some(7280000), - Self::Istanbul => Some(9069000), - Self::MuirGlacier => Some(9200000), - Self::Berlin => Some(12244000), - Self::London => Some(12965000), - Self::ArrowGlacier => Some(13773000), - Self::GrayGlacier => Some(15050000), - Self::Paris => Some(15537394), - Self::Shanghai => Some(17034870), - Self::Cancun => Some(19426587), - - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Sepolia testnet. - pub const fn sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Paris => Some(1735371), - Self::Shanghai => Some(2990908), - Self::Cancun => Some(5187023), - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier => Some(0), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Arbitrum Sepolia testnet. - pub const fn arbitrum_sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(10653737), - // Hardfork::ArbOS11 => Some(10653737), - Self::Cancun => Some(18683405), - // Hardfork::ArbOS20Atlas => Some(18683405), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Arbitrum One mainnet. - pub const fn arbitrum_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(184097479), - // Hardfork::ArbOS11 => Some(184097479), - Self::Cancun => Some(190301729), - // Hardfork::ArbOS20Atlas => Some(190301729), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Base Sepolia testnet. - #[cfg(feature = "optimism")] - pub const fn base_sepolia_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(0), - Self::Shanghai | Self::Canyon => Some(2106456), - Self::Cancun | Self::Ecotone => Some(6383256), - Self::Fjord => Some(10615056), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the Base mainnet. - #[cfg(feature = "optimism")] - pub const fn base_mainnet_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(0), - Self::Shanghai | Self::Canyon => Some(9101527), - Self::Cancun | Self::Ecotone => Some(11188936), - _ => None, - } - } - - /// Retrieves the activation block for the specified hardfork on the holesky testnet. - const fn holesky_activation_block(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(0), - Self::Shanghai => Some(6698), - Self::Cancun => Some(894733), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the given chain. - pub fn activation_timestamp(&self, chain: Chain) -> Option { - if chain == Chain::mainnet() { - return self.mainnet_activation_timestamp() - } - if chain == Chain::sepolia() { - return self.sepolia_activation_timestamp() - } - if chain == Chain::holesky() { - return self.holesky_activation_timestamp() - } - #[cfg(feature = "optimism")] - { - if chain == Chain::base_sepolia() { - return self.base_sepolia_activation_timestamp() - } - if chain == Chain::base_mainnet() { - return self.base_mainnet_activation_timestamp() - } - } - - None - } - - /// Retrieves the activation timestamp for the specified hardfork on the Ethereum mainnet. - pub const fn mainnet_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier => Some(1438226773), - Self::Homestead => Some(1457938193), - Self::Dao => Some(1468977640), - Self::Tangerine => Some(1476753571), - Self::SpuriousDragon => Some(1479788144), - Self::Byzantium => Some(1508131331), - Self::Constantinople | Self::Petersburg => Some(1551340324), - Self::Istanbul => Some(1575807909), - Self::MuirGlacier => Some(1577953849), - Self::Berlin => Some(1618481223), - Self::London => Some(1628166822), - Self::ArrowGlacier => Some(1639036523), - Self::GrayGlacier => Some(1656586444), - Self::Paris => Some(1663224162), - Self::Shanghai => Some(1681338455), - Self::Cancun => Some(1710338135), - - // upcoming hardforks - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Sepolia testnet. - pub const fn sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1633267481), - Self::Shanghai => Some(1677557088), - Self::Cancun => Some(1706655072), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Holesky testnet. - pub const fn holesky_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Shanghai => Some(1696000704), - Self::Cancun => Some(1707305664), - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1695902100), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum Sepolia - /// testnet. - pub const fn arbitrum_sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1692726996), - Self::Shanghai => Some(1706634000), - // Hardfork::ArbOS11 => Some(1706634000), - Self::Cancun => Some(1709229600), - // Hardfork::ArbOS20Atlas => Some(1709229600), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum One mainnet. - pub const fn arbitrum_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris => Some(1622240000), - Self::Shanghai => Some(1708804873), - // Hardfork::ArbOS11 => Some(1708804873), - Self::Cancun => Some(1710424089), - // Hardfork::ArbOS20Atlas => Some(1710424089), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Base Sepolia testnet. - #[cfg(feature = "optimism")] - pub const fn base_sepolia_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(1695768288), - Self::Shanghai | Self::Canyon => Some(1699981200), - Self::Cancun | Self::Ecotone => Some(1708534800), - Self::Fjord => Some(1716998400), - _ => None, - } - } - - /// Retrieves the activation timestamp for the specified hardfork on the Base mainnet. - #[cfg(feature = "optimism")] - pub const fn base_mainnet_activation_timestamp(&self) -> Option { - #[allow(unreachable_patterns)] - match self { - Self::Frontier | - Self::Homestead | - Self::Dao | - Self::Tangerine | - Self::SpuriousDragon | - Self::Byzantium | - Self::Constantinople | - Self::Petersburg | - Self::Istanbul | - Self::MuirGlacier | - Self::Berlin | - Self::London | - Self::ArrowGlacier | - Self::GrayGlacier | - Self::Paris | - Self::Bedrock | - Self::Regolith => Some(1686789347), - Self::Shanghai | Self::Canyon => Some(1704992401), - Self::Cancun | Self::Ecotone => Some(1710374401), - Self::Fjord => Some(1720627201), - _ => None, - } - } -} - -impl FromStr for Hardfork { - type Err = String; - - fn from_str(s: &str) -> Result { - Ok(match s.to_lowercase().as_str() { - "frontier" => Self::Frontier, - "homestead" => Self::Homestead, - "dao" => Self::Dao, - "tangerine" => Self::Tangerine, - "spuriousdragon" => Self::SpuriousDragon, - "byzantium" => Self::Byzantium, - "constantinople" => Self::Constantinople, - "petersburg" => Self::Petersburg, - "istanbul" => Self::Istanbul, - "muirglacier" => Self::MuirGlacier, - "berlin" => Self::Berlin, - "london" => Self::London, - "arrowglacier" => Self::ArrowGlacier, - "grayglacier" => Self::GrayGlacier, - "paris" => Self::Paris, - "shanghai" => Self::Shanghai, - "cancun" => Self::Cancun, - #[cfg(feature = "optimism")] - "bedrock" => Self::Bedrock, - #[cfg(feature = "optimism")] - "regolith" => Self::Regolith, - #[cfg(feature = "optimism")] - "canyon" => Self::Canyon, - #[cfg(feature = "optimism")] - "ecotone" => Self::Ecotone, - #[cfg(feature = "optimism")] - "fjord" => Self::Fjord, - "prague" => Self::Prague, - // "arbos11" => Hardfork::ArbOS11, - // "arbos20atlas" => Hardfork::ArbOS20Atlas, - _ => return Err(format!("Unknown hardfork: {s}")), - }) - } -} - -impl Display for Hardfork { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{self:?}") - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn check_hardfork_from_str() { - let hardfork_str = [ - "frOntier", - "homEstead", - "dao", - "tAngerIne", - "spurIousdrAgon", - "byzAntium", - "constantinople", - "petersburg", - "istanbul", - "muirglacier", - "bErlin", - "lonDon", - "arrowglacier", - "grayglacier", - "PARIS", - "ShAnGhAI", - "CaNcUn", - "PrAguE", - ]; - let expected_hardforks = [ - Hardfork::Frontier, - Hardfork::Homestead, - Hardfork::Dao, - Hardfork::Tangerine, - Hardfork::SpuriousDragon, - Hardfork::Byzantium, - Hardfork::Constantinople, - Hardfork::Petersburg, - Hardfork::Istanbul, - Hardfork::MuirGlacier, - Hardfork::Berlin, - Hardfork::London, - Hardfork::ArrowGlacier, - Hardfork::GrayGlacier, - Hardfork::Paris, - Hardfork::Shanghai, - Hardfork::Cancun, - Hardfork::Prague, - ]; - - let hardforks: Vec = - hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect(); - - assert_eq!(hardforks, expected_hardforks); - } - - #[test] - #[cfg(feature = "optimism")] - fn check_op_hardfork_from_str() { - let hardfork_str = ["beDrOck", "rEgOlITH", "cAnYoN", "eCoToNe", "FJorD"]; - let expected_hardforks = [ - Hardfork::Bedrock, - Hardfork::Regolith, - Hardfork::Canyon, - Hardfork::Ecotone, - Hardfork::Fjord, - ]; - - let hardforks: Vec = - hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect(); - - assert_eq!(hardforks, expected_hardforks); - } - - #[test] - fn check_nonexistent_hardfork_from_str() { - assert!(Hardfork::from_str("not a hardfork").is_err()); - } - - #[test] - fn check_consensus_type() { - let pow_hardforks = [ - Hardfork::Frontier, - Hardfork::Homestead, - Hardfork::Dao, - Hardfork::Tangerine, - Hardfork::SpuriousDragon, - Hardfork::Byzantium, - Hardfork::Constantinople, - Hardfork::Petersburg, - Hardfork::Istanbul, - Hardfork::MuirGlacier, - Hardfork::Berlin, - Hardfork::London, - Hardfork::ArrowGlacier, - Hardfork::GrayGlacier, - ]; - - let pos_hardforks = [Hardfork::Paris, Hardfork::Shanghai, Hardfork::Cancun]; - - #[cfg(feature = "optimism")] - let op_hardforks = [ - Hardfork::Bedrock, - Hardfork::Regolith, - Hardfork::Canyon, - Hardfork::Ecotone, - Hardfork::Fjord, - ]; - - for hardfork in &pow_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfWork); - assert!(!hardfork.is_proof_of_stake()); - assert!(hardfork.is_proof_of_work()); - } - - for hardfork in &pos_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfStake); - assert!(hardfork.is_proof_of_stake()); - assert!(!hardfork.is_proof_of_work()); - } - - #[cfg(feature = "optimism")] - for hardfork in &op_hardforks { - assert_eq!(hardfork.consensus_type(), ConsensusType::ProofOfStake); - assert!(hardfork.is_proof_of_stake()); - assert!(!hardfork.is_proof_of_work()); - } - } -} diff --git a/crates/ethereum-forks/src/hardfork/dev.rs b/crates/ethereum-forks/src/hardfork/dev.rs new file mode 100644 index 000000000000..4b422141b425 --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/dev.rs @@ -0,0 +1,32 @@ +use crate::{ChainHardforks, EthereumHardfork, ForkCondition}; +use alloy_primitives::U256; +use once_cell::sync::Lazy; + +/// Dev hardforks +pub static DEV_HARDFORKS: Lazy = Lazy::new(|| { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Dao.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: None, total_difficulty: U256::ZERO }, + ), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Regolith.boxed(), ForkCondition::Timestamp(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Bedrock.boxed(), ForkCondition::Block(0)), + #[cfg(feature = "optimism")] + (crate::OptimismHardfork::Ecotone.boxed(), ForkCondition::Timestamp(0)), + ]) +}); diff --git a/crates/ethereum-forks/src/hardfork/ethereum.rs b/crates/ethereum-forks/src/hardfork/ethereum.rs new file mode 100644 index 000000000000..9e2a8a111216 --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/ethereum.rs @@ -0,0 +1,441 @@ +use crate::{hardfork, ChainHardforks, ForkCondition, Hardfork}; +use alloy_chains::Chain; +use alloy_primitives::{uint, U256}; +use core::{ + fmt, + fmt::{Display, Formatter}, + str::FromStr, +}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +hardfork!( + /// The name of an Ethereum hardfork. + EthereumHardfork { + /// Frontier: . + Frontier, + /// Homestead: . + Homestead, + /// The DAO fork: . + Dao, + /// Tangerine: . + Tangerine, + /// Spurious Dragon: . + SpuriousDragon, + /// Byzantium: . + Byzantium, + /// Constantinople: . + Constantinople, + /// Petersburg: . + Petersburg, + /// Istanbul: . + Istanbul, + /// Muir Glacier: . + MuirGlacier, + /// Berlin: . + Berlin, + /// London: . + London, + /// Arrow Glacier: . + ArrowGlacier, + /// Gray Glacier: . + GrayGlacier, + /// Paris: . + Paris, + /// Shanghai: . + Shanghai, + /// Cancun. + Cancun, + /// Prague: + Prague, + } +); + +impl EthereumHardfork { + /// Retrieves the activation block for the specified hardfork on the given chain. + pub fn activation_block(&self, chain: Chain) -> Option { + if chain == Chain::mainnet() { + return self.mainnet_activation_block() + } + if chain == Chain::sepolia() { + return self.sepolia_activation_block() + } + if chain == Chain::holesky() { + return self.holesky_activation_block() + } + + None + } + + /// Retrieves the activation block for the specified hardfork on the Ethereum mainnet. + pub const fn mainnet_activation_block(&self) -> Option { + match self { + Self::Frontier => Some(0), + Self::Homestead => Some(1150000), + Self::Dao => Some(1920000), + Self::Tangerine => Some(2463000), + Self::SpuriousDragon => Some(2675000), + Self::Byzantium => Some(4370000), + Self::Constantinople | Self::Petersburg => Some(7280000), + Self::Istanbul => Some(9069000), + Self::MuirGlacier => Some(9200000), + Self::Berlin => Some(12244000), + Self::London => Some(12965000), + Self::ArrowGlacier => Some(13773000), + Self::GrayGlacier => Some(15050000), + Self::Paris => Some(15537394), + Self::Shanghai => Some(17034870), + Self::Cancun => Some(19426587), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Sepolia testnet. + pub const fn sepolia_activation_block(&self) -> Option { + match self { + Self::Paris => Some(1735371), + Self::Shanghai => Some(2990908), + Self::Cancun => Some(5187023), + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier => Some(0), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the holesky testnet. + const fn holesky_activation_block(&self) -> Option { + match self { + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(6698), + Self::Cancun => Some(894733), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Arbitrum Sepolia testnet. + pub const fn arbitrum_sepolia_activation_block(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(10653737), + // Hardfork::ArbOS11 => Some(10653737), + Self::Cancun => Some(18683405), + // Hardfork::ArbOS20Atlas => Some(18683405), + _ => None, + } + } + + /// Retrieves the activation block for the specified hardfork on the Arbitrum One mainnet. + pub const fn arbitrum_activation_block(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(0), + Self::Shanghai => Some(184097479), + // Hardfork::ArbOS11 => Some(184097479), + Self::Cancun => Some(190301729), + // Hardfork::ArbOS20Atlas => Some(190301729), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the given chain. + pub fn activation_timestamp(&self, chain: Chain) -> Option { + if chain == Chain::mainnet() { + return self.mainnet_activation_timestamp() + } + if chain == Chain::sepolia() { + return self.sepolia_activation_timestamp() + } + if chain == Chain::holesky() { + return self.holesky_activation_timestamp() + } + + None + } + + /// Retrieves the activation timestamp for the specified hardfork on the Ethereum mainnet. + pub const fn mainnet_activation_timestamp(&self) -> Option { + match self { + Self::Frontier => Some(1438226773), + Self::Homestead => Some(1457938193), + Self::Dao => Some(1468977640), + Self::Tangerine => Some(1476753571), + Self::SpuriousDragon => Some(1479788144), + Self::Byzantium => Some(1508131331), + Self::Constantinople | Self::Petersburg => Some(1551340324), + Self::Istanbul => Some(1575807909), + Self::MuirGlacier => Some(1577953849), + Self::Berlin => Some(1618481223), + Self::London => Some(1628166822), + Self::ArrowGlacier => Some(1639036523), + Self::GrayGlacier => Some(1656586444), + Self::Paris => Some(1663224162), + Self::Shanghai => Some(1681338455), + Self::Cancun => Some(1710338135), + + // upcoming hardforks + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Sepolia testnet. + pub const fn sepolia_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1633267481), + Self::Shanghai => Some(1677557088), + Self::Cancun => Some(1706655072), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Holesky testnet. + pub const fn holesky_activation_timestamp(&self) -> Option { + match self { + Self::Shanghai => Some(1696000704), + Self::Cancun => Some(1707305664), + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1695902100), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum Sepolia + /// testnet. + pub const fn arbitrum_sepolia_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1692726996), + Self::Shanghai => Some(1706634000), + // Hardfork::ArbOS11 => Some(1706634000), + Self::Cancun => Some(1709229600), + // Hardfork::ArbOS20Atlas => Some(1709229600), + _ => None, + } + } + + /// Retrieves the activation timestamp for the specified hardfork on the Arbitrum One mainnet. + pub const fn arbitrum_activation_timestamp(&self) -> Option { + match self { + Self::Frontier | + Self::Homestead | + Self::Dao | + Self::Tangerine | + Self::SpuriousDragon | + Self::Byzantium | + Self::Constantinople | + Self::Petersburg | + Self::Istanbul | + Self::MuirGlacier | + Self::Berlin | + Self::London | + Self::ArrowGlacier | + Self::GrayGlacier | + Self::Paris => Some(1622240000), + Self::Shanghai => Some(1708804873), + // Hardfork::ArbOS11 => Some(1708804873), + Self::Cancun => Some(1710424089), + // Hardfork::ArbOS20Atlas => Some(1710424089), + _ => None, + } + } + + /// Ethereum mainnet list of hardforks. + pub const fn mainnet() -> [(Self, ForkCondition); 17] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(1150000)), + (Self::Dao, ForkCondition::Block(1920000)), + (Self::Tangerine, ForkCondition::Block(2463000)), + (Self::SpuriousDragon, ForkCondition::Block(2675000)), + (Self::Byzantium, ForkCondition::Block(4370000)), + (Self::Constantinople, ForkCondition::Block(7280000)), + (Self::Petersburg, ForkCondition::Block(7280000)), + (Self::Istanbul, ForkCondition::Block(9069000)), + (Self::MuirGlacier, ForkCondition::Block(9200000)), + (Self::Berlin, ForkCondition::Block(12244000)), + (Self::London, ForkCondition::Block(12965000)), + (Self::ArrowGlacier, ForkCondition::Block(13773000)), + (Self::GrayGlacier, ForkCondition::Block(15050000)), + ( + Self::Paris, + ForkCondition::TTD { + fork_block: None, + total_difficulty: uint!(58_750_000_000_000_000_000_000_U256), + }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1681338455)), + (Self::Cancun, ForkCondition::Timestamp(1710338135)), + ] + } + + /// Ethereum goerli list of hardforks. + pub const fn goerli() -> [(Self, ForkCondition); 14] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(1561651)), + (Self::Berlin, ForkCondition::Block(4460644)), + (Self::London, ForkCondition::Block(5062605)), + ( + Self::Paris, + ForkCondition::TTD { fork_block: None, total_difficulty: uint!(10_790_000_U256) }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1678832736)), + (Self::Cancun, ForkCondition::Timestamp(1705473120)), + ] + } + + /// Ethereum sepolia list of hardforks. + pub const fn sepolia() -> [(Self, ForkCondition); 15] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(0)), + (Self::MuirGlacier, ForkCondition::Block(0)), + (Self::Berlin, ForkCondition::Block(0)), + (Self::London, ForkCondition::Block(0)), + ( + Self::Paris, + ForkCondition::TTD { + fork_block: Some(1735371), + total_difficulty: uint!(17_000_000_000_000_000_U256), + }, + ), + (Self::Shanghai, ForkCondition::Timestamp(1677557088)), + (Self::Cancun, ForkCondition::Timestamp(1706655072)), + ] + } + + /// Ethereum holesky list of hardforks. + pub const fn holesky() -> [(Self, ForkCondition); 15] { + [ + (Self::Frontier, ForkCondition::Block(0)), + (Self::Homestead, ForkCondition::Block(0)), + (Self::Dao, ForkCondition::Block(0)), + (Self::Tangerine, ForkCondition::Block(0)), + (Self::SpuriousDragon, ForkCondition::Block(0)), + (Self::Byzantium, ForkCondition::Block(0)), + (Self::Constantinople, ForkCondition::Block(0)), + (Self::Petersburg, ForkCondition::Block(0)), + (Self::Istanbul, ForkCondition::Block(0)), + (Self::MuirGlacier, ForkCondition::Block(0)), + (Self::Berlin, ForkCondition::Block(0)), + (Self::London, ForkCondition::Block(0)), + (Self::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }), + (Self::Shanghai, ForkCondition::Timestamp(1696000704)), + (Self::Cancun, ForkCondition::Timestamp(1707305664)), + ] + } +} + +impl From<[(EthereumHardfork, ForkCondition); N]> for ChainHardforks { + fn from(list: [(EthereumHardfork, ForkCondition); N]) -> Self { + Self::new( + list.into_iter() + .map(|(fork, cond)| (Box::new(fork) as Box, cond)) + .collect(), + ) + } +} diff --git a/crates/ethereum-forks/src/hardfork/macros.rs b/crates/ethereum-forks/src/hardfork/macros.rs new file mode 100644 index 000000000000..780c15f6e6b9 --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/macros.rs @@ -0,0 +1,52 @@ +/// Macro that defines different variants of a chain specific enum. See [`crate::Hardfork`] as an +/// example. +#[macro_export] +macro_rules! hardfork { + ($(#[$enum_meta:meta])* $enum:ident { $( $(#[$meta:meta])* $variant:ident ),* $(,)? }) => { + $(#[$enum_meta])* + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] + pub enum $enum { + $( $(#[$meta])* $variant ),* + } + + impl $enum { + /// Returns variant as `str`. + pub const fn name(&self) -> &'static str { + match self { + $( $enum::$variant => stringify!($variant), )* + } + } + + /// Boxes `self` and returns it as `Box`. + pub fn boxed(self) -> Box { + Box::new(self) + } + } + + impl FromStr for $enum { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + $( + s if s == stringify!($variant).to_lowercase() => Ok($enum::$variant), + )* + _ => return Err(format!("Unknown hardfork: {s}")), + } + } + } + + impl Hardfork for $enum { + fn name(&self) -> &'static str { + self.name() + } + } + + impl Display for $enum { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{self:?}") + } + } + } +} diff --git a/crates/ethereum-forks/src/hardfork/mod.rs b/crates/ethereum-forks/src/hardfork/mod.rs new file mode 100644 index 000000000000..b6faef6ec2f0 --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/mod.rs @@ -0,0 +1,126 @@ +mod macros; + +mod ethereum; +pub use ethereum::EthereumHardfork; + +mod optimism; +pub use optimism::OptimismHardfork; + +mod dev; +pub use dev::DEV_HARDFORKS; + +use core::{ + any::Any, + hash::{Hash, Hasher}, +}; +use dyn_clone::DynClone; + +#[cfg(not(feature = "std"))] +use alloc::{format, string::String}; + +/// Generic hardfork trait. +#[auto_impl::auto_impl(&, Box)] +pub trait Hardfork: Any + DynClone + Send + Sync + 'static { + /// Fork name. + fn name(&self) -> &'static str; +} + +dyn_clone::clone_trait_object!(Hardfork); + +impl core::fmt::Debug for dyn Hardfork + 'static { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct(self.name()).finish() + } +} + +impl PartialEq for dyn Hardfork + 'static { + fn eq(&self, other: &Self) -> bool { + self.name() == other.name() + } +} + +impl Eq for dyn Hardfork + 'static {} + +impl Hash for dyn Hardfork + 'static { + fn hash(&self, state: &mut H) { + self.name().hash(state) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::hardfork::optimism::OptimismHardfork; + use std::str::FromStr; + + #[test] + fn check_hardfork_from_str() { + let hardfork_str = [ + "frOntier", + "homEstead", + "dao", + "tAngerIne", + "spurIousdrAgon", + "byzAntium", + "constantinople", + "petersburg", + "istanbul", + "muirglacier", + "bErlin", + "lonDon", + "arrowglacier", + "grayglacier", + "PARIS", + "ShAnGhAI", + "CaNcUn", + "PrAguE", + ]; + let expected_hardforks = [ + EthereumHardfork::Frontier, + EthereumHardfork::Homestead, + EthereumHardfork::Dao, + EthereumHardfork::Tangerine, + EthereumHardfork::SpuriousDragon, + EthereumHardfork::Byzantium, + EthereumHardfork::Constantinople, + EthereumHardfork::Petersburg, + EthereumHardfork::Istanbul, + EthereumHardfork::MuirGlacier, + EthereumHardfork::Berlin, + EthereumHardfork::London, + EthereumHardfork::ArrowGlacier, + EthereumHardfork::GrayGlacier, + EthereumHardfork::Paris, + EthereumHardfork::Shanghai, + EthereumHardfork::Cancun, + EthereumHardfork::Prague, + ]; + + let hardforks: Vec = + hardfork_str.iter().map(|h| EthereumHardfork::from_str(h).unwrap()).collect(); + + assert_eq!(hardforks, expected_hardforks); + } + + #[test] + fn check_op_hardfork_from_str() { + let hardfork_str = ["beDrOck", "rEgOlITH", "cAnYoN", "eCoToNe", "FJorD"]; + let expected_hardforks = [ + OptimismHardfork::Bedrock, + OptimismHardfork::Regolith, + OptimismHardfork::Canyon, + OptimismHardfork::Ecotone, + OptimismHardfork::Fjord, + ]; + + let hardforks: Vec = + hardfork_str.iter().map(|h| OptimismHardfork::from_str(h).unwrap()).collect(); + + assert_eq!(hardforks, expected_hardforks); + } + + #[test] + fn check_nonexistent_hardfork_from_str() { + assert!(EthereumHardfork::from_str("not a hardfork").is_err()); + } +} diff --git a/crates/ethereum-forks/src/hardfork/optimism.rs b/crates/ethereum-forks/src/hardfork/optimism.rs new file mode 100644 index 000000000000..6933b7feddae --- /dev/null +++ b/crates/ethereum-forks/src/hardfork/optimism.rs @@ -0,0 +1,337 @@ +use crate::{hardfork, ChainHardforks, EthereumHardfork, ForkCondition, Hardfork}; +use alloy_chains::Chain; +use alloy_primitives::U256; +use core::{ + any::Any, + fmt::{self, Display, Formatter}, + str::FromStr, +}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +hardfork!( + /// The name of an optimism hardfork. + /// + /// When building a list of hardforks for a chain, it's still expected to mix with [`EthereumHardfork`]. + OptimismHardfork { + /// Bedrock: . + Bedrock, + /// Regolith: . + Regolith, + /// . + Canyon, + /// Ecotone: . + Ecotone, + /// Fjord: + Fjord, + } +); + +impl OptimismHardfork { + /// Retrieves the activation block for the specified hardfork on the given chain. + pub fn activation_block(self, fork: H, chain: Chain) -> Option { + if chain == Chain::base_sepolia() { + return Self::base_sepolia_activation_block(fork) + } + if chain == Chain::base_mainnet() { + return Self::base_mainnet_activation_block(fork) + } + + None + } + + /// Retrieves the activation timestamp for the specified hardfork on the given chain. + pub fn activation_timestamp(self, fork: H, chain: Chain) -> Option { + if chain == Chain::base_sepolia() { + return Self::base_sepolia_activation_timestamp(fork) + } + if chain == Chain::base_mainnet() { + return Self::base_mainnet_activation_timestamp(fork) + } + + None + } + + /// Retrieves the activation block for the specified hardfork on the Base Sepolia testnet. + pub fn base_sepolia_activation_block(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(2106456), + EthereumHardfork::Cancun => Some(6383256), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(0), + Self::Canyon => Some(2106456), + Self::Ecotone => Some(6383256), + Self::Fjord => Some(10615056), + }, + ) + } + + /// Retrieves the activation block for the specified hardfork on the Base mainnet. + pub fn base_mainnet_activation_block(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(9101527), + EthereumHardfork::Cancun => Some(11188936), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(0), + Self::Canyon => Some(9101527), + Self::Ecotone => Some(11188936), + _ => None, + }, + ) + } + + /// Retrieves the activation timestamp for the specified hardfork on the Base Sepolia testnet. + pub fn base_sepolia_activation_timestamp(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(1699981200), + EthereumHardfork::Cancun => Some(1708534800), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(1695768288), + Self::Canyon => Some(1699981200), + Self::Ecotone => Some(1708534800), + Self::Fjord => Some(1716998400), + }, + ) + } + + /// Retrieves the activation timestamp for the specified hardfork on the Base mainnet. + pub fn base_mainnet_activation_timestamp(fork: H) -> Option { + match_hardfork( + fork, + |fork| match fork { + EthereumHardfork::Frontier | + EthereumHardfork::Homestead | + EthereumHardfork::Dao | + EthereumHardfork::Tangerine | + EthereumHardfork::SpuriousDragon | + EthereumHardfork::Byzantium | + EthereumHardfork::Constantinople | + EthereumHardfork::Petersburg | + EthereumHardfork::Istanbul | + EthereumHardfork::MuirGlacier | + EthereumHardfork::Berlin | + EthereumHardfork::London | + EthereumHardfork::ArrowGlacier | + EthereumHardfork::GrayGlacier | + EthereumHardfork::Paris | + EthereumHardfork::Shanghai => Some(1704992401), + EthereumHardfork::Cancun => Some(1710374401), + _ => None, + }, + |fork| match fork { + Self::Bedrock | Self::Regolith => Some(1686789347), + Self::Canyon => Some(1704992401), + Self::Ecotone => Some(1710374401), + Self::Fjord => Some(1720627201), + }, + ) + } + + /// Optimism mainnet list of hardforks. + pub fn op_mainnet() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(3950000)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(105235063)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(105235063)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(105235063)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(105235063), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(105235063)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1704992401)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1704992401)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1720627201)), + ]) + } + + /// Optimism sepolia list of hardforks. + pub fn op_sepolia() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1699981200)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1699981200)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1716998400)), + ]) + } + + /// Base sepolia list of hardforks. + pub fn base_sepolia() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1699981200)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1699981200)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1708534800)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1716998400)), + ]) + } + + /// Base mainnet list of hardforks. + pub fn base_mainnet() -> ChainHardforks { + ChainHardforks::new(vec![ + (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::ArrowGlacier.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)), + ( + EthereumHardfork::Paris.boxed(), + ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }, + ), + (Self::Bedrock.boxed(), ForkCondition::Block(0)), + (Self::Regolith.boxed(), ForkCondition::Timestamp(0)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(1704992401)), + (Self::Canyon.boxed(), ForkCondition::Timestamp(1704992401)), + (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Ecotone.boxed(), ForkCondition::Timestamp(1710374401)), + (Self::Fjord.boxed(), ForkCondition::Timestamp(1720627201)), + ]) + } +} + +/// Match helper method since it's not possible to match on `dyn Hardfork` +fn match_hardfork(fork: H, hardfork_fn: HF, optimism_hardfork_fn: OHF) -> Option +where + H: Hardfork, + HF: Fn(&EthereumHardfork) -> Option, + OHF: Fn(&OptimismHardfork) -> Option, +{ + let fork: &dyn Any = ⋔ + if let Some(fork) = fork.downcast_ref::() { + return hardfork_fn(fork) + } + fork.downcast_ref::().and_then(optimism_hardfork_fn) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_match_hardfork() { + assert_eq!( + OptimismHardfork::base_mainnet_activation_block(EthereumHardfork::Cancun), + Some(11188936) + ); + assert_eq!( + OptimismHardfork::base_mainnet_activation_block(OptimismHardfork::Canyon), + Some(9101527) + ); + } +} diff --git a/crates/ethereum-forks/src/hardforks/ethereum.rs b/crates/ethereum-forks/src/hardforks/ethereum.rs new file mode 100644 index 000000000000..3b4c860ad394 --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/ethereum.rs @@ -0,0 +1,56 @@ +use crate::{ + hardforks::{ChainHardforks, Hardforks}, + EthereumHardfork, ForkCondition, +}; + +/// Helper methods for Ethereum forks. +pub trait EthereumHardforks: Hardforks { + /// Convenience method to check if [`EthereumHardfork::Shanghai`] is active at a given + /// timestamp. + fn is_shanghai_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Shanghai, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Cancun`] is active at a given timestamp. + fn is_cancun_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Cancun, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Prague`] is active at a given timestamp. + fn is_prague_active_at_timestamp(&self, timestamp: u64) -> bool { + self.is_fork_active_at_timestamp(EthereumHardfork::Prague, timestamp) + } + + /// Convenience method to check if [`EthereumHardfork::Byzantium`] is active at a given block + /// number. + fn is_byzantium_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::Byzantium).active_at_block(block_number) + } + + /// Convenience method to check if [`EthereumHardfork::SpuriousDragon`] is active at a given + /// block number. + fn is_spurious_dragon_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::SpuriousDragon).active_at_block(block_number) + } + + /// Convenience method to check if [`EthereumHardfork::Homestead`] is active at a given block + /// number. + fn is_homestead_active_at_block(&self, block_number: u64) -> bool { + self.fork(EthereumHardfork::Homestead).active_at_block(block_number) + } + + /// The Paris hardfork (merge) is activated via block number. If we have knowledge of the block, + /// this function will return true if the block number is greater than or equal to the Paris + /// (merge) block. + fn is_paris_active_at_block(&self, block_number: u64) -> Option { + match self.fork(EthereumHardfork::Paris) { + ForkCondition::Block(paris_block) => Some(block_number >= paris_block), + ForkCondition::TTD { fork_block, .. } => { + fork_block.map(|paris_block| block_number >= paris_block) + } + _ => None, + } + } +} + +impl EthereumHardforks for ChainHardforks {} diff --git a/crates/ethereum-forks/src/hardforks/mod.rs b/crates/ethereum-forks/src/hardforks/mod.rs new file mode 100644 index 000000000000..121a189e0152 --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/mod.rs @@ -0,0 +1,131 @@ +/// Ethereum helper methods +mod ethereum; +pub use ethereum::EthereumHardforks; + +/// Optimism helper methods +mod optimism; +pub use optimism::OptimismHardforks; + +use crate::{ForkCondition, Hardfork}; +use rustc_hash::FxHashMap; + +/// Generic trait over a set of ordered hardforks +pub trait Hardforks: Default + Clone { + /// Retrieves [`ForkCondition`] from `fork`. If `fork` is not present, returns + /// [`ForkCondition::Never`]. + fn fork(&self, fork: H) -> ForkCondition; + + /// Get an iterator of all hardforks with their respective activation conditions. + fn forks_iter(&self) -> impl Iterator; + + /// Convenience method to check if a fork is active at a given timestamp. + fn is_fork_active_at_timestamp(&self, fork: H, timestamp: u64) -> bool { + self.fork(fork).active_at_timestamp(timestamp) + } + + /// Convenience method to check if a fork is active at a given block number. + fn is_fork_active_at_block(&self, fork: H, block_number: u64) -> bool { + self.fork(fork).active_at_block(block_number) + } +} + +/// Ordered list of a chain hardforks that implement [`Hardfork`]. +#[derive(Default, Clone, PartialEq, Eq)] +pub struct ChainHardforks { + forks: Vec<(Box, ForkCondition)>, + map: FxHashMap<&'static str, ForkCondition>, +} + +impl ChainHardforks { + /// Creates a new [`ChainHardforks`] from a list which **must be ordered** by activation. + /// + /// Equivalent Ethereum hardforks **must be included** as well. + pub fn new(forks: Vec<(Box, ForkCondition)>) -> Self { + let map = forks.iter().map(|(fork, condition)| (fork.name(), *condition)).collect(); + + Self { forks, map } + } + + /// Total number of hardforks. + pub fn len(&self) -> usize { + self.forks.len() + } + + /// Checks if the fork list is empty. + pub fn is_empty(&self) -> bool { + self.forks.is_empty() + } + + /// Retrieves [`ForkCondition`] from `fork`. If `fork` is not present, returns + /// [`ForkCondition::Never`]. + pub fn fork(&self, fork: H) -> ForkCondition { + self.get(fork).unwrap_or(ForkCondition::Never) + } + + /// Retrieves [`ForkCondition`] from `fork` if it exists, otherwise `None`. + pub fn get(&self, fork: H) -> Option { + self.map.get(fork.name()).copied() + } + + /// Get an iterator of all hardforks with their respective activation conditions. + pub fn forks_iter(&self) -> impl Iterator { + self.forks.iter().map(|(f, b)| (&**f, *b)) + } + + /// Get last hardfork from the list. + pub fn last(&self) -> Option<(Box, ForkCondition)> { + self.forks.last().map(|(f, b)| (f.clone(), *b)) + } + + /// Convenience method to check if a fork is active at a given timestamp. + pub fn is_fork_active_at_timestamp(&self, fork: H, timestamp: u64) -> bool { + self.fork(fork).active_at_timestamp(timestamp) + } + + /// Convenience method to check if a fork is active at a given block number. + pub fn is_fork_active_at_block(&self, fork: H, block_number: u64) -> bool { + self.fork(fork).active_at_block(block_number) + } + + /// Inserts `fork` into list, updating with a new [`ForkCondition`] if it already exists. + pub fn insert(&mut self, fork: H, condition: ForkCondition) { + match self.map.entry(fork.name()) { + std::collections::hash_map::Entry::Occupied(mut entry) => { + *entry.get_mut() = condition; + if let Some((_, inner)) = + self.forks.iter_mut().find(|(inner, _)| inner.name() == fork.name()) + { + *inner = condition; + } + } + std::collections::hash_map::Entry::Vacant(entry) => { + entry.insert(condition); + self.forks.push((Box::new(fork), condition)); + } + } + } + + /// Removes `fork` from list. + pub fn remove(&mut self, fork: H) { + self.forks.retain(|(inner_fork, _)| inner_fork.name() != fork.name()); + self.map.remove(fork.name()); + } +} + +impl Hardforks for ChainHardforks { + fn fork(&self, fork: H) -> ForkCondition { + self.fork(fork) + } + + fn forks_iter(&self) -> impl Iterator { + self.forks_iter() + } +} + +impl core::fmt::Debug for ChainHardforks { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ChainHardforks") + .field("0", &self.forks_iter().map(|(hf, cond)| (hf.name(), cond)).collect::>()) + .finish() + } +} diff --git a/crates/ethereum-forks/src/hardforks/optimism.rs b/crates/ethereum-forks/src/hardforks/optimism.rs new file mode 100644 index 000000000000..39b2bf4ab454 --- /dev/null +++ b/crates/ethereum-forks/src/hardforks/optimism.rs @@ -0,0 +1,12 @@ +use crate::{ChainHardforks, EthereumHardforks, OptimismHardfork}; + +/// Extends [`crate::EthereumHardforks`] with optimism helper methods. +pub trait OptimismHardforks: EthereumHardforks { + /// Convenience method to check if [`OptimismHardfork::Bedrock`] is active at a given block + /// number. + fn is_bedrock_active_at_block(&self, block_number: u64) -> bool { + self.fork(OptimismHardfork::Bedrock).active_at_block(block_number) + } +} + +impl OptimismHardforks for ChainHardforks {} diff --git a/crates/ethereum-forks/src/lib.rs b/crates/ethereum-forks/src/lib.rs index 1a7e0f56e707..51e619f4db0d 100644 --- a/crates/ethereum-forks/src/lib.rs +++ b/crates/ethereum-forks/src/lib.rs @@ -12,8 +12,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] @@ -24,19 +22,18 @@ mod display; mod forkcondition; mod forkid; mod hardfork; +mod hardforks; mod head; pub use forkid::{ EnrForkIdEntry, ForkFilter, ForkFilterKey, ForkHash, ForkId, ForkTransition, ValidationError, }; -pub use hardfork::Hardfork; +pub use hardfork::{EthereumHardfork, Hardfork, OptimismHardfork, DEV_HARDFORKS}; pub use head::Head; pub use display::DisplayHardforks; pub use forkcondition::ForkCondition; - -/// Chains hardforks -pub mod chains; +pub use hardforks::*; #[cfg(any(test, feature = "arbitrary"))] pub use arbitrary; diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index 210f54461394..2027fd539c1f 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -8,7 +8,7 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use reth_chainspec::{Chain, ChainSpec, Hardfork}; +use reth_chainspec::{Chain, ChainSpec, EthereumHardfork, EthereumHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ validate_4844_header_standalone, validate_against_parent_4844, @@ -51,7 +51,7 @@ impl EthBeaconConsensus { ) -> Result<(), ConsensusError> { // Determine the parent gas limit, considering elasticity multiplier on the London fork. let parent_gas_limit = - if self.chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + if self.chain_spec.fork(EthereumHardfork::London).transitions_at_block(header.number) { parent.gas_limit * self.chain_spec .base_fee_params_at_timestamp(header.timestamp) @@ -153,7 +153,7 @@ impl Consensus for EthBeaconConsensus { ) -> Result<(), ConsensusError> { let is_post_merge = self .chain_spec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .active_at_ttd(total_difficulty, header.difficulty); if is_post_merge { diff --git a/crates/ethereum/consensus/src/validation.rs b/crates/ethereum/consensus/src/validation.rs index 1566ec176215..fafd0ee4217b 100644 --- a/crates/ethereum/consensus/src/validation.rs +++ b/crates/ethereum/consensus/src/validation.rs @@ -1,4 +1,4 @@ -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ gas_spent_by_transactions, BlockWithSenders, Bloom, GotExpected, Receipt, Request, B256, diff --git a/crates/ethereum/engine-primitives/Cargo.toml b/crates/ethereum/engine-primitives/Cargo.toml index 231c7f640b39..8a1f25808937 100644 --- a/crates/ethereum/engine-primitives/Cargo.toml +++ b/crates/ethereum/engine-primitives/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # reth reth-chainspec.workspace = true +reth-evm-ethereum.workspace = true reth-primitives.workspace = true reth-engine-primitives.workspace = true reth-payload-primitives.workspace = true diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index 8976f0caa5af..f9fde7028e32 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -2,10 +2,11 @@ use alloy_rlp::Encodable; use reth_chainspec::ChainSpec; +use reth_evm_ethereum::revm_spec_by_timestamp_after_merge; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ - constants::EIP1559_INITIAL_BASE_FEE, revm::config::revm_spec_by_timestamp_after_merge, Address, - BlobTransactionSidecar, Hardfork, Header, SealedBlock, Withdrawals, B256, U256, + constants::EIP1559_INITIAL_BASE_FEE, Address, BlobTransactionSidecar, EthereumHardfork, Header, + SealedBlock, Withdrawals, B256, U256, }; use reth_rpc_types::engine::{ ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, ExecutionPayloadEnvelopeV4, @@ -266,7 +267,7 @@ impl PayloadBuilderAttributes for EthPayloadBuilderAttributes { // If we are on the London fork boundary, we need to multiply the parent's gas limit by the // elasticity multiplier to get the new gas limit. - if chain_spec.fork(Hardfork::London).transitions_at_block(parent.number + 1) { + if chain_spec.fork(EthereumHardfork::London).transitions_at_block(parent.number + 1) { let elasticity_multiplier = chain_spec.base_fee_params_at_timestamp(self.timestamp()).elasticity_multiplier; diff --git a/crates/ethereum/evm/Cargo.toml b/crates/ethereum/evm/Cargo.toml index 1d996e5d3995..7ea2e4b587c9 100644 --- a/crates/ethereum/evm/Cargo.toml +++ b/crates/ethereum/evm/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # Reth reth-chainspec.workspace = true +reth-ethereum-forks.workspace = true reth-evm.workspace = true reth-primitives.workspace = true reth-revm.workspace = true diff --git a/crates/ethereum/evm/src/config.rs b/crates/ethereum/evm/src/config.rs new file mode 100644 index 000000000000..77082b1f7d60 --- /dev/null +++ b/crates/ethereum/evm/src/config.rs @@ -0,0 +1,220 @@ +use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_ethereum_forks::{EthereumHardfork, Head}; + +/// Returns the spec id at the given timestamp. +/// +/// Note: This is only intended to be used after the merge, when hardforks are activated by +/// timestamp. +pub fn revm_spec_by_timestamp_after_merge( + chain_spec: &ChainSpec, + timestamp: u64, +) -> revm_primitives::SpecId { + if chain_spec.is_prague_active_at_timestamp(timestamp) { + revm_primitives::PRAGUE + } else if chain_spec.is_cancun_active_at_timestamp(timestamp) { + revm_primitives::CANCUN + } else if chain_spec.is_shanghai_active_at_timestamp(timestamp) { + revm_primitives::SHANGHAI + } else { + revm_primitives::MERGE + } +} + +/// return `revm_spec` from spec configuration. +pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId { + if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { + revm_primitives::PRAGUE + } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(block) { + revm_primitives::CANCUN + } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) { + revm_primitives::SHANGHAI + } else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(block) { + revm_primitives::MERGE + } else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) { + revm_primitives::LONDON + } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(block) { + revm_primitives::BERLIN + } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(block) { + revm_primitives::ISTANBUL + } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(block) { + revm_primitives::PETERSBURG + } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(block) { + revm_primitives::BYZANTIUM + } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(block) { + revm_primitives::SPURIOUS_DRAGON + } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(block) { + revm_primitives::TANGERINE + } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(block) { + revm_primitives::HOMESTEAD + } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(block) { + revm_primitives::FRONTIER + } else { + panic!( + "invalid hardfork chainspec: expected at least one hardfork, got {:?}", + chain_spec.hardforks + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::U256; + use reth_chainspec::{ChainSpecBuilder, MAINNET}; + + #[test] + fn test_revm_spec_by_timestamp_after_merge() { + assert_eq!( + revm_spec_by_timestamp_after_merge( + &ChainSpecBuilder::mainnet().cancun_activated().build(), + 0 + ), + revm_primitives::CANCUN + ); + assert_eq!( + revm_spec_by_timestamp_after_merge( + &ChainSpecBuilder::mainnet().shanghai_activated().build(), + 0 + ), + revm_primitives::SHANGHAI + ); + assert_eq!( + revm_spec_by_timestamp_after_merge(&ChainSpecBuilder::mainnet().build(), 0), + revm_primitives::MERGE + ); + } + + #[test] + fn test_to_revm_spec() { + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), &Head::default()), + revm_primitives::CANCUN + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().shanghai_activated().build(), &Head::default()), + revm_primitives::SHANGHAI + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), &Head::default()), + revm_primitives::MERGE + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), &Head::default()), + revm_primitives::LONDON + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), &Head::default()), + revm_primitives::BERLIN + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), &Head::default()), + revm_primitives::ISTANBUL + ); + assert_eq!( + revm_spec( + &ChainSpecBuilder::mainnet().petersburg_activated().build(), + &Head::default() + ), + revm_primitives::PETERSBURG + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), &Head::default()), + revm_primitives::BYZANTIUM + ); + assert_eq!( + revm_spec( + &ChainSpecBuilder::mainnet().spurious_dragon_activated().build(), + &Head::default() + ), + revm_primitives::SPURIOUS_DRAGON + ); + assert_eq!( + revm_spec( + &ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(), + &Head::default() + ), + revm_primitives::TANGERINE + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), &Head::default()), + revm_primitives::HOMESTEAD + ); + assert_eq!( + revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), &Head::default()), + revm_primitives::FRONTIER + ); + } + + #[test] + fn test_eth_spec() { + assert_eq!( + revm_spec(&MAINNET, &Head { timestamp: 1710338135, ..Default::default() }), + revm_primitives::CANCUN + ); + assert_eq!( + revm_spec(&MAINNET, &Head { timestamp: 1681338455, ..Default::default() }), + revm_primitives::SHANGHAI + ); + + assert_eq!( + revm_spec( + &MAINNET, + &Head { + total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128), + difficulty: U256::from(10_u128), + ..Default::default() + } + ), + revm_primitives::MERGE + ); + // TTD trumps the block number + assert_eq!( + revm_spec( + &MAINNET, + &Head { + number: 15537394 - 10, + total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128), + difficulty: U256::from(10_u128), + ..Default::default() + } + ), + revm_primitives::MERGE + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 15537394 - 10, ..Default::default() }), + revm_primitives::LONDON + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 12244000 + 10, ..Default::default() }), + revm_primitives::BERLIN + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 12244000 - 10, ..Default::default() }), + revm_primitives::ISTANBUL + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 7280000 + 10, ..Default::default() }), + revm_primitives::PETERSBURG + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 7280000 - 10, ..Default::default() }), + revm_primitives::BYZANTIUM + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 2675000 + 10, ..Default::default() }), + revm_primitives::SPURIOUS_DRAGON + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 2675000 - 10, ..Default::default() }), + revm_primitives::TANGERINE + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 1150000 + 10, ..Default::default() }), + revm_primitives::HOMESTEAD + ); + assert_eq!( + revm_spec(&MAINNET, &Head { number: 1150000 - 10, ..Default::default() }), + revm_primitives::FRONTIER + ); + } +} diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 149fbc9557b9..76ec292396df 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -4,7 +4,7 @@ use crate::{ dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, EthEvmConfig, }; -use reth_chainspec::{ChainSpec, MAINNET}; +use reth_chainspec::{ChainSpec, EthereumHardforks, MAINNET}; use reth_ethereum_consensus::validate_block_post_execution; use reth_evm::{ execute::{ @@ -15,7 +15,7 @@ use reth_evm::{ }; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - BlockNumber, BlockWithSenders, Hardfork, Header, Receipt, Request, Withdrawals, U256, + BlockNumber, BlockWithSenders, EthereumHardfork, Header, Receipt, Request, U256, }; use reth_prune_types::PruneModes; use reth_revm::{ @@ -29,15 +29,11 @@ use reth_revm::{ }; use revm_primitives::{ db::{Database, DatabaseCommit}, - BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, + BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, ResultAndState, }; -#[cfg(not(feature = "std"))] -use alloc::{sync::Arc, vec, vec::Vec}; - #[cfg(feature = "std")] -use std::sync::Arc; - +use std::{fmt::Display, sync::Arc, vec, vec::Vec}; /// Provides executors to execute regular ethereum blocks #[derive(Debug, Clone)] pub struct EthExecutorProvider { @@ -70,7 +66,7 @@ where { fn eth_executor(&self, db: DB) -> EthBlockExecutor where - DB: Database, + DB: Database>, { EthBlockExecutor::new( self.chain_spec.clone(), @@ -84,20 +80,22 @@ impl BlockExecutorProvider for EthExecutorProvider where EvmConfig: ConfigureEvm, { - type Executor> = EthBlockExecutor; + type Executor + Display>> = + EthBlockExecutor; - type BatchExecutor> = EthBatchExecutor; + type BatchExecutor + Display>> = + EthBatchExecutor; fn executor(&self, db: DB) -> Self::Executor where - DB: Database, + DB: Database + Display>, { self.eth_executor(db) } fn batch_executor(&self, db: DB, prune_modes: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + Display>, { let executor = self.eth_executor(db); EthBatchExecutor { @@ -145,7 +143,8 @@ where mut evm: Evm<'_, Ext, &mut State>, ) -> Result where - DB: Database, + DB: Database, + DB::Error: Into + std::fmt::Display, { // apply pre execution changes apply_beacon_root_contract_call( @@ -178,14 +177,21 @@ where .into()) } - EvmConfig::fill_tx_env(evm.tx_mut(), transaction, *sender); + self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); // Execute transaction. let ResultAndState { result, state } = evm.transact().map_err(move |err| { + let new_err = match err { + EVMError::Transaction(e) => EVMError::Transaction(e), + EVMError::Header(e) => EVMError::Header(e), + EVMError::Database(e) => EVMError::Database(e.into()), + EVMError::Custom(e) => EVMError::Custom(e), + EVMError::Precompile(e) => EVMError::Precompile(e), + }; // Ensure hash is calculated for error log, if not already done BlockValidationError::EVM { hash: transaction.recalculate_hash(), - error: err.into(), + error: Box::new(new_err), } })?; evm.db_mut().commit(state); @@ -260,7 +266,7 @@ impl EthBlockExecutor { impl EthBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + Display>, { /// Configures a new evm configuration and block environment for the given block. /// @@ -322,19 +328,11 @@ where block: &BlockWithSenders, total_difficulty: U256, ) -> Result<(), BlockExecutionError> { - let mut balance_increments = post_block_balance_increments( - self.chain_spec(), - block.number, - block.difficulty, - block.beneficiary, - block.timestamp, - total_difficulty, - &block.ommers, - block.withdrawals.as_ref().map(Withdrawals::as_ref), - ); + let mut balance_increments = + post_block_balance_increments(self.chain_spec(), block, total_difficulty); // Irregular state change at Ethereum DAO hardfork - if self.chain_spec().fork(Hardfork::Dao).transitions_at_block(block.number) { + if self.chain_spec().fork(EthereumHardfork::Dao).transitions_at_block(block.number) { // drain balances from hardcoded addresses. let drained_balance: u128 = self .state @@ -358,7 +356,7 @@ where impl Executor for EthBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + std::fmt::Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput; @@ -408,7 +406,7 @@ impl EthBatchExecutor { impl BatchExecutor for EthBatchExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; @@ -531,7 +529,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -628,7 +626,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -671,7 +669,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -724,7 +722,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(0)) .build(), ); @@ -811,7 +809,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Cancun, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Cancun, ForkCondition::Timestamp(1)) .build(), ); @@ -881,7 +879,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Never) + .with_fork(EthereumHardfork::Prague, ForkCondition::Never) .build(), ); @@ -934,7 +932,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -986,7 +984,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); @@ -1049,7 +1047,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(1)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(1)) .build(), ); @@ -1108,7 +1106,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -1245,7 +1243,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); @@ -1326,7 +1324,7 @@ mod tests { let chain_spec = Arc::new( ChainSpecBuilder::from(&*MAINNET) .shanghai_activated() - .with_fork(Hardfork::Prague, ForkCondition::Timestamp(0)) + .with_fork(EthereumHardfork::Prague, ForkCondition::Timestamp(0)) .build(), ); diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index 4134849ea8f9..17c0c7370b35 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -12,14 +12,14 @@ #[cfg(not(feature = "std"))] extern crate alloc; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, Head}; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; -use reth_primitives::{ - revm::{config::revm_spec, env::fill_tx_env}, - revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, - Address, Head, Header, TransactionSigned, U256, -}; +use reth_primitives::{Header, U256}; use reth_revm::{Database, EvmBuilder}; +use revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg}; + +mod config; +pub use config::{revm_spec, revm_spec_by_timestamp_after_merge}; pub mod execute; @@ -35,19 +35,15 @@ pub mod eip6110; pub struct EthEvmConfig; impl ConfigureEvmEnv for EthEvmConfig { - fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { - fill_tx_env(tx_env, transaction, sender) - } - fn fill_cfg_env( cfg_env: &mut CfgEnvWithHandlerCfg, chain_spec: &ChainSpec, header: &Header, total_difficulty: U256, ) { - let spec_id = revm_spec( + let spec_id = config::revm_spec( chain_spec, - Head { + &Head { number: header.number, timestamp: header.timestamp, difficulty: header.difficulty, @@ -77,7 +73,12 @@ impl ConfigureEvm for EthEvmConfig { #[cfg(test)] mod tests { use super::*; - use reth_primitives::revm_primitives::{BlockEnv, CfgEnv, SpecId}; + use reth_chainspec::ChainSpec; + use reth_primitives::{ + revm_primitives::{BlockEnv, CfgEnv, SpecId}, + Header, U256, + }; + use revm_primitives::CfgEnvWithHandlerCfg; #[test] #[ignore] diff --git a/crates/ethereum/node/tests/e2e/dev.rs b/crates/ethereum/node/tests/e2e/dev.rs index 990c6f0bf2b0..2b20d781f7c5 100644 --- a/crates/ethereum/node/tests/e2e/dev.rs +++ b/crates/ethereum/node/tests/e2e/dev.rs @@ -1,12 +1,14 @@ -use crate::utils::EthNode; +use std::sync::Arc; + use alloy_genesis::Genesis; use alloy_primitives::{b256, hex}; use futures::StreamExt; -use reth::rpc::eth::EthTransactions; +use reth::rpc::api::eth::helpers::EthTransactions; use reth_chainspec::ChainSpec; use reth_e2e_test_utils::setup; use reth_provider::CanonStateSubscriptions; -use std::sync::Arc; + +use crate::utils::EthNode; #[tokio::test] async fn can_run_dev_node() -> eyre::Result<()> { diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 1e53180d99bb..43a00fb98cff 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -28,7 +28,8 @@ use reth_primitives::{ eip4844::calculate_excess_blob_gas, proofs::{self, calculate_requests_root}, revm::env::tx_env_with_recovered, - Block, Header, IntoRecoveredTransaction, Receipt, EMPTY_OMMER_ROOT_HASH, U256, + Block, EthereumHardforks, Header, IntoRecoveredTransaction, Receipt, EMPTY_OMMER_ROOT_HASH, + U256, }; use reth_provider::StateProviderFactory; use reth_revm::{database::StateProviderDatabase, state_change::apply_blockhashes_update}; diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 8833615bbc38..8ccf0f480e9d 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -94,6 +94,11 @@ impl Chain { &self.execution_outcome } + /// Get mutable execution outcome of this chain + pub fn execution_outcome_mut(&mut self) -> &mut ExecutionOutcome { + &mut self.execution_outcome + } + /// Prepends the given state to the current state. pub fn prepend_state(&mut self, state: BundleState) { self.execution_outcome.prepend_state(state); diff --git a/crates/evm/src/either.rs b/crates/evm/src/either.rs index 2c8edfd29265..2f55f1668923 100644 --- a/crates/evm/src/either.rs +++ b/crates/evm/src/either.rs @@ -1,5 +1,7 @@ //! Helper type that represents one of two possible executor types +use std::fmt::Display; + use crate::execute::{ BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor, }; @@ -18,13 +20,15 @@ where A: BlockExecutorProvider, B: BlockExecutorProvider, { - type Executor> = Either, B::Executor>; - type BatchExecutor> = + type Executor + Display>> = + Either, B::Executor>; + + type BatchExecutor + Display>> = Either, B::BatchExecutor>; fn executor(&self, db: DB) -> Self::Executor where - DB: Database, + DB: Database + Display>, { match self { Self::Left(a) => Either::Left(a.executor(db)), @@ -34,7 +38,7 @@ where fn batch_executor(&self, db: DB, prune_modes: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + Display>, { match self { Self::Left(a) => Either::Left(a.batch_executor(db, prune_modes)), @@ -57,7 +61,7 @@ where Output = BlockExecutionOutput, Error = BlockExecutionError, >, - DB: Database, + DB: Database + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput; @@ -85,7 +89,7 @@ where Output = ExecutionOutcome, Error = BlockExecutionError, >, - DB: Database, + DB: Database + Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; diff --git a/crates/evm/src/execute.rs b/crates/evm/src/execute.rs index ea8b7abb0779..6d076fd45303 100644 --- a/crates/evm/src/execute.rs +++ b/crates/evm/src/execute.rs @@ -5,6 +5,7 @@ use reth_primitives::{BlockNumber, BlockWithSenders, Receipt, Request, U256}; use reth_prune_types::PruneModes; use revm::db::BundleState; use revm_primitives::db::Database; +use std::fmt::Display; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -142,7 +143,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// /// It is not expected to validate the state trie root, this must be done by the caller using /// the returned state. - type Executor>: for<'a> Executor< + type Executor + Display>>: for<'a> Executor< DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = BlockExecutionOutput, @@ -150,7 +151,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { >; /// An executor that can execute a batch of blocks given a database. - type BatchExecutor>: for<'a> BatchExecutor< + type BatchExecutor + Display>>: for<'a> BatchExecutor< DB, Input<'a> = BlockExecutionInput<'a, BlockWithSenders>, Output = ExecutionOutcome, @@ -162,7 +163,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// This is used to execute a single block and get the changed state. fn executor(&self, db: DB) -> Self::Executor where - DB: Database; + DB: Database + Display>; /// Creates a new batch executor with the given database and pruning modes. /// @@ -173,7 +174,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static { /// execution. fn batch_executor(&self, db: DB, prune_modes: PruneModes) -> Self::BatchExecutor where - DB: Database; + DB: Database + Display>; } #[cfg(test)] @@ -187,19 +188,19 @@ mod tests { struct TestExecutorProvider; impl BlockExecutorProvider for TestExecutorProvider { - type Executor> = TestExecutor; - type BatchExecutor> = TestExecutor; + type Executor + Display>> = TestExecutor; + type BatchExecutor + Display>> = TestExecutor; fn executor(&self, _db: DB) -> Self::Executor where - DB: Database, + DB: Database + Display>, { TestExecutor(PhantomData) } fn batch_executor(&self, _db: DB, _prune_modes: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + Display>, { TestExecutor(PhantomData) } diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index a3e643e88b4c..20d2f67ed6f2 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -12,8 +12,13 @@ #[cfg(not(feature = "std"))] extern crate alloc; +use core::ops::Deref; + use reth_chainspec::ChainSpec; -use reth_primitives::{revm::env::fill_block_env, Address, Header, TransactionSigned, U256}; +use reth_primitives::{ + revm::env::{fill_block_env, fill_tx_env}, + Address, Header, TransactionSigned, TransactionSignedEcRecovered, U256, +}; use revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, SpecId, TxEnv}; @@ -27,6 +32,7 @@ pub mod provider; pub mod test_utils; /// Trait for configuring the EVM for executing full blocks. +#[auto_impl::auto_impl(&, Arc)] pub trait ConfigureEvm: ConfigureEvmEnv { /// Associated type for the default external context that should be configured for the EVM. type DefaultExternalContext<'a>; @@ -98,9 +104,21 @@ pub trait ConfigureEvm: ConfigureEvmEnv { /// This represents the set of methods used to configure the EVM's environment before block /// execution. +/// +/// Default trait method implementation is done w.r.t. L1. +#[auto_impl::auto_impl(&, Arc)] pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static { + /// Returns a [`TxEnv`] from a [`TransactionSignedEcRecovered`]. + fn tx_env(&self, transaction: &TransactionSignedEcRecovered) -> TxEnv { + let mut tx_env = TxEnv::default(); + self.fill_tx_env(&mut tx_env, transaction.deref(), transaction.signer()); + tx_env + } + /// Fill transaction environment from a [`TransactionSigned`] and the given sender address. - fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address); + fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { + fill_tx_env(tx_env, transaction, sender) + } /// Fill [`CfgEnvWithHandlerCfg`] fields according to the chain spec and given header fn fill_cfg_env( diff --git a/crates/evm/src/noop.rs b/crates/evm/src/noop.rs index fdee35239369..d393f66d566d 100644 --- a/crates/evm/src/noop.rs +++ b/crates/evm/src/noop.rs @@ -1,5 +1,7 @@ //! A no operation block executor implementation. +use std::fmt::Display; + use reth_execution_errors::BlockExecutionError; use reth_execution_types::ExecutionOutcome; use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; @@ -19,20 +21,20 @@ const UNAVAILABLE_FOR_NOOP: &str = "execution unavailable for noop"; pub struct NoopBlockExecutorProvider; impl BlockExecutorProvider for NoopBlockExecutorProvider { - type Executor> = Self; + type Executor + Display>> = Self; - type BatchExecutor> = Self; + type BatchExecutor + Display>> = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database, + DB: Database + Display>, { Self } fn batch_executor(&self, _: DB, _: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + Display>, { Self } diff --git a/crates/evm/src/provider.rs b/crates/evm/src/provider.rs index abf04be8938c..2e73ff2fa985 100644 --- a/crates/evm/src/provider.rs +++ b/crates/evm/src/provider.rs @@ -6,13 +6,13 @@ use reth_storage_errors::provider::ProviderResult; use revm::primitives::{BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}; /// A provider type that knows chain specific information required to configure a -/// [CfgEnvWithHandlerCfg]. +/// [`CfgEnvWithHandlerCfg`]. /// /// This type is mainly used to provide required data to configure the EVM environment that is /// usually stored on disk. #[auto_impl::auto_impl(&, Arc)] pub trait EvmEnvProvider: Send + Sync { - /// Fills the [CfgEnvWithHandlerCfg] and [BlockEnv] fields with values specific to the given + /// Fills the [`CfgEnvWithHandlerCfg`] and [BlockEnv] fields with values specific to the given /// [BlockHashOrNumber]. fn fill_env_at( &self, @@ -24,7 +24,7 @@ pub trait EvmEnvProvider: Send + Sync { where EvmConfig: ConfigureEvmEnv; - /// Fills the default [CfgEnvWithHandlerCfg] and [BlockEnv] fields with values specific to the + /// Fills the default [`CfgEnvWithHandlerCfg`] and [BlockEnv] fields with values specific to the /// given [Header]. fn env_with_header( &self, @@ -40,7 +40,7 @@ pub trait EvmEnvProvider: Send + Sync { Ok((cfg, block_env)) } - /// Fills the [CfgEnvWithHandlerCfg] and [BlockEnv] fields with values specific to the given + /// Fills the [`CfgEnvWithHandlerCfg`] and [BlockEnv] fields with values specific to the given /// [Header]. fn fill_env_with_header( &self, @@ -52,21 +52,7 @@ pub trait EvmEnvProvider: Send + Sync { where EvmConfig: ConfigureEvmEnv; - /// Fills the [BlockEnv] fields with values specific to the given [BlockHashOrNumber]. - fn fill_block_env_at( - &self, - block_env: &mut BlockEnv, - at: BlockHashOrNumber, - ) -> ProviderResult<()>; - - /// Fills the [BlockEnv] fields with values specific to the given [Header]. - fn fill_block_env_with_header( - &self, - block_env: &mut BlockEnv, - header: &Header, - ) -> ProviderResult<()>; - - /// Fills the [CfgEnvWithHandlerCfg] fields with values specific to the given + /// Fills the [`CfgEnvWithHandlerCfg`] fields with values specific to the given /// [BlockHashOrNumber]. fn fill_cfg_env_at( &self, @@ -77,7 +63,7 @@ pub trait EvmEnvProvider: Send + Sync { where EvmConfig: ConfigureEvmEnv; - /// Fills the [CfgEnvWithHandlerCfg] fields with values specific to the given [Header]. + /// Fills the [`CfgEnvWithHandlerCfg`] fields with values specific to the given [Header]. fn fill_cfg_env_with_header( &self, cfg: &mut CfgEnvWithHandlerCfg, diff --git a/crates/evm/src/test_utils.rs b/crates/evm/src/test_utils.rs index c9627933a7fc..a4d098f0b3aa 100644 --- a/crates/evm/src/test_utils.rs +++ b/crates/evm/src/test_utils.rs @@ -10,7 +10,7 @@ use reth_primitives::{BlockNumber, BlockWithSenders, Receipt}; use reth_prune_types::PruneModes; use reth_storage_errors::provider::ProviderError; use revm_primitives::db::Database; -use std::sync::Arc; +use std::{fmt::Display, sync::Arc}; /// A [`BlockExecutorProvider`] that returns mocked execution results. #[derive(Clone, Debug, Default)] @@ -26,20 +26,20 @@ impl MockExecutorProvider { } impl BlockExecutorProvider for MockExecutorProvider { - type Executor> = Self; + type Executor + Display>> = Self; - type BatchExecutor> = Self; + type BatchExecutor + Display>> = Self; fn executor(&self, _: DB) -> Self::Executor where - DB: Database, + DB: Database + Display>, { self.clone() } fn batch_executor(&self, _: DB, _: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + Display>, { self.clone() } diff --git a/crates/exex/exex/Cargo.toml b/crates/exex/exex/Cargo.toml index 5bbf177d098b..a911f45997a7 100644 --- a/crates/exex/exex/Cargo.toml +++ b/crates/exex/exex/Cargo.toml @@ -24,6 +24,11 @@ reth-tasks.workspace = true reth-tracing.workspace = true reth-network.workspace = true reth-payload-builder.workspace = true +reth-evm.workspace = true +reth-prune-types.workspace = true +reth-revm.workspace = true +reth-stages-api.workspace = true +reth-db-api.workspace = true ## async tokio.workspace = true @@ -34,6 +39,17 @@ eyre.workspace = true metrics.workspace = true serde = { workspace = true, optional = true } +[dev-dependencies] +reth-chainspec.workspace = true +reth-evm-ethereum.workspace = true +reth-testing-utils.workspace = true +reth-blockchain-tree.workspace = true +reth-db-common.workspace = true +reth-node-api.workspace = true +reth-provider = { workspace = true, features = ["test-utils"] } + +secp256k1.workspace = true + [features] default = [] serde = ["dep:serde", "reth-provider/serde"] diff --git a/crates/exex/exex/src/backfill.rs b/crates/exex/exex/src/backfill.rs new file mode 100644 index 000000000000..f46c82d24101 --- /dev/null +++ b/crates/exex/exex/src/backfill.rs @@ -0,0 +1,344 @@ +use reth_db_api::database::Database; +use reth_evm::execute::{BatchExecutor, BlockExecutionError, BlockExecutorProvider}; +use reth_node_api::FullNodeComponents; +use reth_primitives::{Block, BlockNumber}; +use reth_provider::{Chain, FullProvider, ProviderError, TransactionVariant}; +use reth_prune_types::PruneModes; +use reth_revm::database::StateProviderDatabase; +use reth_stages_api::{format_gas_throughput, ExecutionStageThresholds}; +use reth_tracing::tracing::{debug, trace}; +use std::{ + marker::PhantomData, + ops::RangeInclusive, + time::{Duration, Instant}, +}; + +/// Factory for creating new backfill jobs. +#[derive(Debug, Clone)] +pub struct BackfillJobFactory { + executor: E, + provider: P, + prune_modes: PruneModes, + thresholds: ExecutionStageThresholds, +} + +impl BackfillJobFactory { + /// Creates a new [`BackfillJobFactory`]. + pub fn new(executor: E, provider: P, prune_modes: PruneModes) -> Self { + Self { executor, provider, prune_modes, thresholds: ExecutionStageThresholds::default() } + } + + /// Sets the thresholds + pub const fn with_thresholds(mut self, thresholds: ExecutionStageThresholds) -> Self { + self.thresholds = thresholds; + self + } +} + +impl BackfillJobFactory { + /// Creates a new backfill job for the given range. + pub fn backfill(&self, range: RangeInclusive) -> BackfillJob { + BackfillJob { + executor: self.executor.clone(), + provider: self.provider.clone(), + prune_modes: self.prune_modes.clone(), + range, + thresholds: self.thresholds.clone(), + _db: PhantomData, + } + } +} + +impl BackfillJobFactory<(), ()> { + /// Creates a new [`BackfillJobFactory`] from [`FullNodeComponents`]. + pub fn new_from_components( + components: Node, + prune_modes: PruneModes, + ) -> BackfillJobFactory { + BackfillJobFactory::<_, _>::new( + components.block_executor().clone(), + components.provider().clone(), + prune_modes, + ) + } +} + +/// Backfill job started for a specific range. +/// +/// It implements [`Iterator`] that executes blocks in batches according to the provided thresholds +/// and yields [`Chain`] +#[derive(Debug)] +pub struct BackfillJob { + executor: E, + provider: P, + prune_modes: PruneModes, + range: RangeInclusive, + thresholds: ExecutionStageThresholds, + _db: PhantomData, +} + +impl Iterator for BackfillJob +where + E: BlockExecutorProvider, + DB: Database, + P: FullProvider, +{ + type Item = Result; + + fn next(&mut self) -> Option { + if self.range.is_empty() { + return None + } + + Some(self.execute_range()) + } +} + +impl BackfillJob +where + E: BlockExecutorProvider, + DB: Database, + P: FullProvider, +{ + fn execute_range(&mut self) -> Result { + let mut executor = self.executor.batch_executor( + StateProviderDatabase::new( + self.provider.history_by_block_number(self.range.start().saturating_sub(1))?, + ), + self.prune_modes.clone(), + ); + + let mut fetch_block_duration = Duration::default(); + let mut execution_duration = Duration::default(); + let mut cumulative_gas = 0; + let batch_start = Instant::now(); + + let mut blocks = Vec::new(); + for block_number in self.range.clone() { + // Fetch the block + let fetch_block_start = Instant::now(); + + let td = self + .provider + .header_td_by_number(block_number)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + // we need the block's transactions along with their hashes + let block = self + .provider + .sealed_block_with_senders(block_number.into(), TransactionVariant::WithHash)? + .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?; + + fetch_block_duration += fetch_block_start.elapsed(); + + cumulative_gas += block.gas_used; + + // Configure the executor to use the current state. + trace!(target: "exex::backfill", number = block_number, txs = block.body.len(), "Executing block"); + + // Execute the block + let execute_start = Instant::now(); + + // Unseal the block for execution + let (block, senders) = block.into_components(); + let (unsealed_header, hash) = block.header.split(); + let block = Block { + header: unsealed_header, + body: block.body, + ommers: block.ommers, + withdrawals: block.withdrawals, + requests: block.requests, + } + .with_senders_unchecked(senders); + + executor.execute_and_verify_one((&block, td).into())?; + execution_duration += execute_start.elapsed(); + + // TODO(alexey): report gas metrics using `block.header.gas_used` + + // Seal the block back and save it + blocks.push(block.seal(hash)); + + // Check if we should commit now + let bundle_size_hint = executor.size_hint().unwrap_or_default() as u64; + if self.thresholds.is_end_of_batch( + block_number - *self.range.start(), + bundle_size_hint, + cumulative_gas, + batch_start.elapsed(), + ) { + break + } + } + + let last_block_number = blocks.last().expect("blocks should not be empty").number; + debug!( + target: "exex::backfill", + range = ?*self.range.start()..=last_block_number, + block_fetch = ?fetch_block_duration, + execution = ?execution_duration, + throughput = format_gas_throughput(cumulative_gas, execution_duration), + "Finished executing block range" + ); + self.range = last_block_number + 1..=*self.range.end(); + + let chain = Chain::new(blocks, executor.finalize(), None); + Ok(chain) + } +} + +#[cfg(test)] +mod tests { + use crate::BackfillJobFactory; + use eyre::OptionExt; + use reth_blockchain_tree::noop::NoopBlockchainTree; + use reth_chainspec::{ChainSpecBuilder, EthereumHardfork, MAINNET}; + use reth_db_common::init::init_genesis; + use reth_evm::execute::{BatchExecutor, BlockExecutorProvider}; + use reth_evm_ethereum::execute::EthExecutorProvider; + use reth_primitives::{ + b256, constants::ETH_TO_WEI, public_key_to_address, Address, Block, Genesis, + GenesisAccount, Header, Transaction, TxEip2930, TxKind, U256, + }; + use reth_provider::{ + providers::BlockchainProvider, test_utils::create_test_provider_factory_with_chain_spec, + BlockWriter, LatestStateProviderRef, + }; + use reth_prune_types::PruneModes; + use reth_revm::database::StateProviderDatabase; + use reth_testing_utils::generators::{self, sign_tx_with_key_pair}; + use secp256k1::Keypair; + use std::sync::Arc; + + #[tokio::test] + async fn test_backfill() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + + // Create a key pair for the sender + let key_pair = Keypair::new_global(&mut generators::rng()); + let address = public_key_to_address(key_pair.public_key()); + + // Create a chain spec with a genesis state that contains the sender + let chain_spec = Arc::new( + ChainSpecBuilder::default() + .chain(MAINNET.chain) + .genesis(Genesis { + alloc: [( + address, + GenesisAccount { balance: U256::from(ETH_TO_WEI), ..Default::default() }, + )] + .into(), + ..MAINNET.genesis.clone() + }) + .paris_activated() + .build(), + ); + + let executor = EthExecutorProvider::ethereum(chain_spec.clone()); + let provider_factory = create_test_provider_factory_with_chain_spec(chain_spec.clone()); + init_genesis(provider_factory.clone())?; + let blockchain_db = BlockchainProvider::new( + provider_factory.clone(), + Arc::new(NoopBlockchainTree::default()), + )?; + + // First block has a transaction that transfers some ETH to zero address + let block1 = Block { + header: Header { + parent_hash: chain_spec.genesis_hash(), + receipts_root: b256!( + "d3a6acf9a244d78b33831df95d472c4128ea85bf079a1d41e32ed0b7d2244c9e" + ), + difficulty: chain_spec.fork(EthereumHardfork::Paris).ttd().expect("Paris TTD"), + number: 1, + gas_limit: 21000, + gas_used: 21000, + ..Default::default() + }, + body: vec![sign_tx_with_key_pair( + key_pair, + Transaction::Eip2930(TxEip2930 { + chain_id: chain_spec.chain.id(), + nonce: 0, + gas_limit: 21000, + gas_price: 1_500_000_000, + to: TxKind::Call(Address::ZERO), + value: U256::from(0.1 * ETH_TO_WEI as f64), + ..Default::default() + }), + )], + ..Default::default() + } + .with_recovered_senders() + .ok_or_eyre("failed to recover senders")?; + + // Second block has no state changes + let block2 = Block { + header: Header { + parent_hash: block1.hash_slow(), + difficulty: chain_spec.fork(EthereumHardfork::Paris).ttd().expect("Paris TTD"), + number: 2, + ..Default::default() + }, + ..Default::default() + } + .with_recovered_senders() + .ok_or_eyre("failed to recover senders")?; + + let provider = provider_factory.provider()?; + // Execute only the first block on top of genesis state + let mut outcome_single = EthExecutorProvider::ethereum(chain_spec.clone()) + .batch_executor( + StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider.static_file_provider().clone(), + )), + PruneModes::none(), + ) + .execute_and_verify_batch([(&block1, U256::ZERO).into()])?; + outcome_single.bundle.reverts.sort(); + // Execute both blocks on top of the genesis state + let outcome_batch = EthExecutorProvider::ethereum(chain_spec) + .batch_executor( + StateProviderDatabase::new(LatestStateProviderRef::new( + provider.tx_ref(), + provider.static_file_provider().clone(), + )), + PruneModes::none(), + ) + .execute_and_verify_batch([ + (&block1, U256::ZERO).into(), + (&block2, U256::ZERO).into(), + ])?; + drop(provider); + + let block1 = block1.seal_slow(); + let block2 = block2.seal_slow(); + + // Update the state with the execution results of both blocks + let provider_rw = provider_factory.provider_rw()?; + provider_rw.append_blocks_with_state( + vec![block1.clone(), block2], + outcome_batch, + Default::default(), + Default::default(), + None, + )?; + provider_rw.commit()?; + + // Backfill the first block + let factory = BackfillJobFactory::new(executor, blockchain_db, PruneModes::none()); + let job = factory.backfill(1..=1); + let chains = job.collect::, _>>()?; + + // Assert that the backfill job produced the same chain as we got before when we were + // executing only the first block + assert_eq!(chains.len(), 1); + let mut chain = chains.into_iter().next().unwrap(); + chain.execution_outcome_mut().bundle.reverts.sort(); + assert_eq!(chain.blocks(), &[(1, block1)].into()); + assert_eq!(chain.execution_outcome(), &outcome_single); + + Ok(()) + } +} diff --git a/crates/exex/exex/src/lib.rs b/crates/exex/exex/src/lib.rs index a7661d855f41..5f859accca42 100644 --- a/crates/exex/exex/src/lib.rs +++ b/crates/exex/exex/src/lib.rs @@ -34,6 +34,9 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] +mod backfill; +pub use backfill::*; + mod context; pub use context::*; diff --git a/crates/exex/types/Cargo.toml b/crates/exex/types/Cargo.toml index 8797376da74b..e03b63342f72 100644 --- a/crates/exex/types/Cargo.toml +++ b/crates/exex/types/Cargo.toml @@ -12,4 +12,4 @@ description = "Commonly used types for exex usage in reth." workspace = true [dependencies] -alloy-primitives.workspace = true \ No newline at end of file +alloy-primitives.workspace = true diff --git a/crates/net/banlist/src/ban_list.rs b/crates/net/banlist/src/ban_list.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/crates/net/discv4/src/lib.rs b/crates/net/discv4/src/lib.rs index 6e18892fdd0c..7c14eac9b653 100644 --- a/crates/net/discv4/src/lib.rs +++ b/crates/net/discv4/src/lib.rs @@ -214,9 +214,8 @@ impl Discv4 { /// ``` /// # use std::io; /// use rand::thread_rng; - /// use reth_chainspec::net::NodeRecord; /// use reth_discv4::{Discv4, Discv4Config}; - /// use reth_network_peers::{pk2id, PeerId}; + /// use reth_network_peers::{pk2id, NodeRecord, PeerId}; /// use secp256k1::SECP256K1; /// use std::{net::SocketAddr, str::FromStr}; /// # async fn t() -> io::Result<()> { @@ -2288,8 +2287,8 @@ mod tests { use alloy_primitives::hex; use alloy_rlp::{Decodable, Encodable}; use rand::{thread_rng, Rng}; - use reth_chainspec::net::mainnet_nodes; use reth_ethereum_forks::{EnrForkIdEntry, ForkHash}; + use reth_network_peers::mainnet_nodes; use std::future::poll_fn; #[tokio::test] diff --git a/crates/net/discv5/src/enr.rs b/crates/net/discv5/src/enr.rs index eb8b6be006b2..bb49f72e8f6d 100644 --- a/crates/net/discv5/src/enr.rs +++ b/crates/net/discv5/src/enr.rs @@ -58,7 +58,7 @@ mod tests { use super::*; use alloy_rlp::Encodable; use discv5::enr::{CombinedKey, EnrKey}; - use reth_chainspec::{Hardfork, MAINNET}; + use reth_chainspec::{EthereumHardfork, MAINNET}; use reth_network_peers::NodeRecord; #[test] @@ -84,7 +84,7 @@ mod tests { let key = CombinedKey::generate_secp256k1(); let mut buf = Vec::new(); - let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier); + let fork_id = MAINNET.hardfork_fork_id(EthereumHardfork::Frontier); fork_id.unwrap().encode(&mut buf); let enr = Enr::builder() diff --git a/crates/net/dns/src/lib.rs b/crates/net/dns/src/lib.rs index f07fde2e4a67..55d93c459cb8 100644 --- a/crates/net/dns/src/lib.rs +++ b/crates/net/dns/src/lib.rs @@ -415,7 +415,7 @@ mod tests { use alloy_rlp::{Decodable, Encodable}; use enr::EnrKey; use reth_chainspec::MAINNET; - use reth_ethereum_forks::{ForkHash, Hardfork}; + use reth_ethereum_forks::{EthereumHardfork, ForkHash}; use secp256k1::rand::thread_rng; use std::{future::poll_fn, net::Ipv4Addr}; @@ -513,7 +513,7 @@ mod tests { resolver.insert(link.domain.clone(), root.to_string()); let mut builder = Enr::builder(); - let fork_id = MAINNET.hardfork_fork_id(Hardfork::Frontier).unwrap(); + let fork_id = MAINNET.hardfork_fork_id(EthereumHardfork::Frontier).unwrap(); builder .ip4(Ipv4Addr::LOCALHOST) .udp4(30303) diff --git a/crates/net/downloaders/src/file_client.rs b/crates/net/downloaders/src/file_client.rs index 3464baf5d6ff..3d00c389237b 100644 --- a/crates/net/downloaders/src/file_client.rs +++ b/crates/net/downloaders/src/file_client.rs @@ -228,15 +228,7 @@ impl FromReader for FileClient { // add to the internal maps headers.insert(block.header.number, block.header.clone()); hash_to_number.insert(block_hash, block.header.number); - bodies.insert( - block_hash, - BlockBody { - transactions: block.body, - ommers: block.ommers, - withdrawals: block.withdrawals, - requests: block.requests, - }, - ); + bodies.insert(block_hash, block.into()); if log_interval == 0 { trace!(target: "downloaders::file", diff --git a/crates/net/ecies/src/codec.rs b/crates/net/ecies/src/codec.rs index 54250e10210e..c3e9b8d58cc9 100644 --- a/crates/net/ecies/src/codec.rs +++ b/crates/net/ecies/src/codec.rs @@ -1,3 +1,5 @@ +//! This contains the main codec for `RLPx` ECIES messages + use crate::{algorithm::ECIES, ECIESError, EgressECIESValue, IngressECIESValue}; use alloy_primitives::{bytes::BytesMut, B512 as PeerId}; use secp256k1::SecretKey; @@ -7,14 +9,14 @@ use tracing::{instrument, trace}; /// Tokio codec for ECIES #[derive(Debug)] -pub(crate) struct ECIESCodec { +pub struct ECIESCodec { ecies: ECIES, state: ECIESState, } /// Current ECIES state of a connection #[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum ECIESState { +pub enum ECIESState { /// The first stage of the ECIES handshake, where each side of the connection sends an auth /// message containing the ephemeral public key, signature of the public key, nonce, and other /// metadata. @@ -23,7 +25,12 @@ enum ECIESState { /// The second stage of the ECIES handshake, where each side of the connection sends an ack /// message containing the nonce and other metadata. Ack, + + /// The third stage of the ECIES handshake, where header is parsed, message integrity checks + /// performed, and message is decrypted. Header, + + /// The final stage, where the ECIES message is actually read and returned by the ECIES codec. Body, } diff --git a/crates/net/ecies/src/lib.rs b/crates/net/ecies/src/lib.rs index 378398d6ba30..f766b48b21cb 100644 --- a/crates/net/ecies/src/lib.rs +++ b/crates/net/ecies/src/lib.rs @@ -16,7 +16,7 @@ pub mod util; mod error; pub use error::ECIESError; -mod codec; +pub mod codec; use alloy_primitives::{ bytes::{Bytes, BytesMut}, diff --git a/crates/net/eth-wire-types/src/lib.rs b/crates/net/eth-wire-types/src/lib.rs index a60fa4c8c1e9..e75898a1ff70 100644 --- a/crates/net/eth-wire-types/src/lib.rs +++ b/crates/net/eth-wire-types/src/lib.rs @@ -6,8 +6,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![allow(clippy::needless_lifetimes)] // side effect of optimism fields #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] diff --git a/crates/net/eth-wire-types/src/status.rs b/crates/net/eth-wire-types/src/status.rs index 95e5aa84adf5..873af22274bd 100644 --- a/crates/net/eth-wire-types/src/status.rs +++ b/crates/net/eth-wire-types/src/status.rs @@ -3,7 +3,7 @@ use alloy_genesis::Genesis; use alloy_rlp::{RlpDecodable, RlpEncodable}; use reth_chainspec::{Chain, ChainSpec, NamedChain, MAINNET}; use reth_codecs_derive::derive_arbitrary; -use reth_primitives::{hex, ForkId, Hardfork, Head, B256, U256}; +use reth_primitives::{hex, EthereumHardfork, ForkId, Head, B256, U256}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display}; @@ -142,7 +142,7 @@ impl Default for Status { blockhash: mainnet_genesis, genesis: mainnet_genesis, forkid: MAINNET - .hardfork_fork_id(Hardfork::Frontier) + .hardfork_fork_id(EthereumHardfork::Frontier) .expect("The Frontier hardfork should always exist"), } } @@ -152,7 +152,7 @@ impl Default for Status { /// /// # Example /// ``` -/// use reth_chainspec::{Chain, Hardfork, MAINNET}; +/// use reth_chainspec::{Chain, EthereumHardfork, MAINNET}; /// use reth_eth_wire_types::{EthVersion, Status}; /// use reth_primitives::{B256, MAINNET_GENESIS_HASH, U256}; /// @@ -163,7 +163,7 @@ impl Default for Status { /// .total_difficulty(U256::from(100)) /// .blockhash(B256::from(MAINNET_GENESIS_HASH)) /// .genesis(B256::from(MAINNET_GENESIS_HASH)) -/// .forkid(MAINNET.hardfork_fork_id(Hardfork::Paris).unwrap()) +/// .forkid(MAINNET.hardfork_fork_id(EthereumHardfork::Paris).unwrap()) /// .build(); /// /// assert_eq!( @@ -174,7 +174,7 @@ impl Default for Status { /// total_difficulty: U256::from(100), /// blockhash: B256::from(MAINNET_GENESIS_HASH), /// genesis: B256::from(MAINNET_GENESIS_HASH), -/// forkid: MAINNET.hardfork_fork_id(Hardfork::Paris).unwrap(), +/// forkid: MAINNET.hardfork_fork_id(EthereumHardfork::Paris).unwrap(), /// } /// ); /// ``` @@ -233,7 +233,7 @@ mod tests { use alloy_rlp::{Decodable, Encodable}; use rand::Rng; use reth_chainspec::{Chain, ChainSpec, ForkCondition, NamedChain}; - use reth_primitives::{hex, ForkHash, ForkId, Hardfork, Head, B256, U256}; + use reth_primitives::{hex, EthereumHardfork, ForkHash, ForkId, Head, B256, U256}; use std::str::FromStr; #[test] @@ -368,12 +368,12 @@ mod tests { // add a few hardforks let hardforks = vec![ - (Hardfork::Tangerine, ForkCondition::Block(1)), - (Hardfork::SpuriousDragon, ForkCondition::Block(2)), - (Hardfork::Byzantium, ForkCondition::Block(3)), - (Hardfork::MuirGlacier, ForkCondition::Block(5)), - (Hardfork::London, ForkCondition::Block(8)), - (Hardfork::Shanghai, ForkCondition::Timestamp(13)), + (EthereumHardfork::Tangerine, ForkCondition::Block(1)), + (EthereumHardfork::SpuriousDragon, ForkCondition::Block(2)), + (EthereumHardfork::Byzantium, ForkCondition::Block(3)), + (EthereumHardfork::MuirGlacier, ForkCondition::Block(5)), + (EthereumHardfork::London, ForkCondition::Block(8)), + (EthereumHardfork::Shanghai, ForkCondition::Timestamp(13)), ]; let mut chainspec = ChainSpec::builder().genesis(genesis).chain(Chain::from_id(1337)); diff --git a/crates/net/eth-wire/src/lib.rs b/crates/net/eth-wire/src/lib.rs index 3830baa1b7e5..e96a27077f8c 100644 --- a/crates/net/eth-wire/src/lib.rs +++ b/crates/net/eth-wire/src/lib.rs @@ -11,8 +11,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] pub mod capability; diff --git a/crates/net/eth-wire/src/p2pstream.rs b/crates/net/eth-wire/src/p2pstream.rs index 23f106da9a42..aa8770d058c6 100644 --- a/crates/net/eth-wire/src/p2pstream.rs +++ b/crates/net/eth-wire/src/p2pstream.rs @@ -478,11 +478,10 @@ where // // It's possible we already tried to RLP decode this, but it was snappy // compressed, so we need to RLP decode it again. - let reason = DisconnectReason::decode(&mut &decompress_buf[1..]).map_err(|err| { + let reason = DisconnectReason::decode(&mut &decompress_buf[1..]).inspect_err(|err| { debug!( %err, msg=%hex::encode(&decompress_buf[1..]), "Failed to decode disconnect message from peer" ); - err })?; return Poll::Ready(Some(Err(P2PStreamError::Disconnected(reason)))) } diff --git a/crates/net/eth-wire/tests/fuzz_roundtrip.rs b/crates/net/eth-wire/tests/fuzz_roundtrip.rs index f20d0397c2b6..ec55fc448ae0 100644 --- a/crates/net/eth-wire/tests/fuzz_roundtrip.rs +++ b/crates/net/eth-wire/tests/fuzz_roundtrip.rs @@ -1,8 +1,5 @@ //! Round-trip encoding fuzzing for the `eth-wire` crate. -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] - use alloy_rlp::{Decodable, Encodable}; use serde::Serialize; use std::fmt::Debug; diff --git a/crates/net/network-api/src/lib.rs b/crates/net/network-api/src/lib.rs index 6c6f8036daff..e9cce0866fde 100644 --- a/crates/net/network-api/src/lib.rs +++ b/crates/net/network-api/src/lib.rs @@ -66,9 +66,14 @@ pub trait PeersInfo: Send + Sync { /// Provides an API for managing the peers of the network. pub trait Peers: PeersInfo { - /// Adds a peer to the peer set. - fn add_peer(&self, peer: PeerId, addr: SocketAddr) { - self.add_peer_kind(peer, PeerKind::Basic, addr); + /// Adds a peer to the peer set with UDP `SocketAddr`. + fn add_peer(&self, peer: PeerId, tcp_addr: SocketAddr) { + self.add_peer_kind(peer, PeerKind::Static, tcp_addr, None); + } + + /// Adds a peer to the peer set with TCP and UDP `SocketAddr`. + fn add_peer_with_udp(&self, peer: PeerId, tcp_addr: SocketAddr, udp_addr: SocketAddr) { + self.add_peer_kind(peer, PeerKind::Static, tcp_addr, Some(udp_addr)); } /// Adds a trusted [`PeerId`] to the peer set. @@ -76,13 +81,24 @@ pub trait Peers: PeersInfo { /// This allows marking a peer as trusted without having to know the peer's address. fn add_trusted_peer_id(&self, peer: PeerId); - /// Adds a trusted peer to the peer set. - fn add_trusted_peer(&self, peer: PeerId, addr: SocketAddr) { - self.add_peer_kind(peer, PeerKind::Trusted, addr); + /// Adds a trusted peer to the peer set with UDP `SocketAddr`. + fn add_trusted_peer(&self, peer: PeerId, tcp_addr: SocketAddr) { + self.add_peer_kind(peer, PeerKind::Trusted, tcp_addr, None); + } + + /// Adds a trusted peer with TCP and UDP `SocketAddr` to the peer set. + fn add_trusted_peer_with_udp(&self, peer: PeerId, tcp_addr: SocketAddr, udp_addr: SocketAddr) { + self.add_peer_kind(peer, PeerKind::Trusted, tcp_addr, Some(udp_addr)); } /// Adds a peer to the known peer set, with the given kind. - fn add_peer_kind(&self, peer: PeerId, kind: PeerKind, addr: SocketAddr); + fn add_peer_kind( + &self, + peer: PeerId, + kind: PeerKind, + tcp_addr: SocketAddr, + udp_addr: Option, + ); /// Returns the rpc [`PeerInfo`] for all connected [`PeerKind::Trusted`] peers. fn get_trusted_peers( @@ -147,6 +163,8 @@ pub enum PeerKind { /// Basic peer kind. #[default] Basic, + /// Static peer, added via JSON-RPC. + Static, /// Trusted peer. Trusted, } @@ -157,6 +175,11 @@ impl PeerKind { matches!(self, Self::Trusted) } + /// Returns `true` if the peer is static. + pub const fn is_static(&self) -> bool { + matches!(self, Self::Static) + } + /// Returns `true` if the peer is basic. pub const fn is_basic(&self) -> bool { matches!(self, Self::Basic) diff --git a/crates/net/network-api/src/noop.rs b/crates/net/network-api/src/noop.rs index 745613f40655..a74204a3f742 100644 --- a/crates/net/network-api/src/noop.rs +++ b/crates/net/network-api/src/noop.rs @@ -71,7 +71,14 @@ impl PeersInfo for NoopNetwork { impl Peers for NoopNetwork { fn add_trusted_peer_id(&self, _peer: PeerId) {} - fn add_peer_kind(&self, _peer: PeerId, _kind: PeerKind, _addr: SocketAddr) {} + fn add_peer_kind( + &self, + _peer: PeerId, + _kind: PeerKind, + _tcp_addr: SocketAddr, + _udp_addr: Option, + ) { + } async fn get_peers_by_kind(&self, _kind: PeerKind) -> Result, NetworkError> { Ok(vec![]) diff --git a/crates/net/network-types/Cargo.toml b/crates/net/network-types/Cargo.toml new file mode 100644 index 000000000000..66c1f4d84a38 --- /dev/null +++ b/crates/net/network-types/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "reth-network-types" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +description = "Commonly used network types" + +[lints] +workspace = true + +[dependencies] +# reth +reth-network-api.workspace = true +reth-network-peers.workspace = true +reth-net-banlist.workspace = true + +# io +serde = { workspace = true, optional = true } +humantime-serde = { workspace = true, optional = true } +serde_json = { workspace = true } + +# misc +tracing.workspace = true + +[features] +serde = ["dep:serde", "dep:humantime-serde"] +test-utils = [] diff --git a/crates/net/network-types/src/backoff.rs b/crates/net/network-types/src/backoff.rs new file mode 100644 index 000000000000..8ee9f68a4e31 --- /dev/null +++ b/crates/net/network-types/src/backoff.rs @@ -0,0 +1,27 @@ +/// Describes the type of backoff should be applied. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum BackoffKind { + /// Use the lowest configured backoff duration. + /// + /// This applies to connection problems where there is a chance that they will be resolved + /// after the short duration. + Low, + /// Use a slightly higher duration to put a peer in timeout + /// + /// This applies to more severe connection problems where there is a lower chance that they + /// will be resolved. + Medium, + /// Use the max configured backoff duration. + /// + /// This is intended for spammers, or bad peers in general. + High, +} + +// === impl BackoffKind === + +impl BackoffKind { + /// Returns true if the backoff is considered severe. + pub const fn is_severe(&self) -> bool { + matches!(self, Self::Medium | Self::High) + } +} diff --git a/crates/net/network-types/src/lib.rs b/crates/net/network-types/src/lib.rs new file mode 100644 index 000000000000..5b075d609bc1 --- /dev/null +++ b/crates/net/network-types/src/lib.rs @@ -0,0 +1,24 @@ +//! Commonly used networking types. +//! +//! ## Feature Flags +//! +//! - `serde` (default): Enable serde support + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +/// Types related to peering. +pub mod peers; +pub use peers::{ConnectionsConfig, PeersConfig, ReputationChangeWeights}; + +pub mod session; +pub use session::{SessionLimits, SessionsConfig}; + +/// [`BackoffKind`] definition. +mod backoff; +pub use backoff::BackoffKind; diff --git a/crates/net/network-types/src/peers/config.rs b/crates/net/network-types/src/peers/config.rs new file mode 100644 index 000000000000..5143c4c6f2bf --- /dev/null +++ b/crates/net/network-types/src/peers/config.rs @@ -0,0 +1,292 @@ +//! Configuration for peering. + +use crate::{BackoffKind, ReputationChangeWeights}; +use reth_net_banlist::BanList; +use reth_network_peers::NodeRecord; +use std::{ + collections::HashSet, + io::{self, ErrorKind}, + path::Path, + time::Duration, +}; +use tracing::info; + +/// Maximum number of available slots for outbound sessions. +pub const DEFAULT_MAX_COUNT_PEERS_OUTBOUND: u32 = 100; + +/// Maximum number of available slots for inbound sessions. +pub const DEFAULT_MAX_COUNT_PEERS_INBOUND: u32 = 30; + +/// Maximum number of available slots for concurrent outgoing dials. +/// +/// This restricts how many outbound dials can be performed concurrently. +pub const DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS: usize = 15; + +/// The durations to use when a backoff should be applied to a peer. +/// +/// See also [`BackoffKind`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct PeerBackoffDurations { + /// Applies to connection problems where there is a chance that they will be resolved after the + /// short duration. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub low: Duration, + /// Applies to more severe connection problems where there is a lower chance that they will be + /// resolved. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub medium: Duration, + /// Intended for spammers, or bad peers in general. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub high: Duration, + /// Maximum total backoff duration. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub max: Duration, +} + +impl PeerBackoffDurations { + /// Returns the corresponding [`Duration`] + pub const fn backoff(&self, kind: BackoffKind) -> Duration { + match kind { + BackoffKind::Low => self.low, + BackoffKind::Medium => self.medium, + BackoffKind::High => self.high, + } + } + + /// Returns the timestamp until which we should backoff. + /// + /// The Backoff duration is capped by the configured maximum backoff duration. + pub fn backoff_until(&self, kind: BackoffKind, backoff_counter: u8) -> std::time::Instant { + let backoff_time = self.backoff(kind); + let backoff_time = backoff_time + backoff_time * backoff_counter as u32; + let now = std::time::Instant::now(); + now + backoff_time.min(self.max) + } + + /// Returns durations for testing. + #[cfg(any(test, feature = "test-utils"))] + pub const fn test() -> Self { + Self { + low: Duration::from_millis(200), + medium: Duration::from_millis(200), + high: Duration::from_millis(200), + max: Duration::from_millis(200), + } + } +} + +impl Default for PeerBackoffDurations { + fn default() -> Self { + Self { + low: Duration::from_secs(30), + // 3min + medium: Duration::from_secs(60 * 3), + // 15min + high: Duration::from_secs(60 * 15), + // 1h + max: Duration::from_secs(60 * 60), + } + } +} + +/// Tracks stats about connected nodes +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))] +pub struct ConnectionsConfig { + /// Maximum allowed outbound connections. + pub max_outbound: usize, + /// Maximum allowed inbound connections. + pub max_inbound: usize, + /// Maximum allowed concurrent outbound dials. + #[cfg_attr(feature = "serde", serde(default))] + pub max_concurrent_outbound_dials: usize, +} + +impl Default for ConnectionsConfig { + fn default() -> Self { + Self { + max_outbound: DEFAULT_MAX_COUNT_PEERS_OUTBOUND as usize, + max_inbound: DEFAULT_MAX_COUNT_PEERS_INBOUND as usize, + max_concurrent_outbound_dials: DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS, + } + } +} + +/// Config type for initiating a `PeersManager` instance. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(default))] +pub struct PeersConfig { + /// How often to recheck free slots for outbound connections. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub refill_slots_interval: Duration, + /// Trusted nodes to connect to or accept from + pub trusted_nodes: HashSet, + /// Connect to or accept from trusted nodes only? + #[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))] + pub trusted_nodes_only: bool, + /// Maximum number of backoff attempts before we give up on a peer and dropping. + /// + /// The max time spent of a peer before it's removed from the set is determined by the + /// configured backoff duration and the max backoff count. + /// + /// With a backoff counter of 5 and a backoff duration of 1h, the minimum time spent of the + /// peer in the table is the sum of all backoffs (1h + 2h + 3h + 4h + 5h = 15h). + /// + /// Note: this does not apply to trusted peers. + pub max_backoff_count: u8, + /// Basic nodes to connect to. + #[cfg_attr(feature = "serde", serde(skip))] + pub basic_nodes: HashSet, + /// How long to ban bad peers. + #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] + pub ban_duration: Duration, + /// Restrictions on `PeerIds` and Ips. + #[cfg_attr(feature = "serde", serde(skip))] + pub ban_list: BanList, + /// Restrictions on connections. + pub connection_info: ConnectionsConfig, + /// How to weigh reputation changes. + pub reputation_weights: ReputationChangeWeights, + /// How long to backoff peers that we are failed to connect to for non-fatal reasons. + /// + /// The backoff duration increases with number of backoff attempts. + pub backoff_durations: PeerBackoffDurations, +} + +impl Default for PeersConfig { + fn default() -> Self { + Self { + refill_slots_interval: Duration::from_millis(5_000), + connection_info: Default::default(), + reputation_weights: Default::default(), + ban_list: Default::default(), + // Ban peers for 12h + ban_duration: Duration::from_secs(60 * 60 * 12), + backoff_durations: Default::default(), + trusted_nodes: Default::default(), + trusted_nodes_only: false, + basic_nodes: Default::default(), + max_backoff_count: 5, + } + } +} + +impl PeersConfig { + /// A set of `peer_ids` and ip addr that we want to never connect to + pub fn with_ban_list(mut self, ban_list: BanList) -> Self { + self.ban_list = ban_list; + self + } + + /// Configure how long to ban bad peers + pub const fn with_ban_duration(mut self, ban_duration: Duration) -> Self { + self.ban_duration = ban_duration; + self + } + + /// Maximum allowed outbound connections. + pub const fn with_max_outbound(mut self, max_outbound: usize) -> Self { + self.connection_info.max_outbound = max_outbound; + self + } + + /// Maximum allowed inbound connections with optional update. + pub const fn with_max_inbound_opt(mut self, max_inbound: Option) -> Self { + if let Some(max_inbound) = max_inbound { + self.connection_info.max_inbound = max_inbound; + } + self + } + + /// Maximum allowed outbound connections with optional update. + pub const fn with_max_outbound_opt(mut self, max_outbound: Option) -> Self { + if let Some(max_outbound) = max_outbound { + self.connection_info.max_outbound = max_outbound; + } + self + } + + /// Maximum allowed inbound connections. + pub const fn with_max_inbound(mut self, max_inbound: usize) -> Self { + self.connection_info.max_inbound = max_inbound; + self + } + + /// Maximum allowed concurrent outbound dials. + pub const fn with_max_concurrent_dials(mut self, max_concurrent_outbound_dials: usize) -> Self { + self.connection_info.max_concurrent_outbound_dials = max_concurrent_outbound_dials; + self + } + + /// Nodes to always connect to. + pub fn with_trusted_nodes(mut self, nodes: HashSet) -> Self { + self.trusted_nodes = nodes; + self + } + + /// Connect only to trusted nodes. + pub const fn with_trusted_nodes_only(mut self, trusted_only: bool) -> Self { + self.trusted_nodes_only = trusted_only; + self + } + + /// Nodes available at launch. + pub fn with_basic_nodes(mut self, nodes: HashSet) -> Self { + self.basic_nodes = nodes; + self + } + + /// Configures the max allowed backoff count. + pub const fn with_max_backoff_count(mut self, max_backoff_count: u8) -> Self { + self.max_backoff_count = max_backoff_count; + self + } + + /// Configures how to weigh reputation changes. + pub const fn with_reputation_weights( + mut self, + reputation_weights: ReputationChangeWeights, + ) -> Self { + self.reputation_weights = reputation_weights; + self + } + + /// Configures how long to backoff peers that are we failed to connect to for non-fatal reasons + pub const fn with_backoff_durations(mut self, backoff_durations: PeerBackoffDurations) -> Self { + self.backoff_durations = backoff_durations; + self + } + + /// Returns the maximum number of peers, inbound and outbound. + pub const fn max_peers(&self) -> usize { + self.connection_info.max_outbound + self.connection_info.max_inbound + } + + /// Read from file nodes available at launch. Ignored if None. + pub fn with_basic_nodes_from_file( + self, + optional_file: Option>, + ) -> Result { + let Some(file_path) = optional_file else { return Ok(self) }; + let reader = match std::fs::File::open(file_path.as_ref()) { + Ok(file) => io::BufReader::new(file), + Err(e) if e.kind() == ErrorKind::NotFound => return Ok(self), + Err(e) => Err(e)?, + }; + info!(target: "net::peers", file = %file_path.as_ref().display(), "Loading saved peers"); + let nodes: HashSet = serde_json::from_reader(reader)?; + Ok(self.with_basic_nodes(nodes)) + } + + /// Returns settings for testing + #[cfg(any(test, feature = "test-utils"))] + pub fn test() -> Self { + Self { + refill_slots_interval: Duration::from_millis(100), + backoff_durations: PeerBackoffDurations::test(), + ..Default::default() + } + } +} diff --git a/crates/net/network-types/src/peers/mod.rs b/crates/net/network-types/src/peers/mod.rs new file mode 100644 index 000000000000..4b195750b516 --- /dev/null +++ b/crates/net/network-types/src/peers/mod.rs @@ -0,0 +1,5 @@ +pub mod reputation; +pub use reputation::ReputationChangeWeights; + +pub mod config; +pub use config::{ConnectionsConfig, PeersConfig}; diff --git a/crates/net/network/src/peers/reputation.rs b/crates/net/network-types/src/peers/reputation.rs similarity index 92% rename from crates/net/network/src/peers/reputation.rs rename to crates/net/network-types/src/peers/reputation.rs index 9d3ec256bea0..13fac4c1ebc2 100644 --- a/crates/net/network/src/peers/reputation.rs +++ b/crates/net/network-types/src/peers/reputation.rs @@ -3,13 +3,13 @@ use reth_network_api::{Reputation, ReputationChangeKind}; /// The default reputation of a peer -pub(crate) const DEFAULT_REPUTATION: Reputation = 0; +pub const DEFAULT_REPUTATION: Reputation = 0; /// The minimal unit we're measuring reputation const REPUTATION_UNIT: i32 = -1024; /// The reputation value below which new connection from/to peers are rejected. -pub(crate) const BANNED_REPUTATION: i32 = 50 * REPUTATION_UNIT; +pub const BANNED_REPUTATION: i32 = 50 * REPUTATION_UNIT; /// The reputation change to apply to a peer that dropped the connection. const REMOTE_DISCONNECT_REPUTATION_CHANGE: i32 = 4 * REPUTATION_UNIT; @@ -42,11 +42,11 @@ const BAD_ANNOUNCEMENT_REPUTATION_CHANGE: i32 = REPUTATION_UNIT; /// This gives a trusted peer more leeway when interacting with the node, which is useful for in /// custom setups. By not setting this to `0` we still allow trusted peer penalization but less than /// untrusted peers. -pub(crate) const MAX_TRUSTED_PEER_REPUTATION_CHANGE: Reputation = 2 * REPUTATION_UNIT; +pub const MAX_TRUSTED_PEER_REPUTATION_CHANGE: Reputation = 2 * REPUTATION_UNIT; /// Returns `true` if the given reputation is below the [`BANNED_REPUTATION`] threshold #[inline] -pub(crate) const fn is_banned_reputation(reputation: i32) -> bool { +pub const fn is_banned_reputation(reputation: i32) -> bool { reputation < BANNED_REPUTATION } @@ -80,7 +80,7 @@ pub struct ReputationChangeWeights { impl ReputationChangeWeights { /// Returns the quantifiable [`ReputationChange`] for the given [`ReputationChangeKind`] using /// the configured weights - pub(crate) fn change(&self, kind: ReputationChangeKind) -> ReputationChange { + pub fn change(&self, kind: ReputationChangeKind) -> ReputationChange { match kind { ReputationChangeKind::BadMessage => self.bad_message.into(), ReputationChangeKind::BadBlock => self.bad_block.into(), @@ -115,14 +115,14 @@ impl Default for ReputationChangeWeights { /// Represents a change in a peer's reputation. #[derive(Debug, Copy, Clone, Default)] -pub(crate) struct ReputationChange(Reputation); +pub struct ReputationChange(Reputation); // === impl ReputationChange === impl ReputationChange { /// Helper type for easier conversion #[inline] - pub(crate) const fn as_i32(self) -> Reputation { + pub const fn as_i32(self) -> Reputation { self.0 } } diff --git a/crates/net/network/src/session/config.rs b/crates/net/network-types/src/session/config.rs similarity index 65% rename from crates/net/network/src/session/config.rs rename to crates/net/network-types/src/session/config.rs index 6c7fc282d0a5..941448effd6b 100644 --- a/crates/net/network/src/session/config.rs +++ b/crates/net/network-types/src/session/config.rs @@ -1,9 +1,6 @@ -//! Configuration types for [`SessionManager`](crate::session::SessionManager). +//! Configuration types for peer sessions manager. -use crate::{ - peers::{DEFAULT_MAX_COUNT_PEERS_INBOUND, DEFAULT_MAX_COUNT_PEERS_OUTBOUND}, - session::{Direction, ExceedsSessionLimit}, -}; +use crate::peers::config::{DEFAULT_MAX_COUNT_PEERS_INBOUND, DEFAULT_MAX_COUNT_PEERS_OUTBOUND}; use std::time::Duration; /// Default request timeout for a single request. @@ -29,7 +26,7 @@ const DEFAULT_MAX_PEERS: usize = /// With maxed out peers, this will allow for 3 messages per session (average) const DEFAULT_SESSION_EVENT_BUFFER_SIZE: usize = DEFAULT_MAX_PEERS * 2; -/// Configuration options when creating a [`SessionManager`](crate::session::SessionManager). +/// Configuration options for peer session management. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(default))] @@ -111,10 +108,14 @@ impl SessionsConfig { #[derive(Debug, Clone, Default, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SessionLimits { - max_pending_inbound: Option, - max_pending_outbound: Option, - max_established_inbound: Option, - max_established_outbound: Option, + /// Maximum allowed inbound connections. + pub max_pending_inbound: Option, + /// Maximum allowed outbound connections. + pub max_pending_outbound: Option, + /// Maximum allowed established inbound connections. + pub max_established_inbound: Option, + /// Maximum allowed established outbound connections. + pub max_established_outbound: Option, } impl SessionLimits { @@ -143,107 +144,10 @@ impl SessionLimits { } } -/// Keeps track of all sessions. -#[derive(Debug, Clone)] -pub struct SessionCounter { - /// Limits to enforce. - limits: SessionLimits, - /// Number of pending incoming sessions. - pending_inbound: u32, - /// Number of pending outgoing sessions. - pending_outbound: u32, - /// Number of active inbound sessions. - active_inbound: u32, - /// Number of active outbound sessions. - active_outbound: u32, -} - -// === impl SessionCounter === - -impl SessionCounter { - pub(crate) const fn new(limits: SessionLimits) -> Self { - Self { - limits, - pending_inbound: 0, - pending_outbound: 0, - active_inbound: 0, - active_outbound: 0, - } - } - - pub(crate) fn inc_pending_inbound(&mut self) { - self.pending_inbound += 1; - } - - pub(crate) fn inc_pending_outbound(&mut self) { - self.pending_outbound += 1; - } - - pub(crate) fn dec_pending(&mut self, direction: &Direction) { - match direction { - Direction::Outgoing(_) => { - self.pending_outbound -= 1; - } - Direction::Incoming => { - self.pending_inbound -= 1; - } - } - } - - pub(crate) fn inc_active(&mut self, direction: &Direction) { - match direction { - Direction::Outgoing(_) => { - self.active_outbound += 1; - } - Direction::Incoming => { - self.active_inbound += 1; - } - } - } - - pub(crate) fn dec_active(&mut self, direction: &Direction) { - match direction { - Direction::Outgoing(_) => { - self.active_outbound -= 1; - } - Direction::Incoming => { - self.active_inbound -= 1; - } - } - } - - pub(crate) const fn ensure_pending_outbound(&self) -> Result<(), ExceedsSessionLimit> { - Self::ensure(self.pending_outbound, self.limits.max_pending_outbound) - } - - pub(crate) const fn ensure_pending_inbound(&self) -> Result<(), ExceedsSessionLimit> { - Self::ensure(self.pending_inbound, self.limits.max_pending_inbound) - } - - const fn ensure(current: u32, limit: Option) -> Result<(), ExceedsSessionLimit> { - if let Some(limit) = limit { - if current >= limit { - return Err(ExceedsSessionLimit(limit)) - } - } - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; - #[test] - fn test_limits() { - let mut limits = SessionCounter::new(SessionLimits::default().with_max_pending_inbound(2)); - assert!(limits.ensure_pending_outbound().is_ok()); - limits.inc_pending_inbound(); - assert!(limits.ensure_pending_inbound().is_ok()); - limits.inc_pending_inbound(); - assert!(limits.ensure_pending_inbound().is_err()); - } - #[test] fn scale_session_event_buffer() { let config = SessionsConfig::default().with_upscaled_event_buffer(10); diff --git a/crates/net/network-types/src/session/mod.rs b/crates/net/network-types/src/session/mod.rs new file mode 100644 index 000000000000..a5b613189c02 --- /dev/null +++ b/crates/net/network-types/src/session/mod.rs @@ -0,0 +1,4 @@ +//! Peer sessions configuration. + +pub mod config; +pub use config::{SessionLimits, SessionsConfig}; diff --git a/crates/net/network/Cargo.toml b/crates/net/network/Cargo.toml index 1dde28cfe2cf..d61caa7bec96 100644 --- a/crates/net/network/Cargo.toml +++ b/crates/net/network/Cargo.toml @@ -29,6 +29,7 @@ reth-provider.workspace = true reth-tokio-util.workspace = true reth-consensus.workspace = true reth-network-peers.workspace = true +reth-network-types.workspace = true # ethereum enr = { workspace = true, features = ["serde", "rust-secp256k1"] } @@ -75,6 +76,7 @@ reth-primitives = { workspace = true, features = ["test-utils"] } # integration tests reth-network = { workspace = true, features = ["test-utils"] } reth-network-p2p = { workspace = true, features = ["test-utils"] } +reth-network-types = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-tracing.workspace = true @@ -95,8 +97,8 @@ criterion = { workspace = true, features = ["async_tokio", "html_reports"] } [features] default = ["serde"] geth-tests = [] -serde = ["dep:serde", "dep:humantime-serde", "secp256k1/serde", "enr/serde", "dep:serde_json"] -test-utils = ["reth-provider/test-utils", "dep:tempfile", "reth-transaction-pool/test-utils"] +serde = ["dep:serde", "dep:humantime-serde", "secp256k1/serde", "enr/serde", "dep:serde_json", "reth-network-types/serde"] +test-utils = ["reth-provider/test-utils", "dep:tempfile", "reth-transaction-pool/test-utils", "reth-network-types/test-utils"] [[bench]] name = "bench" diff --git a/crates/net/network/src/config.rs b/crates/net/network/src/config.rs index 151421b4a5de..b6c95521245c 100644 --- a/crates/net/network/src/config.rs +++ b/crates/net/network/src/config.rs @@ -3,20 +3,16 @@ use crate::{ error::NetworkError, import::{BlockImport, ProofOfStakeBlockImport}, - peers::PeersConfig, - session::SessionsConfig, transactions::TransactionsManagerConfig, NetworkHandle, NetworkManager, }; -use reth_chainspec::{ - net::{mainnet_nodes, sepolia_nodes, TrustedPeer}, - ChainSpec, MAINNET, -}; +use reth_chainspec::{ChainSpec, MAINNET}; use reth_discv4::{Discv4Config, Discv4ConfigBuilder, NatResolver, DEFAULT_DISCOVERY_ADDRESS}; use reth_discv5::NetworkStackId; use reth_dns_discovery::DnsDiscoveryConfig; use reth_eth_wire::{HelloMessage, HelloMessageWithProtocols, Status}; -use reth_network_peers::{pk2id, PeerId}; +use reth_network_peers::{mainnet_nodes, pk2id, sepolia_nodes, PeerId, TrustedPeer}; +use reth_network_types::{PeersConfig, SessionsConfig}; use reth_primitives::{ForkFilter, Head}; use reth_provider::{BlockReader, HeaderProvider}; use reth_tasks::{TaskSpawner, TokioTaskExecutor}; @@ -411,36 +407,6 @@ impl NetworkConfigBuilder { } } - /// Calls a closure on [`reth_discv5::ConfigBuilder`], if discv5 discovery is enabled and the - /// builder has been set. - /// ``` - /// use reth_chainspec::MAINNET; - /// use reth_network::NetworkConfigBuilder; - /// use reth_provider::test_utils::NoopProvider; - /// use secp256k1::{rand::thread_rng, SecretKey}; - /// - /// let sk = SecretKey::new(&mut thread_rng()); - /// let fork_id = MAINNET.latest_fork_id(); - /// let network_config = NetworkConfigBuilder::new(sk) - /// .map_discv5_config_builder(|builder| builder.fork(b"eth", fork_id)) - /// .build(NoopProvider::default()); - /// ``` - pub fn map_discv5_config_builder( - mut self, - f: impl FnOnce(reth_discv5::ConfigBuilder) -> reth_discv5::ConfigBuilder, - ) -> Self { - if let Some(mut builder) = self.discovery_v5_builder { - if let Some(network_stack_id) = NetworkStackId::id(&self.chain_spec) { - let fork_id = self.chain_spec.latest_fork_id(); - builder = builder.fork(network_stack_id, fork_id); - } - - self.discovery_v5_builder = Some(f(builder)); - } - - self - } - /// Adds a new additional protocol to the `RLPx` sub-protocol list. pub fn add_rlpx_sub_protocol(mut self, protocol: impl IntoRlpxSubProtocol) -> Self { self.extra_protocols.push(protocol); @@ -480,7 +446,7 @@ impl NetworkConfigBuilder { secret_key, mut dns_discovery_config, discovery_v4_builder, - discovery_v5_builder, + mut discovery_v5_builder, boot_nodes, discovery_addr, listener_addr, @@ -497,6 +463,15 @@ impl NetworkConfigBuilder { transactions_manager_config, } = self; + discovery_v5_builder = discovery_v5_builder.map(|mut builder| { + if let Some(network_stack_id) = NetworkStackId::id(&chain_spec) { + let fork_id = chain_spec.latest_fork_id(); + builder = builder.fork(network_stack_id, fork_id) + } + + builder + }); + let listener_addr = listener_addr.unwrap_or(DEFAULT_DISCOVERY_ADDRESS); let mut hello_message = @@ -585,7 +560,6 @@ mod tests { use reth_dns_discovery::tree::LinkEntry; use reth_primitives::ForkHash; use reth_provider::test_utils::NoopProvider; - use std::collections::BTreeMap; fn builder() -> NetworkConfigBuilder { let secret_key = SecretKey::new(&mut thread_rng()); @@ -609,7 +583,7 @@ mod tests { let mut chain_spec = Arc::clone(&MAINNET); // remove any `next` fields we would have by removing all hardforks - Arc::make_mut(&mut chain_spec).hardforks = BTreeMap::new(); + Arc::make_mut(&mut chain_spec).hardforks = Default::default(); // check that the forkid is initialized with the genesis and no other forks let genesis_fork_hash = ForkHash::from(chain_spec.genesis_hash()); diff --git a/crates/net/network/src/discovery.rs b/crates/net/network/src/discovery.rs index c320c7fe1575..2e51a6b71cb4 100644 --- a/crates/net/network/src/discovery.rs +++ b/crates/net/network/src/discovery.rs @@ -4,6 +4,7 @@ use crate::{ cache::LruMap, error::{NetworkError, ServiceKind}, manager::DiscoveredEvent, + peers::PeerAddr, }; use enr::Enr; use futures::StreamExt; @@ -40,7 +41,7 @@ pub struct Discovery { /// All nodes discovered via discovery protocol. /// /// These nodes can be ephemeral and are updated via the discovery protocol. - discovered_nodes: LruMap, + discovered_nodes: LruMap, /// Local ENR of the discovery v4 service (discv5 ENR has same [`PeerId`]). local_enr: NodeRecord, /// Handler to interact with the Discovery v4 service @@ -204,12 +205,14 @@ impl Discovery { /// Processes an incoming [`NodeRecord`] update from a discovery service fn on_node_record_update(&mut self, record: NodeRecord, fork_id: Option) { - let id = record.id; - let addr = record.tcp_addr(); + let peer_id = record.id; + let tcp_addr = record.tcp_addr(); + let udp_addr = record.udp_addr(); + let addr = PeerAddr::new(tcp_addr, Some(udp_addr)); _ = - self.discovered_nodes.get_or_insert(id, || { + self.discovered_nodes.get_or_insert(peer_id, || { self.queued_events.push_back(DiscoveryEvent::NewNode( - DiscoveredEvent::EventQueued { peer_id: id, socket_addr: addr, fork_id }, + DiscoveredEvent::EventQueued { peer_id, addr, fork_id }, )); addr @@ -224,8 +227,8 @@ impl Discovery { DiscoveryUpdate::EnrForkId(node, fork_id) => { self.queued_events.push_back(DiscoveryEvent::EnrForkId(node.id, fork_id)) } - DiscoveryUpdate::Removed(node) => { - self.discovered_nodes.remove(&node); + DiscoveryUpdate::Removed(peer_id) => { + self.discovered_nodes.remove(&peer_id); } DiscoveryUpdate::Batch(updates) => { for update in updates { @@ -427,7 +430,7 @@ mod tests { assert_eq!( DiscoveryEvent::NewNode(DiscoveredEvent::EventQueued { peer_id: discv4_id_2, - socket_addr: discv4_enr_2.tcp_addr(), + addr: PeerAddr::new(discv4_enr_2.tcp_addr(), Some(discv4_enr_2.udp_addr())), fork_id: None }), event_node_1 @@ -435,7 +438,7 @@ mod tests { assert_eq!( DiscoveryEvent::NewNode(DiscoveredEvent::EventQueued { peer_id: discv4_id_1, - socket_addr: discv4_enr_1.tcp_addr(), + addr: PeerAddr::new(discv4_enr_1.tcp_addr(), Some(discv4_enr_1.udp_addr())), fork_id: None }), event_node_2 diff --git a/crates/net/network/src/error.rs b/crates/net/network/src/error.rs index 9019a79f2371..d5e0f453721d 100644 --- a/crates/net/network/src/error.rs +++ b/crates/net/network/src/error.rs @@ -6,6 +6,7 @@ use reth_eth_wire::{ errors::{EthHandshakeError, EthStreamError, P2PHandshakeError, P2PStreamError}, DisconnectReason, }; +use reth_network_types::BackoffKind; use std::{fmt, io, io::ErrorKind, net::SocketAddr}; /// Service kind. @@ -104,34 +105,6 @@ pub(crate) trait SessionError: fmt::Debug + fmt::Display { fn should_backoff(&self) -> Option; } -/// Describes the type of backoff should be applied. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum BackoffKind { - /// Use the lowest configured backoff duration. - /// - /// This applies to connection problems where there is a chance that they will be resolved - /// after the short duration. - Low, - /// Use a slightly higher duration to put a peer in timeout - /// - /// This applies to more severe connection problems where there is a lower chance that they - /// will be resolved. - Medium, - /// Use the max configured backoff duration. - /// - /// This is intended for spammers, or bad peers in general. - High, -} - -// === impl BackoffKind === - -impl BackoffKind { - /// Returns true if the backoff is considered severe. - pub(crate) const fn is_severe(&self) -> bool { - matches!(self, Self::Medium | Self::High) - } -} - impl SessionError for EthStreamError { fn merits_discovery_ban(&self) -> bool { match self { diff --git a/crates/net/network/src/eth_requests.rs b/crates/net/network/src/eth_requests.rs index 2e403a517dc0..3b7e9500e077 100644 --- a/crates/net/network/src/eth_requests.rs +++ b/crates/net/network/src/eth_requests.rs @@ -66,8 +66,12 @@ pub struct EthRequestHandler { impl EthRequestHandler { /// Create a new instance pub fn new(client: C, peers: PeersHandle, incoming: Receiver) -> Self { - let metrics = Default::default(); - Self { client, peers, incoming_requests: ReceiverStream::new(incoming), metrics } + Self { + client, + peers, + incoming_requests: ReceiverStream::new(incoming), + metrics: Default::default(), + } } } @@ -124,11 +128,7 @@ where total_bytes += header.length(); headers.push(header); - if headers.len() >= MAX_HEADERS_SERVE { - break - } - - if total_bytes > SOFT_RESPONSE_LIMIT { + if headers.len() >= MAX_HEADERS_SERVE || total_bytes > SOFT_RESPONSE_LIMIT { break } } else { @@ -163,21 +163,12 @@ where for hash in request.0 { if let Some(block) = self.client.block_by_hash(hash).unwrap_or_default() { - let body = BlockBody { - transactions: block.body, - ommers: block.ommers, - withdrawals: block.withdrawals, - requests: block.requests, - }; + let body: BlockBody = block.into(); total_bytes += body.length(); bodies.push(body); - if bodies.len() >= MAX_BODIES_SERVE { - break - } - - if total_bytes > SOFT_RESPONSE_LIMIT { + if bodies.len() >= MAX_BODIES_SERVE || total_bytes > SOFT_RESPONSE_LIMIT { break } } else { @@ -212,11 +203,7 @@ where total_bytes += receipt.length(); receipts.push(receipt); - if receipts.len() >= MAX_RECEIPTS_SERVE { - break - } - - if total_bytes > SOFT_RESPONSE_LIMIT { + if receipts.len() >= MAX_RECEIPTS_SERVE || total_bytes > SOFT_RESPONSE_LIMIT { break } } else { diff --git a/crates/net/network/src/lib.rs b/crates/net/network/src/lib.rs index b8f3f8be1697..f14f6e850416 100644 --- a/crates/net/network/src/lib.rs +++ b/crates/net/network/src/lib.rs @@ -46,8 +46,8 @@ //! //! ``` //! # async fn launch() { -//! use reth_chainspec::net::mainnet_nodes; //! use reth_network::{config::rng_secret_key, NetworkConfig, NetworkManager}; +//! use reth_network_peers::mainnet_nodes; //! use reth_provider::test_utils::NoopProvider; //! //! // This block provider implementation is used for testing purposes. @@ -71,8 +71,8 @@ //! ### Configure all components of the Network with the [`NetworkBuilder`] //! //! ``` -//! use reth_chainspec::net::mainnet_nodes; //! use reth_network::{config::rng_secret_key, NetworkConfig, NetworkManager}; +//! use reth_network_peers::mainnet_nodes; //! use reth_provider::test_utils::NoopProvider; //! use reth_transaction_pool::TransactionPool; //! async fn launch(pool: Pool) { @@ -143,12 +143,12 @@ pub use fetch::FetchClient; pub use manager::{NetworkEvent, NetworkManager}; pub use message::PeerRequest; pub use network::{NetworkEvents, NetworkHandle, NetworkProtocols}; -pub use peers::PeersConfig; pub use session::{ ActiveSessionHandle, ActiveSessionMessage, Direction, PeerInfo, PendingSessionEvent, PendingSessionHandle, PendingSessionHandshakeError, SessionCommand, SessionEvent, SessionId, - SessionLimits, SessionManager, SessionsConfig, + SessionManager, }; pub use transactions::{FilterAnnouncement, MessageFilter, ValidateTx68}; pub use reth_eth_wire::{DisconnectReason, HelloMessageWithProtocols}; +pub use reth_network_types::{PeersConfig, SessionsConfig}; diff --git a/crates/net/network/src/manager.rs b/crates/net/network/src/manager.rs index 17827444bc20..b3fa43252ec1 100644 --- a/crates/net/network/src/manager.rs +++ b/crates/net/network/src/manager.rs @@ -26,7 +26,7 @@ use crate::{ message::{NewBlockMessage, PeerMessage, PeerRequest, PeerRequestSender}, metrics::{DisconnectMetrics, NetworkMetrics, NETWORK_POOL_TRANSACTIONS_SCOPE}, network::{NetworkHandle, NetworkHandleMessage}, - peers::{PeersHandle, PeersManager}, + peers::{PeerAddr, PeersHandle, PeersManager}, poll_nested_stream_with_budget, protocol::IntoRlpxSubProtocol, session::SessionManager, @@ -280,8 +280,8 @@ where /// components of the network /// /// ``` - /// use reth_chainspec::net::mainnet_nodes; /// use reth_network::{config::rng_secret_key, NetworkConfig, NetworkManager}; + /// use reth_network_peers::mainnet_nodes; /// use reth_provider::test_utils::NoopProvider; /// use reth_transaction_pool::TransactionPool; /// async fn launch(pool: Pool) { @@ -562,7 +562,7 @@ where } } NetworkHandleMessage::RemovePeer(peer_id, kind) => { - self.swarm.state_mut().remove_peer(peer_id, kind); + self.swarm.state_mut().remove_peer_kind(peer_id, kind); } NetworkHandleMessage::DisconnectPeer(peer_id, reason) => { self.swarm.sessions_mut().disconnect(peer_id, reason); @@ -1030,7 +1030,7 @@ pub enum NetworkEvent { #[derive(Debug, Clone, PartialEq, Eq)] pub enum DiscoveredEvent { - EventQueued { peer_id: PeerId, socket_addr: SocketAddr, fork_id: Option }, + EventQueued { peer_id: PeerId, addr: PeerAddr, fork_id: Option }, } #[derive(Debug, Default)] diff --git a/crates/net/network/src/network.rs b/crates/net/network/src/network.rs index 632a6028795a..ab092a164406 100644 --- a/crates/net/network/src/network.rs +++ b/crates/net/network/src/network.rs @@ -1,7 +1,13 @@ use crate::{ - config::NetworkMode, discovery::DiscoveryEvent, manager::NetworkEvent, message::PeerRequest, - peers::PeersHandle, protocol::RlpxSubProtocol, swarm::NetworkConnectionState, - transactions::TransactionsHandle, FetchClient, + config::NetworkMode, + discovery::DiscoveryEvent, + manager::NetworkEvent, + message::PeerRequest, + peers::{PeerAddr, PeersHandle}, + protocol::RlpxSubProtocol, + swarm::NetworkConnectionState, + transactions::TransactionsHandle, + FetchClient, }; use enr::Enr; use parking_lot::Mutex; @@ -257,7 +263,14 @@ impl Peers for NetworkHandle { /// Sends a message to the [`NetworkManager`](crate::NetworkManager) to add a peer to the known /// set, with the given kind. - fn add_peer_kind(&self, peer: PeerId, kind: PeerKind, addr: SocketAddr) { + fn add_peer_kind( + &self, + peer: PeerId, + kind: PeerKind, + tcp_addr: SocketAddr, + udp_addr: Option, + ) { + let addr = PeerAddr::new(tcp_addr, udp_addr); self.send_message(NetworkHandleMessage::AddPeerAddress(peer, kind, addr)); } @@ -420,7 +433,7 @@ pub(crate) enum NetworkHandleMessage { /// Marks a peer as trusted. AddTrustedPeerId(PeerId), /// Adds an address for a peer, including its ID, kind, and socket address. - AddPeerAddress(PeerId, PeerKind, SocketAddr), + AddPeerAddress(PeerId, PeerKind, PeerAddr), /// Removes a peer from the peerset corresponding to the given kind. RemovePeer(PeerId, PeerKind), /// Disconnects a connection to a peer if it exists, optionally providing a disconnect reason. diff --git a/crates/net/network/src/peers/manager.rs b/crates/net/network/src/peers.rs similarity index 84% rename from crates/net/network/src/peers/manager.rs rename to crates/net/network/src/peers.rs index bde0bd066f07..ca80faf5c1bb 100644 --- a/crates/net/network/src/peers/manager.rs +++ b/crates/net/network/src/peers.rs @@ -1,12 +1,7 @@ +//! Peer related implementations + use crate::{ - error::{BackoffKind, SessionError}, - peers::{ - reputation::{ - is_banned_reputation, DEFAULT_REPUTATION, MAX_TRUSTED_PEER_REPUTATION_CHANGE, - }, - ReputationChangeWeights, DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS, - DEFAULT_MAX_COUNT_PEERS_INBOUND, DEFAULT_MAX_COUNT_PEERS_OUTBOUND, - }, + error::SessionError, session::{Direction, PendingSessionHandshakeError}, swarm::NetworkConnectionState, }; @@ -15,13 +10,21 @@ use reth_eth_wire::{errors::EthStreamError, DisconnectReason}; use reth_net_banlist::BanList; use reth_network_api::{PeerKind, ReputationChangeKind}; use reth_network_peers::{NodeRecord, PeerId}; +use reth_network_types::{ + peers::{ + config::PeerBackoffDurations, + reputation::{ + is_banned_reputation, DEFAULT_REPUTATION, MAX_TRUSTED_PEER_REPUTATION_CHANGE, + }, + }, + ConnectionsConfig, PeersConfig, ReputationChangeWeights, +}; use reth_primitives::ForkId; use std::{ collections::{hash_map::Entry, HashMap, HashSet, VecDeque}, fmt::Display, - io::{self, ErrorKind}, + io::{self}, net::{IpAddr, SocketAddr}, - path::Path, task::{Context, Poll}, time::Duration, }; @@ -31,7 +34,7 @@ use tokio::{ time::{Instant, Interval}, }; use tokio_stream::wrappers::UnboundedReceiverStream; -use tracing::{info, trace}; +use tracing::trace; /// A communication channel to the [`PeersManager`] to apply manual changes to the peer set. #[derive(Clone, Debug)] @@ -152,13 +155,17 @@ impl PeersManager { let mut peers = HashMap::with_capacity(trusted_nodes.len() + basic_nodes.len()); let mut trusted_peer_ids = HashSet::with_capacity(trusted_nodes.len()); - for NodeRecord { address, tcp_port, udp_port: _, id } in trusted_nodes { + for NodeRecord { address, tcp_port, udp_port, id } in trusted_nodes { trusted_peer_ids.insert(id); - peers.entry(id).or_insert_with(|| Peer::trusted(SocketAddr::from((address, tcp_port)))); + peers.entry(id).or_insert_with(|| { + Peer::trusted(PeerAddr::new_with_ports(address, tcp_port, Some(udp_port))) + }); } - for NodeRecord { address, tcp_port, udp_port: _, id } in basic_nodes { - peers.entry(id).or_insert_with(|| Peer::new(SocketAddr::from((address, tcp_port)))); + for NodeRecord { address, tcp_port, udp_port, id } in basic_nodes { + peers.entry(id).or_insert_with(|| { + Peer::new(PeerAddr::new_with_ports(address, tcp_port, Some(udp_port))) + }); } Self { @@ -170,7 +177,7 @@ impl PeersManager { reputation_weights, refill_slots_interval: tokio::time::interval(refill_slots_interval), release_interval: tokio::time::interval_at(now + unban_interval, unban_interval), - connection_info, + connection_info: ConnectionInfo::new(connection_info), ban_list, backed_off_peers: Default::default(), ban_duration, @@ -195,7 +202,27 @@ impl PeersManager { /// Returns an iterator over all peers pub(crate) fn iter_peers(&self) -> impl Iterator + '_ { - self.peers.iter().map(|(peer_id, v)| NodeRecord::new(v.addr, *peer_id)) + self.peers.iter().map(|(peer_id, v)| { + NodeRecord::new_with_ports( + v.addr.tcp.ip(), + v.addr.tcp.port(), + v.addr.udp.map(|addr| addr.port()), + *peer_id, + ) + }) + } + + /// Returns the [`NodeRecord`] for the given peer id + #[allow(dead_code)] + fn peer_by_id(&self, peer_id: PeerId) -> Option { + self.peers.get(&peer_id).map(|v| { + NodeRecord::new_with_ports( + v.addr.tcp.ip(), + v.addr.tcp.port(), + v.addr.udp.map(|addr| addr.port()), + peer_id, + ) + }) } /// Returns an iterator over all peer ids for peers with the given kind @@ -238,9 +265,7 @@ impl PeersManager { return Err(InboundConnectionError::IpBanned) } - if (!self.connection_info.has_in_capacity() || self.connection_info.max_inbound == 0) && - self.trusted_peer_ids.is_empty() - { + if !self.connection_info.has_in_capacity() && self.trusted_peer_ids.is_empty() { // if we don't have any inbound slots and no trusted peers, we don't accept any new // connections return Err(InboundConnectionError::ExceedsCapacity) @@ -324,33 +349,24 @@ impl PeersManager { peer.state = PeerConnectionState::In; is_trusted = is_trusted || peer.is_trusted(); - - // if a peer is not trusted and we don't have capacity for more inbound connections, - // disconnecting the peer - if !is_trusted && !has_in_capacity { - self.queued_actions.push_back(PeerAction::Disconnect { - peer_id, - reason: Some(DisconnectReason::TooManyPeers), - }); - } } Entry::Vacant(entry) => { // peer is missing in the table, we add it but mark it as to be removed after // disconnect, because we only know the outgoing port - let mut peer = Peer::with_state(addr, PeerConnectionState::In); + let mut peer = Peer::with_state(PeerAddr::tcp(addr), PeerConnectionState::In); peer.remove_after_disconnect = true; entry.insert(peer); self.queued_actions.push_back(PeerAction::PeerAdded(peer_id)); - - // disconnect the peer if we don't have capacity for more inbound connections - if !is_trusted && !has_in_capacity { - self.queued_actions.push_back(PeerAction::Disconnect { - peer_id, - reason: Some(DisconnectReason::TooManyPeers), - }); - } } } + + // disconnect the peer if we don't have capacity for more inbound connections + if !is_trusted && !has_in_capacity { + self.queued_actions.push_back(PeerAction::Disconnect { + peer_id, + reason: Some(DisconnectReason::TooManyPeers), + }); + } } /// Bans the peer temporarily with the configured ban timeout @@ -662,7 +678,7 @@ impl PeersManager { /// Called for a newly discovered peer. /// /// If the peer already exists, then the address, kind and `fork_id` will be updated. - pub(crate) fn add_peer(&mut self, peer_id: PeerId, addr: SocketAddr, fork_id: Option) { + pub(crate) fn add_peer(&mut self, peer_id: PeerId, addr: PeerAddr, fork_id: Option) { self.add_peer_kind(peer_id, PeerKind::Basic, addr, fork_id) } @@ -675,7 +691,7 @@ impl PeersManager { /// /// If the peer already exists, then the address and kind will be updated. #[allow(dead_code)] - pub(crate) fn add_trusted_peer(&mut self, peer_id: PeerId, addr: SocketAddr) { + pub(crate) fn add_trusted_peer(&mut self, peer_id: PeerId, addr: PeerAddr) { self.add_peer_kind(peer_id, PeerKind::Trusted, addr, None) } @@ -686,10 +702,10 @@ impl PeersManager { &mut self, peer_id: PeerId, kind: PeerKind, - addr: SocketAddr, + addr: PeerAddr, fork_id: Option, ) { - if self.ban_list.is_banned(&peer_id, &addr.ip()) { + if self.ban_list.is_banned(&peer_id, &addr.tcp.ip()) { return } @@ -708,7 +724,7 @@ impl PeersManager { } } Entry::Vacant(entry) => { - trace!(target: "net::peers", ?peer_id, ?addr, "discovered new node"); + trace!(target: "net::peers", ?peer_id, ?addr.tcp, "discovered new node"); let mut peer = Peer::with_kind(addr, kind); peer.fork_id = fork_id; entry.insert(peer); @@ -812,7 +828,7 @@ impl PeersManager { return } - // as long as there a slots available fill them with the best peers + // as long as there are slots available fill them with the best peers while self.connection_info.has_out_capacity() { let action = { let (peer_id, peer) = match self.best_unconnected() { @@ -823,7 +839,7 @@ impl PeersManager { trace!(target: "net::peers", ?peer_id, addr=?peer.addr, "schedule outbound connection"); peer.state = PeerConnectionState::PendingOut; - PeerAction::Connect { peer_id, remote_addr: peer.addr } + PeerAction::Connect { peer_id, remote_addr: peer.addr.tcp } }; self.connection_info.inc_pending_out(); @@ -861,7 +877,7 @@ impl PeersManager { while let Poll::Ready(Some(cmd)) = self.handle_rx.poll_next_unpin(cx) { match cmd { PeerCommand::Add(peer_id, addr) => { - self.add_peer(peer_id, addr, None); + self.add_peer(peer_id, PeerAddr::tcp(addr), None); } PeerCommand::Remove(peer) => self.remove_peer(peer), PeerCommand::ReputationChange(peer_id, rep) => { @@ -918,42 +934,37 @@ impl Default for PeersManager { } /// Tracks stats about connected nodes -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(default))] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct ConnectionInfo { /// Counter for currently occupied slots for active outbound connections. - #[cfg_attr(feature = "serde", serde(skip))] num_outbound: usize, /// Counter for pending outbound connections. - #[cfg_attr(feature = "serde", serde(skip))] num_pending_out: usize, /// Counter for currently occupied slots for active inbound connections. - #[cfg_attr(feature = "serde", serde(skip))] num_inbound: usize, /// Counter for pending inbound connections. - #[cfg_attr(feature = "serde", serde(skip))] num_pending_in: usize, - /// Maximum allowed outbound connections. - max_outbound: usize, - /// Maximum allowed inbound connections. - max_inbound: usize, - /// Maximum allowed concurrent outbound dials. - #[cfg_attr(feature = "serde", serde(default))] - max_concurrent_outbound_dials: usize, + /// Restrictions on number of connections. + config: ConnectionsConfig, } // === impl ConnectionInfo === impl ConnectionInfo { + /// Returns a new [`ConnectionInfo`] with the given config. + const fn new(config: ConnectionsConfig) -> Self { + Self { config, num_outbound: 0, num_pending_out: 0, num_inbound: 0, num_pending_in: 0 } + } + /// Returns `true` if there's still capacity for a new outgoing connection. const fn has_out_capacity(&self) -> bool { - self.num_pending_out < self.max_concurrent_outbound_dials && - self.num_outbound < self.max_outbound + self.num_pending_out < self.config.max_concurrent_outbound_dials && + self.num_outbound < self.config.max_outbound } /// Returns `true` if there's still capacity for a new incoming connection. const fn has_in_capacity(&self) -> bool { - self.num_inbound < self.max_inbound + self.num_inbound < self.config.max_inbound } fn decr_state(&mut self, state: PeerConnectionState) { @@ -998,25 +1009,43 @@ impl ConnectionInfo { } } -impl Default for ConnectionInfo { - fn default() -> Self { - Self { - num_outbound: 0, - num_inbound: 0, - max_outbound: DEFAULT_MAX_COUNT_PEERS_OUTBOUND as usize, - max_inbound: DEFAULT_MAX_COUNT_PEERS_INBOUND as usize, - max_concurrent_outbound_dials: DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS, - num_pending_out: 0, - num_pending_in: 0, - } +/// Represents a peer's address information. +/// +/// # Fields +/// +/// - `tcp`: A `SocketAddr` representing the peer's data transfer address. +/// - `udp`: An optional `SocketAddr` representing the peer's discover address. `None` if the peer +/// is directly connecting to us or the port is the same to `tcp`'s +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct PeerAddr { + tcp: SocketAddr, + udp: Option, +} + +impl PeerAddr { + /// Returns a new `PeerAddr` with the given `tcp` and `udp` addresses. + pub const fn new(tcp: SocketAddr, udp: Option) -> Self { + Self { tcp, udp } + } + + /// Returns a new `PeerAddr` with a `tcp` address only. + pub const fn tcp(tcp: SocketAddr) -> Self { + Self { tcp, udp: None } + } + + /// Returns a new `PeerAddr` with the given `tcp` and `udp` ports. + fn new_with_ports(ip: IpAddr, tcp_port: u16, udp_port: Option) -> Self { + let tcp = SocketAddr::new(ip, tcp_port); + let udp = udp_port.map(|port| SocketAddr::new(ip, port)); + Self::new(tcp, udp) } } /// Tracks info about a single peer. #[derive(Debug, Clone)] pub struct Peer { - /// Where to reach the peer - addr: SocketAddr, + /// Where to reach the peer. + addr: PeerAddr, /// Reputation of the peer. reputation: i32, /// The state of the connection, if any. @@ -1029,18 +1058,19 @@ pub struct Peer { kind: PeerKind, /// Whether the peer is currently backed off. backed_off: bool, - /// Counts number of times the peer was backed off due to a severe [`BackoffKind`]. + /// Counts number of times the peer was backed off due to a severe + /// [`reth_network_types::BackoffKind`]. severe_backoff_counter: u8, } // === impl Peer === impl Peer { - fn new(addr: SocketAddr) -> Self { + fn new(addr: PeerAddr) -> Self { Self::with_state(addr, Default::default()) } - fn trusted(addr: SocketAddr) -> Self { + fn trusted(addr: PeerAddr) -> Self { Self { kind: PeerKind::Trusted, ..Self::new(addr) } } @@ -1049,7 +1079,7 @@ impl Peer { self.reputation } - fn with_state(addr: SocketAddr, state: PeerConnectionState) -> Self { + fn with_state(addr: PeerAddr, state: PeerConnectionState) -> Self { Self { addr, state, @@ -1062,7 +1092,7 @@ impl Peer { } } - fn with_kind(addr: SocketAddr, kind: PeerKind) -> Self { + fn with_kind(addr: PeerAddr, kind: PeerKind) -> Self { Self { kind, ..Self::new(addr) } } @@ -1263,265 +1293,6 @@ pub enum PeerAction { PeerRemoved(PeerId), } -/// Config type for initiating a [`PeersManager`] instance. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(default))] -pub struct PeersConfig { - /// How often to recheck free slots for outbound connections. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub refill_slots_interval: Duration, - /// Trusted nodes to connect to or accept from - pub trusted_nodes: HashSet, - /// Connect to or accept from trusted nodes only? - #[cfg_attr(feature = "serde", serde(alias = "connect_trusted_nodes_only"))] - pub trusted_nodes_only: bool, - /// Maximum number of backoff attempts before we give up on a peer and dropping. - /// - /// The max time spent of a peer before it's removed from the set is determined by the - /// configured backoff duration and the max backoff count. - /// - /// With a backoff counter of 5 and a backoff duration of 1h, the minimum time spent of the - /// peer in the table is the sum of all backoffs (1h + 2h + 3h + 4h + 5h = 15h). - /// - /// Note: this does not apply to trusted peers. - pub max_backoff_count: u8, - /// Basic nodes to connect to. - #[cfg_attr(feature = "serde", serde(skip))] - pub basic_nodes: HashSet, - /// How long to ban bad peers. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub ban_duration: Duration, - /// Restrictions on `PeerIds` and Ips. - #[cfg_attr(feature = "serde", serde(skip))] - pub ban_list: BanList, - /// Restrictions on connections. - pub connection_info: ConnectionInfo, - /// How to weigh reputation changes. - pub reputation_weights: ReputationChangeWeights, - /// How long to backoff peers that are we failed to connect to for non-fatal reasons, such as - /// [`DisconnectReason::TooManyPeers`]. - /// - /// The backoff duration increases with number of backoff attempts. - pub backoff_durations: PeerBackoffDurations, -} - -impl Default for PeersConfig { - fn default() -> Self { - Self { - refill_slots_interval: Duration::from_millis(5_000), - connection_info: Default::default(), - reputation_weights: Default::default(), - ban_list: Default::default(), - // Ban peers for 12h - ban_duration: Duration::from_secs(60 * 60 * 12), - backoff_durations: Default::default(), - trusted_nodes: Default::default(), - trusted_nodes_only: false, - basic_nodes: Default::default(), - max_backoff_count: 5, - } - } -} - -impl PeersConfig { - /// A set of `peer_ids` and ip addr that we want to never connect to - pub fn with_ban_list(mut self, ban_list: BanList) -> Self { - self.ban_list = ban_list; - self - } - - /// Configure how long to ban bad peers - pub const fn with_ban_duration(mut self, ban_duration: Duration) -> Self { - self.ban_duration = ban_duration; - self - } - - /// Maximum occupied slots for outbound connections. - pub const fn with_max_pending_outbound(mut self, num_outbound: usize) -> Self { - self.connection_info.num_outbound = num_outbound; - self - } - - /// Maximum occupied slots for inbound connections. - pub const fn with_max_pending_inbound(mut self, num_inbound: usize) -> Self { - self.connection_info.num_inbound = num_inbound; - self - } - - /// Maximum allowed outbound connections. - pub const fn with_max_outbound(mut self, max_outbound: usize) -> Self { - self.connection_info.max_outbound = max_outbound; - self - } - - /// Maximum allowed inbound connections with optional update. - pub const fn with_max_inbound_opt(mut self, max_inbound: Option) -> Self { - if let Some(max_inbound) = max_inbound { - self.connection_info.max_inbound = max_inbound; - } - self - } - - /// Maximum allowed outbound connections with optional update. - pub const fn with_max_outbound_opt(mut self, max_outbound: Option) -> Self { - if let Some(max_outbound) = max_outbound { - self.connection_info.max_outbound = max_outbound; - } - self - } - - /// Maximum allowed inbound connections. - pub const fn with_max_inbound(mut self, max_inbound: usize) -> Self { - self.connection_info.max_inbound = max_inbound; - self - } - - /// Maximum allowed concurrent outbound dials. - pub const fn with_max_concurrent_dials(mut self, max_concurrent_outbound_dials: usize) -> Self { - self.connection_info.max_concurrent_outbound_dials = max_concurrent_outbound_dials; - self - } - - /// Nodes to always connect to. - pub fn with_trusted_nodes(mut self, nodes: HashSet) -> Self { - self.trusted_nodes = nodes; - self - } - - /// Connect only to trusted nodes. - pub const fn with_trusted_nodes_only(mut self, trusted_only: bool) -> Self { - self.trusted_nodes_only = trusted_only; - self - } - - /// Nodes available at launch. - pub fn with_basic_nodes(mut self, nodes: HashSet) -> Self { - self.basic_nodes = nodes; - self - } - - /// Configures the max allowed backoff count. - pub const fn with_max_backoff_count(mut self, max_backoff_count: u8) -> Self { - self.max_backoff_count = max_backoff_count; - self - } - - /// Configures how to weigh reputation changes. - pub const fn with_reputation_weights( - mut self, - reputation_weights: ReputationChangeWeights, - ) -> Self { - self.reputation_weights = reputation_weights; - self - } - - /// Configures how long to backoff peers that are we failed to connect to for non-fatal reasons - pub const fn with_backoff_durations(mut self, backoff_durations: PeerBackoffDurations) -> Self { - self.backoff_durations = backoff_durations; - self - } - - /// Returns the maximum number of peers, inbound and outbound. - pub const fn max_peers(&self) -> usize { - self.connection_info.max_outbound + self.connection_info.max_inbound - } - - /// Read from file nodes available at launch. Ignored if None. - pub fn with_basic_nodes_from_file( - self, - optional_file: Option>, - ) -> Result { - let Some(file_path) = optional_file else { return Ok(self) }; - let reader = match std::fs::File::open(file_path.as_ref()) { - Ok(file) => io::BufReader::new(file), - Err(e) if e.kind() == ErrorKind::NotFound => return Ok(self), - Err(e) => Err(e)?, - }; - info!(target: "net::peers", file = %file_path.as_ref().display(), "Loading saved peers"); - let nodes: HashSet = serde_json::from_reader(reader)?; - Ok(self.with_basic_nodes(nodes)) - } - - /// Returns settings for testing - #[cfg(test)] - fn test() -> Self { - Self { - refill_slots_interval: Duration::from_millis(100), - backoff_durations: PeerBackoffDurations::test(), - ..Default::default() - } - } -} - -/// The durations to use when a backoff should be applied to a peer. -/// -/// See also [`BackoffKind`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct PeerBackoffDurations { - /// Applies to connection problems where there is a chance that they will be resolved after the - /// short duration. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub low: Duration, - /// Applies to more severe connection problems where there is a lower chance that they will be - /// resolved. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub medium: Duration, - /// Intended for spammers, or bad peers in general. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub high: Duration, - /// Maximum total backoff duration. - #[cfg_attr(feature = "serde", serde(with = "humantime_serde"))] - pub max: Duration, -} - -impl PeerBackoffDurations { - /// Returns the corresponding [`Duration`] - pub const fn backoff(&self, kind: BackoffKind) -> Duration { - match kind { - BackoffKind::Low => self.low, - BackoffKind::Medium => self.medium, - BackoffKind::High => self.high, - } - } - - /// Returns the timestamp until which we should backoff. - /// - /// The Backoff duration is capped by the configured maximum backoff duration. - pub fn backoff_until(&self, kind: BackoffKind, backoff_counter: u8) -> std::time::Instant { - let backoff_time = self.backoff(kind); - let backoff_time = backoff_time + backoff_time * backoff_counter as u32; - let now = std::time::Instant::now(); - now + backoff_time.min(self.max) - } - - /// Returns durations for testing. - #[cfg(test)] - const fn test() -> Self { - Self { - low: Duration::from_millis(200), - medium: Duration::from_millis(200), - high: Duration::from_millis(200), - max: Duration::from_millis(200), - } - } -} - -impl Default for PeerBackoffDurations { - fn default() -> Self { - Self { - low: Duration::from_secs(30), - // 3min - medium: Duration::from_secs(60 * 3), - // 15min - high: Duration::from_secs(60 * 15), - // 1h - max: Duration::from_secs(60 * 60), - } - } -} - /// Error thrown when a incoming connection is rejected right away #[derive(Debug, Error, PartialEq, Eq)] pub enum InboundConnectionError { @@ -1541,11 +1312,9 @@ impl Display for InboundConnectionError { mod tests { use super::PeersManager; use crate::{ - error::BackoffKind, peers::{ - manager::{ConnectionInfo, PeerBackoffDurations, PeerConnectionState}, - reputation::DEFAULT_REPUTATION, - InboundConnectionError, PeerAction, + ConnectionInfo, InboundConnectionError, PeerAction, PeerAddr, PeerBackoffDurations, + PeerConnectionState, }, session::PendingSessionHandshakeError, PeersConfig, @@ -1558,6 +1327,7 @@ mod tests { use reth_net_banlist::BanList; use reth_network_api::{Direction, ReputationChangeKind}; use reth_network_peers::PeerId; + use reth_network_types::{peers::reputation::DEFAULT_REPUTATION, BackoffKind}; use reth_primitives::B512; use std::{ collections::HashSet, @@ -1592,7 +1362,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -1607,6 +1377,37 @@ mod tests { } _ => unreachable!(), } + + let record = peers.peer_by_id(peer).unwrap(); + assert_eq!(record.tcp_addr(), socket_addr); + assert_eq!(record.udp_addr(), socket_addr); + } + + #[tokio::test] + async fn test_insert_udp() { + let peer = PeerId::random(); + let tcp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); + let udp_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8009); + let mut peers = PeersManager::default(); + peers.add_peer(peer, PeerAddr::new(tcp_addr, Some(udp_addr)), None); + + match event!(peers) { + PeerAction::PeerAdded(peer_id) => { + assert_eq!(peer_id, peer); + } + _ => unreachable!(), + } + match event!(peers) { + PeerAction::Connect { peer_id, remote_addr } => { + assert_eq!(peer_id, peer); + assert_eq!(remote_addr, tcp_addr); + } + _ => unreachable!(), + } + + let record = peers.peer_by_id(peer).unwrap(); + assert_eq!(record.tcp_addr(), tcp_addr); + assert_eq!(record.udp_addr(), udp_addr); } #[tokio::test] @@ -1615,7 +1416,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); peers.ban_peer(peer); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::BanPeer { peer_id } => { @@ -1637,7 +1438,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); peers.ban_peer(peer); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::BanPeer { peer_id } => { @@ -1674,7 +1475,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::new(PeersConfig::test()); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -1733,7 +1534,7 @@ mod tests { let backoff_durations = PeerBackoffDurations::test(); let config = PeersConfig { backoff_durations, ..PeersConfig::test() }; let mut peers = PeersManager::new(config); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -1790,7 +1591,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let config = PeersConfig::test(); let mut peers = PeersManager::new(config); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); let peer_struct = peers.peers.get_mut(&peer).unwrap(); let backoff_timestamp = peers @@ -1807,7 +1608,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let config = PeersConfig::default(); let mut peers = PeersManager::new(config); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); let peer_struct = peers.peers.get_mut(&peer).unwrap(); // Simulate a peer that was already backed off once @@ -1835,7 +1636,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -1892,7 +1693,7 @@ mod tests { let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let config = PeersConfig::test(); let mut peers = PeersManager::new(config.clone()); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); let peer_struct = peers.peers.get_mut(&peer).unwrap(); // Simulate a peer that was already backed off once @@ -1946,7 +1747,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2058,7 +1859,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2106,7 +1907,7 @@ mod tests { peers.add_trusted_peer_id(trusted); // saturate the inbound slots - for i in 0..peers.connection_info.max_inbound { + for i in 0..peers.connection_info.config.max_inbound { let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, i as u8)), 8008); assert!(peers.on_incoming_pending_session(socket_addr.ip()).is_ok()); let peer_id = PeerId::random(); @@ -2176,7 +1977,7 @@ mod tests { // to increase by 1 peers.on_incoming_session_established(peer, socket_addr); let p = peers.peers.get_mut(&peer).expect("peer not found"); - assert_eq!(p.addr, socket_addr); + assert_eq!(p.addr.tcp, socket_addr); assert_eq!(peers.connection_info.num_pending_in, 0); assert_eq!(peers.connection_info.num_inbound, 1); @@ -2191,7 +1992,7 @@ mod tests { peers.on_already_connected(Direction::Incoming); let p = peers.peers.get_mut(&peer).expect("peer not found"); - assert_eq!(p.addr, socket_addr); + assert_eq!(p.addr.tcp, socket_addr); assert_eq!(peers.connection_info.num_pending_in, 0); assert_eq!(peers.connection_info.num_inbound, 1); } @@ -2201,7 +2002,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_trusted_peer(peer, socket_addr); + peers.add_trusted_peer(peer, PeerAddr::tcp(socket_addr)); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2253,7 +2054,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); assert_eq!(peers.get_reputation(&peer), Some(0)); peers.apply_reputation_change(&peer, ReputationChangeKind::Other(1024)); @@ -2268,7 +2069,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2305,7 +2106,7 @@ mod tests { let p = peers.peers.get(&peer).unwrap(); assert_eq!(p.state, PeerConnectionState::PendingOut); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); let p = peers.peers.get(&peer).unwrap(); assert_eq!(p.state, PeerConnectionState::PendingOut); @@ -2318,7 +2119,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2353,7 +2154,7 @@ mod tests { let peer = PeerId::random(); let socket_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8008); let mut peers = PeersManager::default(); - peers.add_peer(peer, socket_addr, None); + peers.add_peer(peer, PeerAddr::tcp(socket_addr), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2387,7 +2188,7 @@ mod tests { let ban_list = BanList::new(HashSet::new(), vec![ip]); let config = PeersConfig::default().with_ban_list(ban_list); let mut peer_manager = PeersManager::new(config); - peer_manager.add_peer(B512::default(), socket_addr, None); + peer_manager.add_peer(B512::default(), PeerAddr::tcp(socket_addr), None); assert!(peer_manager.peers.is_empty()); } @@ -2404,7 +2205,7 @@ mod tests { match a { Ok(_) => panic!(), Err(err) => match err { - super::InboundConnectionError::IpBanned {} => { + InboundConnectionError::IpBanned {} => { assert_eq!(peer_manager.connection_info.num_pending_in, 0) } _ => unreachable!(), @@ -2490,7 +2291,7 @@ mod tests { let basic_peer = PeerId::random(); let basic_sock = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8009); - peers.add_peer(basic_peer, basic_sock, None); + peers.add_peer(basic_peer, PeerAddr::tcp(basic_sock), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2530,7 +2331,7 @@ mod tests { let basic_peer = PeerId::random(); let basic_sock = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)), 8009); - peers.add_peer(basic_peer, basic_sock, None); + peers.add_peer(basic_peer, PeerAddr::tcp(basic_sock), None); match event!(peers) { PeerAction::PeerAdded(peer_id) => { @@ -2638,7 +2439,7 @@ mod tests { let config = PeersConfig::test(); let mut peer_manager = PeersManager::new(config); let peer_id = PeerId::random(); - peer_manager.add_peer(peer_id, socket_addr, None); + peer_manager.add_peer(peer_id, PeerAddr::tcp(socket_addr), None); tokio::time::sleep(Duration::from_secs(1)).await; peer_manager.tick(); @@ -2693,7 +2494,7 @@ mod tests { assert!(peer.remove_after_disconnect); // trigger discovery manually while the peer is still connected - peers.add_peer(peer_id, addr, None); + peers.add_peer(peer_id, PeerAddr::tcp(addr), None); peers.on_active_session_gracefully_closed(peer_id); @@ -2709,7 +2510,7 @@ mod tests { let mut peers = PeersManager::default(); peers.on_incoming_pending_session(addr.ip()).unwrap(); - peers.add_peer(peer_id, addr, None); + peers.add_peer(peer_id, PeerAddr::tcp(addr), None); match event!(peers) { PeerAction::PeerAdded(_) => {} @@ -2737,7 +2538,7 @@ mod tests { let mut peers = PeersManager::default(); peers.on_incoming_pending_session(addr.ip()).unwrap(); - peers.add_peer(peer_id, addr, None); + peers.add_peer(peer_id, PeerAddr::tcp(addr), None); match event!(peers) { PeerAction::PeerAdded(_) => {} @@ -2768,9 +2569,9 @@ mod tests { let config = PeersConfig::default(); let mut peer_manager = PeersManager::new(config); let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)); - let socket_addr = SocketAddr::new(ip, 8008); - for _ in 0..peer_manager.connection_info.max_concurrent_outbound_dials * 2 { - peer_manager.add_peer(PeerId::random(), socket_addr, None); + let peer_addr = PeerAddr::tcp(SocketAddr::new(ip, 8008)); + for _ in 0..peer_manager.connection_info.config.max_concurrent_outbound_dials * 2 { + peer_manager.add_peer(PeerId::random(), peer_addr, None); } peer_manager.fill_outbound_slots(); @@ -2779,7 +2580,7 @@ mod tests { .iter() .filter(|ev| matches!(ev, PeerAction::Connect { .. })) .count(); - assert_eq!(dials, peer_manager.connection_info.max_concurrent_outbound_dials); + assert_eq!(dials, peer_manager.connection_info.config.max_concurrent_outbound_dials); } #[tokio::test] @@ -2787,21 +2588,21 @@ mod tests { let config = PeersConfig::default(); let mut peer_manager = PeersManager::new(config); let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 1, 2)); - let socket_addr = SocketAddr::new(ip, 8008); + let peer_addr = PeerAddr::tcp(SocketAddr::new(ip, 8008)); // add more peers than allowed - for _ in 0..peer_manager.connection_info.max_concurrent_outbound_dials * 2 { - peer_manager.add_peer(PeerId::random(), socket_addr, None); + for _ in 0..peer_manager.connection_info.config.max_concurrent_outbound_dials * 2 { + peer_manager.add_peer(PeerId::random(), peer_addr, None); } - for _ in 0..peer_manager.connection_info.max_concurrent_outbound_dials * 2 { + for _ in 0..peer_manager.connection_info.config.max_concurrent_outbound_dials * 2 { match event!(peer_manager) { PeerAction::PeerAdded(_) => {} _ => unreachable!(), } } - for _ in 0..peer_manager.connection_info.max_concurrent_outbound_dials { + for _ in 0..peer_manager.connection_info.config.max_concurrent_outbound_dials { match event!(peer_manager) { PeerAction::Connect { .. } => {} _ => unreachable!(), @@ -2813,7 +2614,7 @@ mod tests { // all dialed connections should be in 'PendingOut' state let dials = peer_manager.connection_info.num_pending_out; - assert_eq!(dials, peer_manager.connection_info.max_concurrent_outbound_dials); + assert_eq!(dials, peer_manager.connection_info.config.max_concurrent_outbound_dials); let num_pendingout_states = peer_manager .peers @@ -2823,7 +2624,7 @@ mod tests { .collect::>(); assert_eq!( num_pendingout_states.len(), - peer_manager.connection_info.max_concurrent_outbound_dials + peer_manager.connection_info.config.max_concurrent_outbound_dials ); // establish dialed connections diff --git a/crates/net/network/src/peers/mod.rs b/crates/net/network/src/peers/mod.rs deleted file mode 100644 index fafb2d7622e7..000000000000 --- a/crates/net/network/src/peers/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Peer related implementations - -mod manager; -mod reputation; - -pub(crate) use manager::InboundConnectionError; -pub use manager::{ConnectionInfo, Peer, PeerAction, PeersConfig, PeersHandle, PeersManager}; -pub use reputation::ReputationChangeWeights; -pub use reth_network_api::PeerKind; - -/// Maximum number of available slots for outbound sessions. -pub const DEFAULT_MAX_COUNT_PEERS_OUTBOUND: u32 = 100; - -/// Maximum number of available slots for inbound sessions. -pub const DEFAULT_MAX_COUNT_PEERS_INBOUND: u32 = 30; - -/// Maximum number of available slots for concurrent outgoing dials. -/// -/// This restricts how many outbound dials can be performed concurrently. -pub const DEFAULT_MAX_COUNT_CONCURRENT_OUTBOUND_DIALS: usize = 15; diff --git a/crates/net/network/src/session/active.rs b/crates/net/network/src/session/active.rs index 7551721ea231..1cd090105993 100644 --- a/crates/net/network/src/session/active.rs +++ b/crates/net/network/src/session/active.rs @@ -3,7 +3,6 @@ use crate::{ message::{NewBlockMessage, PeerMessage, PeerRequest, PeerResponse, PeerResponseResult}, session::{ - config::INITIAL_REQUEST_TIMEOUT, conn::EthRlpxConnection, handle::{ActiveSessionMessage, SessionCommand}, SessionId, @@ -20,6 +19,7 @@ use reth_eth_wire::{ use reth_metrics::common::mpsc::MeteredPollSender; use reth_network_p2p::error::RequestError; use reth_network_peers::PeerId; +use reth_network_types::session::config::INITIAL_REQUEST_TIMEOUT; use rustc_hash::FxHashMap; use std::{ collections::VecDeque, @@ -759,10 +759,7 @@ fn calculate_new_timeout(current_timeout: Duration, estimated_rtt: Duration) -> #[cfg(test)] mod tests { use super::*; - use crate::session::{ - config::PROTOCOL_BREACH_REQUEST_TIMEOUT, handle::PendingSessionEvent, - start_pending_incoming_session, - }; + use crate::session::{handle::PendingSessionEvent, start_pending_incoming_session}; use reth_chainspec::MAINNET; use reth_ecies::stream::ECIESStream; use reth_eth_wire::{ @@ -770,7 +767,8 @@ mod tests { UnauthedEthStream, UnauthedP2PStream, }; use reth_network_peers::pk2id; - use reth_primitives::{ForkFilter, Hardfork}; + use reth_network_types::session::config::PROTOCOL_BREACH_REQUEST_TIMEOUT; + use reth_primitives::{EthereumHardfork, ForkFilter}; use secp256k1::{SecretKey, SECP256K1}; use tokio::{ net::{TcpListener, TcpStream}, @@ -920,7 +918,7 @@ mod tests { local_peer_id, status: StatusBuilder::default().build(), fork_filter: MAINNET - .hardfork_fork_filter(Hardfork::Frontier) + .hardfork_fork_filter(EthereumHardfork::Frontier) .expect("The Frontier fork filter should exist on mainnet"), } } diff --git a/crates/net/network/src/session/counter.rs b/crates/net/network/src/session/counter.rs new file mode 100644 index 000000000000..0d8f764f206d --- /dev/null +++ b/crates/net/network/src/session/counter.rs @@ -0,0 +1,106 @@ +use reth_network_api::Direction; +use reth_network_types::SessionLimits; + +use super::ExceedsSessionLimit; + +/// Keeps track of all sessions. +#[derive(Debug, Clone)] +pub struct SessionCounter { + /// Limits to enforce. + limits: SessionLimits, + /// Number of pending incoming sessions. + pending_inbound: u32, + /// Number of pending outgoing sessions. + pending_outbound: u32, + /// Number of active inbound sessions. + active_inbound: u32, + /// Number of active outbound sessions. + active_outbound: u32, +} + +// === impl SessionCounter === + +impl SessionCounter { + pub(crate) const fn new(limits: SessionLimits) -> Self { + Self { + limits, + pending_inbound: 0, + pending_outbound: 0, + active_inbound: 0, + active_outbound: 0, + } + } + + pub(crate) fn inc_pending_inbound(&mut self) { + self.pending_inbound += 1; + } + + pub(crate) fn inc_pending_outbound(&mut self) { + self.pending_outbound += 1; + } + + pub(crate) fn dec_pending(&mut self, direction: &Direction) { + match direction { + Direction::Outgoing(_) => { + self.pending_outbound -= 1; + } + Direction::Incoming => { + self.pending_inbound -= 1; + } + } + } + + pub(crate) fn inc_active(&mut self, direction: &Direction) { + match direction { + Direction::Outgoing(_) => { + self.active_outbound += 1; + } + Direction::Incoming => { + self.active_inbound += 1; + } + } + } + + pub(crate) fn dec_active(&mut self, direction: &Direction) { + match direction { + Direction::Outgoing(_) => { + self.active_outbound -= 1; + } + Direction::Incoming => { + self.active_inbound -= 1; + } + } + } + + pub(crate) const fn ensure_pending_outbound(&self) -> Result<(), ExceedsSessionLimit> { + Self::ensure(self.pending_outbound, self.limits.max_pending_outbound) + } + + pub(crate) const fn ensure_pending_inbound(&self) -> Result<(), ExceedsSessionLimit> { + Self::ensure(self.pending_inbound, self.limits.max_pending_inbound) + } + + const fn ensure(current: u32, limit: Option) -> Result<(), ExceedsSessionLimit> { + if let Some(limit) = limit { + if current >= limit { + return Err(ExceedsSessionLimit(limit)) + } + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_limits() { + let mut limits = SessionCounter::new(SessionLimits::default().with_max_pending_inbound(2)); + assert!(limits.ensure_pending_outbound().is_ok()); + limits.inc_pending_inbound(); + assert!(limits.ensure_pending_inbound().is_ok()); + limits.inc_pending_inbound(); + assert!(limits.ensure_pending_inbound().is_err()); + } +} diff --git a/crates/net/network/src/session/mod.rs b/crates/net/network/src/session/mod.rs index 6ce4e97aa519..715ed59cf635 100644 --- a/crates/net/network/src/session/mod.rs +++ b/crates/net/network/src/session/mod.rs @@ -1,10 +1,7 @@ //! Support for handling peer sessions. -use crate::{ - message::PeerMessage, - metrics::SessionManagerMetrics, - session::{active::ActiveSession, config::SessionCounter}, -}; +use crate::{message::PeerMessage, metrics::SessionManagerMetrics, session::active::ActiveSession}; +use counter::SessionCounter; use futures::{future::Either, io, FutureExt, StreamExt}; use reth_ecies::{stream::ECIESStream, ECIESError}; use reth_eth_wire::{ @@ -15,6 +12,7 @@ use reth_eth_wire::{ }; use reth_metrics::common::mpsc::MeteredPollSender; use reth_network_peers::PeerId; +use reth_network_types::SessionsConfig; use reth_primitives::{ForkFilter, ForkId, ForkTransition, Head}; use reth_tasks::TaskSpawner; use rustc_hash::FxHashMap; @@ -37,12 +35,11 @@ use tokio_util::sync::PollSender; use tracing::{debug, instrument, trace}; mod active; -mod config; mod conn; +mod counter; mod handle; pub use crate::message::PeerRequestSender; use crate::protocol::{IntoRlpxSubProtocol, RlpxSubProtocolHandlers, RlpxSubProtocols}; -pub use config::{SessionLimits, SessionsConfig}; pub use handle::{ ActiveSessionHandle, ActiveSessionMessage, PendingSessionEvent, PendingSessionHandle, SessionCommand, @@ -1006,10 +1003,7 @@ async fn authenticate_stream( (eth_stream.into(), their_status) } else { // Multiplex the stream with the extra protocols - let (mut multiplex_stream, their_status) = RlpxProtocolMultiplexer::new(p2p_stream) - .into_eth_satellite_stream(status, fork_filter) - .await - .unwrap(); + let mut multiplex_stream = RlpxProtocolMultiplexer::new(p2p_stream); // install additional handlers for handler in extra_handlers.into_iter() { @@ -1022,6 +1016,19 @@ async fn authenticate_stream( .ok(); } + let (multiplex_stream, their_status) = + match multiplex_stream.into_eth_satellite_stream(status, fork_filter).await { + Ok((multiplex_stream, their_status)) => (multiplex_stream, their_status), + Err(err) => { + return PendingSessionEvent::Disconnected { + remote_addr, + session_id, + direction, + error: Some(PendingSessionHandshakeError::Eth(err)), + } + } + }; + (multiplex_stream.into(), their_status) }; diff --git a/crates/net/network/src/state.rs b/crates/net/network/src/state.rs index afbf05dde691..7334e483b2b4 100644 --- a/crates/net/network/src/state.rs +++ b/crates/net/network/src/state.rs @@ -9,7 +9,7 @@ use crate::{ BlockRequest, NewBlockMessage, PeerRequest, PeerRequestSender, PeerResponse, PeerResponseResult, }, - peers::{PeerAction, PeersManager}, + peers::{PeerAction, PeerAddr, PeersManager}, FetchClient, }; use rand::seq::SliceRandom; @@ -274,13 +274,14 @@ where } /// Adds a peer and its address with the given kind to the peerset. - pub(crate) fn add_peer_kind(&mut self, peer_id: PeerId, kind: PeerKind, addr: SocketAddr) { + pub(crate) fn add_peer_kind(&mut self, peer_id: PeerId, kind: PeerKind, addr: PeerAddr) { self.peers_manager.add_peer_kind(peer_id, kind, addr, None) } - pub(crate) fn remove_peer(&mut self, peer_id: PeerId, kind: PeerKind) { + /// Removes a peer and its address with the given kind from the peerset. + pub(crate) fn remove_peer_kind(&mut self, peer_id: PeerId, kind: PeerKind) { match kind { - PeerKind::Basic => self.peers_manager.remove_peer(peer_id), + PeerKind::Basic | PeerKind::Static => self.peers_manager.remove_peer(peer_id), PeerKind::Trusted => self.peers_manager.remove_peer_from_trusted_set(peer_id), } } @@ -288,14 +289,10 @@ where /// Event hook for events received from the discovery service. fn on_discovery_event(&mut self, event: DiscoveryEvent) { match event { - DiscoveryEvent::NewNode(DiscoveredEvent::EventQueued { - peer_id, - socket_addr, - fork_id, - }) => { + DiscoveryEvent::NewNode(DiscoveredEvent::EventQueued { peer_id, addr, fork_id }) => { self.queued_messages.push_back(StateAction::DiscoveredNode { peer_id, - socket_addr, + addr, fork_id, }); } @@ -516,7 +513,7 @@ pub(crate) enum StateAction { fork_id: ForkId, }, /// A new node was found through the discovery, possibly with a `ForkId` - DiscoveredNode { peer_id: PeerId, socket_addr: SocketAddr, fork_id: Option }, + DiscoveredNode { peer_id: PeerId, addr: PeerAddr, fork_id: Option }, /// A peer was added PeerAdded(PeerId), /// A peer was dropped diff --git a/crates/net/network/src/swarm.rs b/crates/net/network/src/swarm.rs index cfc1f841713c..057cd1143726 100644 --- a/crates/net/network/src/swarm.rs +++ b/crates/net/network/src/swarm.rs @@ -247,14 +247,14 @@ where } StateAction::PeerAdded(peer_id) => return Some(SwarmEvent::PeerAdded(peer_id)), StateAction::PeerRemoved(peer_id) => return Some(SwarmEvent::PeerRemoved(peer_id)), - StateAction::DiscoveredNode { peer_id, socket_addr, fork_id } => { + StateAction::DiscoveredNode { peer_id, addr, fork_id } => { // Don't try to connect to peer if node is shutting down if self.is_shutting_down() { return None } // Insert peer only if no fork id or a valid fork id if fork_id.map_or_else(|| true, |f| self.sessions.is_valid_fork_id(f)) { - self.state_mut().peers_mut().add_peer(peer_id, socket_addr, fork_id); + self.state_mut().peers_mut().add_peer(peer_id, addr, fork_id); } } StateAction::DiscoveredEnrForkId { peer_id, fork_id } => { diff --git a/crates/net/network/src/transactions/constants.rs b/crates/net/network/src/transactions/constants.rs index 59ec103cdace..48fb8857cc35 100644 --- a/crates/net/network/src/transactions/constants.rs +++ b/crates/net/network/src/transactions/constants.rs @@ -57,9 +57,9 @@ pub mod tx_manager { /// Constants used by [`TransactionFetcher`](super::TransactionFetcher). pub mod tx_fetcher { - use crate::{ - peers::{DEFAULT_MAX_COUNT_PEERS_INBOUND, DEFAULT_MAX_COUNT_PEERS_OUTBOUND}, - transactions::fetcher::TransactionFetcherInfo, + use crate::transactions::fetcher::TransactionFetcherInfo; + use reth_network_types::peers::config::{ + DEFAULT_MAX_COUNT_PEERS_INBOUND, DEFAULT_MAX_COUNT_PEERS_OUTBOUND, }; use super::{ diff --git a/crates/net/network/tests/it/connect.rs b/crates/net/network/tests/it/connect.rs index a191443ed8cb..2dbd311cb9f1 100644 --- a/crates/net/network/tests/it/connect.rs +++ b/crates/net/network/tests/it/connect.rs @@ -3,7 +3,6 @@ use alloy_node_bindings::Geth; use alloy_provider::{ext::AdminApi, ProviderBuilder}; use futures::StreamExt; -use reth_chainspec::net::mainnet_nodes; use reth_discv4::Discv4Config; use reth_eth_wire::DisconnectReason; use reth_net_banlist::BanList; @@ -16,7 +15,7 @@ use reth_network_p2p::{ headers::client::{HeadersClient, HeadersRequest}, sync::{NetworkSyncUpdater, SyncState}, }; -use reth_network_peers::NodeRecord; +use reth_network_peers::{mainnet_nodes, NodeRecord}; use reth_primitives::HeadersDirection; use reth_provider::test_utils::NoopProvider; use reth_transaction_pool::test_utils::testing_pool; diff --git a/crates/net/peers/src/bootnodes/ethereum.rs b/crates/net/peers/src/bootnodes/ethereum.rs new file mode 100644 index 000000000000..ba77bb701fcd --- /dev/null +++ b/crates/net/peers/src/bootnodes/ethereum.rs @@ -0,0 +1,40 @@ +//! Ethereum bootnodes come from + +/// Ethereum Foundation Go Bootnodes +pub static MAINNET_BOOTNODES : [&str; 4] = [ + "enode://d860a01f9722d78051619d1e2351aba3f43f943f6f00718d1b9baa4101932a1f5011f16bb2b1bb35db20d6fe28fa0bf09636d26a87d31de9ec6203eeedb1f666@18.138.108.67:30303", // bootnode-aws-ap-southeast-1-001 + "enode://22a8232c3abc76a16ae9d6c3b164f98775fe226f0917b0ca871128a74a8e9630b458460865bab457221f1d448dd9791d24c4e5d88786180ac185df813a68d4de@3.209.45.79:30303", // bootnode-aws-us-east-1-001 + "enode://2b252ab6a1d0f971d9722cb839a42cb81db019ba44c08754628ab4a823487071b5695317c8ccd085219c3a03af063495b2f1da8d18218da2d6a82981b45e6ffc@65.108.70.101:30303", // bootnode-hetzner-hel + "enode://4aeb4ab6c14b23e2c4cfdce879c04b0748a20d8e9b59e25ded2a08143e265c6c25936e74cbc8e641e3312ca288673d91f2f93f8e277de3cfa444ecdaaf982052@157.90.35.166:30303", // bootnode-hetzner-fsn +]; + +/// Ethereum Foundation Sepolia Bootnodes +pub static SEPOLIA_BOOTNODES : [&str; 5] = [ + "enode://4e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476f8fb1cbe914af0d9aef0d51665c214cf653c651c4bbd9d5550a934f241f1682b@138.197.51.181:30303", // sepolia-bootnode-1-nyc3 + "enode://143e11fb766781d22d92a2e33f8f104cddae4411a122295ed1fdb6638de96a6ce65f5b7c964ba3763bba27961738fef7d3ecc739268f3e5e771fb4c87b6234ba@146.190.1.103:30303", // sepolia-bootnode-1-sfo3 + "enode://8b61dc2d06c3f96fddcbebb0efb29d60d3598650275dc469c22229d3e5620369b0d3dedafd929835fe7f489618f19f456fe7c0df572bf2d914a9f4e006f783a9@170.64.250.88:30303", // sepolia-bootnode-1-syd1 + "enode://10d62eff032205fcef19497f35ca8477bea0eadfff6d769a147e895d8b2b8f8ae6341630c645c30f5df6e67547c03494ced3d9c5764e8622a26587b083b028e8@139.59.49.206:30303", // sepolia-bootnode-1-blr1 + "enode://9e9492e2e8836114cc75f5b929784f4f46c324ad01daf87d956f98b3b6c5fcba95524d6e5cf9861dc96a2c8a171ea7105bb554a197455058de185fa870970c7c@138.68.123.152:30303", // sepolia-bootnode-1-ams3 +]; + +/// Görli Bootnodes +pub static GOERLI_BOOTNODES : [&str; 7] = [ + // Upstream bootnodes + "enode://011f758e6552d105183b1761c5e2dea0111bc20fd5f6422bc7f91e0fabbec9a6595caf6239b37feb773dddd3f87240d99d859431891e4a642cf2a0a9e6cbb98a@51.141.78.53:30303", + "enode://176b9417f511d05b6b2cf3e34b756cf0a7096b3094572a8f6ef4cdcb9d1f9d00683bf0f83347eebdf3b81c3521c2332086d9592802230bf528eaf606a1d9677b@13.93.54.137:30303", + "enode://46add44b9f13965f7b9875ac6b85f016f341012d84f975377573800a863526f4da19ae2c620ec73d11591fa9510e992ecc03ad0751f53cc02f7c7ed6d55c7291@94.237.54.114:30313", + "enode://b5948a2d3e9d486c4d75bf32713221c2bd6cf86463302339299bd227dc2e276cd5a1c7ca4f43a0e9122fe9af884efed563bd2a1fd28661f3b5f5ad7bf1de5949@18.218.250.66:30303", + + // Ethereum Foundation bootnode + "enode://a61215641fb8714a373c80edbfa0ea8878243193f57c96eeb44d0bc019ef295abd4e044fd619bfc4c59731a73fb79afe84e9ab6da0c743ceb479cbb6d263fa91@3.11.147.67:30303", + + // Goerli Initiative bootnodes + "enode://d4f764a48ec2a8ecf883735776fdefe0a3949eb0ca476bd7bc8d0954a9defe8fea15ae5da7d40b5d2d59ce9524a99daedadf6da6283fca492cc80b53689fb3b3@46.4.99.122:32109", + "enode://d2b720352e8216c9efc470091aa91ddafc53e222b32780f505c817ceef69e01d5b0b0797b69db254c586f493872352f5a022b4d8479a00fc92ec55f9ad46a27e@88.99.70.182:30303", +]; + +/// Ethereum Foundation Holesky Bootnodes +pub static HOLESKY_BOOTNODES : [&str; 2] = [ + "enode://ac906289e4b7f12df423d654c5a962b6ebe5b3a74cc9e06292a85221f9a64a6f1cfdd6b714ed6dacef51578f92b34c60ee91e9ede9c7f8fadc4d347326d95e2b@146.190.13.128:30303", + "enode://a3435a0155a3e837c02f5e7f5662a2f1fbc25b48e4dc232016e1c51b544cb5b4510ef633ea3278c0e970fa8ad8141e2d4d0f9f95456c537ff05fdf9b31c15072@178.128.136.233:30303", +]; diff --git a/crates/net/peers/src/bootnodes/mod.rs b/crates/net/peers/src/bootnodes/mod.rs new file mode 100644 index 000000000000..ecd6de3103a6 --- /dev/null +++ b/crates/net/peers/src/bootnodes/mod.rs @@ -0,0 +1,54 @@ +//! Bootnodes for the network + +use crate::NodeRecord; + +mod ethereum; +pub use ethereum::*; + +mod optimism; +pub use optimism::*; + +/// Returns parsed mainnet nodes +pub fn mainnet_nodes() -> Vec { + parse_nodes(&MAINNET_BOOTNODES[..]) +} + +/// Returns parsed goerli nodes +pub fn goerli_nodes() -> Vec { + parse_nodes(&GOERLI_BOOTNODES[..]) +} + +/// Returns parsed sepolia nodes +pub fn sepolia_nodes() -> Vec { + parse_nodes(&SEPOLIA_BOOTNODES[..]) +} + +/// Returns parsed holesky nodes +pub fn holesky_nodes() -> Vec { + parse_nodes(&HOLESKY_BOOTNODES[..]) +} + +/// Returns parsed op-stack mainnet nodes +pub fn op_nodes() -> Vec { + parse_nodes(OP_BOOTNODES) +} + +/// Returns parsed op-stack testnet nodes +pub fn op_testnet_nodes() -> Vec { + parse_nodes(OP_TESTNET_BOOTNODES) +} + +/// Returns parsed op-stack base mainnet nodes +pub fn base_nodes() -> Vec { + parse_nodes(OP_BOOTNODES) +} + +/// Returns parsed op-stack base testnet nodes +pub fn base_testnet_nodes() -> Vec { + parse_nodes(OP_TESTNET_BOOTNODES) +} + +/// Parses all the nodes +pub fn parse_nodes(nodes: impl IntoIterator>) -> Vec { + nodes.into_iter().map(|s| s.as_ref().parse().unwrap()).collect() +} diff --git a/crates/net/peers/src/bootnodes/optimism.rs b/crates/net/peers/src/bootnodes/optimism.rs new file mode 100644 index 000000000000..e3465721b1ca --- /dev/null +++ b/crates/net/peers/src/bootnodes/optimism.rs @@ -0,0 +1,26 @@ +//! OP bootnodes come from + +/// OP stack mainnet boot nodes. +pub static OP_BOOTNODES: &[&str] = &[ + // OP Labs + "enode://ca2774c3c401325850b2477fd7d0f27911efbf79b1e8b335066516e2bd8c4c9e0ba9696a94b1cb030a88eac582305ff55e905e64fb77fe0edcd70a4e5296d3ec@34.65.175.185:30305", + "enode://dd751a9ef8912be1bfa7a5e34e2c3785cc5253110bd929f385e07ba7ac19929fb0e0c5d93f77827291f4da02b2232240fbc47ea7ce04c46e333e452f8656b667@34.65.107.0:30305", + "enode://c5d289b56a77b6a2342ca29956dfd07aadf45364dde8ab20d1dc4efd4d1bc6b4655d902501daea308f4d8950737a4e93a4dfedd17b49cd5760ffd127837ca965@34.65.202.239:30305", + // Base + "enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301", + "enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301", + "enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301", + "enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301", + "enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301" +]; + +/// OP stack testnet boot nodes. +pub static OP_TESTNET_BOOTNODES: &[&str] = &[ + // OP Labs + "enode://2bd2e657bb3c8efffb8ff6db9071d9eb7be70d7c6d7d980ff80fc93b2629675c5f750bc0a5ef27cd788c2e491b8795a7e9a4a6e72178c14acc6753c0e5d77ae4@34.65.205.244:30305", + "enode://db8e1cab24624cc62fc35dbb9e481b88a9ef0116114cd6e41034c55b5b4f18755983819252333509bd8e25f6b12aadd6465710cd2e956558faf17672cce7551f@34.65.173.88:30305", + "enode://bfda2e0110cfd0f4c9f7aa5bf5ec66e6bd18f71a2db028d36b8bf8b0d6fdb03125c1606a6017b31311d96a36f5ef7e1ad11604d7a166745e6075a715dfa67f8a@34.65.229.245:30305", + // Base + "enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301", + "enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301", +]; diff --git a/crates/net/peers/src/lib.rs b/crates/net/peers/src/lib.rs index f531f1eb8f09..b58f499abf3a 100644 --- a/crates/net/peers/src/lib.rs +++ b/crates/net/peers/src/lib.rs @@ -63,6 +63,9 @@ pub use node_record::{NodeRecord, NodeRecordParseError}; pub mod trusted_peer; pub use trusted_peer::TrustedPeer; +mod bootnodes; +pub use bootnodes::*; + /// This tag should be set to indicate to libsecp256k1 that the following bytes denote an /// uncompressed pubkey. /// diff --git a/crates/net/peers/src/node_record.rs b/crates/net/peers/src/node_record.rs index 3b6c38170d56..5f268c253919 100644 --- a/crates/net/peers/src/node_record.rs +++ b/crates/net/peers/src/node_record.rs @@ -92,6 +92,17 @@ impl NodeRecord { Self { address: addr.ip(), tcp_port: addr.port(), udp_port: addr.port(), id } } + /// Creates a new record from an ip address and ports. + pub fn new_with_ports( + ip_addr: IpAddr, + tcp_port: u16, + udp_port: Option, + id: PeerId, + ) -> Self { + let udp_port = udp_port.unwrap_or(tcp_port); + Self { address: ip_addr, tcp_port, udp_port, id } + } + /// The TCP socket address of this node #[must_use] pub const fn tcp_addr(&self) -> SocketAddr { diff --git a/crates/node-core/src/metrics/version_metrics.rs b/crates/node-core/src/metrics/version_metrics.rs deleted file mode 100644 index f0b11c3b7e8b..000000000000 --- a/crates/node-core/src/metrics/version_metrics.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! This exposes reth's version information over prometheus. - -use crate::version::build_profile_name; -use metrics::gauge; - -const LABELS: [(&str, &str); 6] = [ - ("version", env!("CARGO_PKG_VERSION")), - ("build_timestamp", env!("VERGEN_BUILD_TIMESTAMP")), - ("cargo_features", env!("VERGEN_CARGO_FEATURES")), - ("git_sha", env!("VERGEN_GIT_SHA")), - ("target_triple", env!("VERGEN_CARGO_TARGET_TRIPLE")), - ("build_profile", build_profile_name()), -]; - -/// This exposes reth's version information over prometheus. -pub fn register_version_metrics() { - let _gauge = gauge!("info", &LABELS); -} diff --git a/crates/node-taiko/Cargo.toml b/crates/node-taiko/Cargo.toml new file mode 100644 index 000000000000..01e084a467cc --- /dev/null +++ b/crates/node-taiko/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "reth-node-taiko" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +# reth +reth-primitives.workspace = true +reth-payload-builder.workspace = true +reth-basic-payload-builder.workspace = true +reth-taiko-payload-builder.workspace = true +reth-rpc-types.workspace = true +reth-node-api.workspace = true +reth-node-builder.workspace = true +reth-tracing.workspace = true +reth-provider.workspace = true +reth-transaction-pool.workspace = true +reth-network.workspace = true + +# misc +eyre.workspace = true +serde.workspace = true + +[dev-dependencies] +reth-db.workspace = true diff --git a/crates/node-taiko/src/engine.rs b/crates/node-taiko/src/engine.rs new file mode 100644 index 000000000000..ce7dfcdb589a --- /dev/null +++ b/crates/node-taiko/src/engine.rs @@ -0,0 +1,33 @@ +use reth_node_api::{ + validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion, + EngineTypes, PayloadOrAttributes, +}; +use reth_payload_builder::{ + TaikoBuiltPayload, TaikoExecutionPayloadEnvelope, TaikoPayloadAttributes, + TaikoPayloadBuilderAttributes, +}; +use reth_primitives::ChainSpec; +use reth_rpc_types::{engine::ExecutionPayloadEnvelopeV2, ExecutionPayloadV1}; +use serde::{Deserialize, Serialize}; + +/// The types used in the default mainnet ethereum beacon consensus engine. +#[derive(Debug, Default, Clone, Deserialize, Serialize)] +#[non_exhaustive] +pub struct TaikoEngineTypes; + +impl EngineTypes for TaikoEngineTypes { + type PayloadAttributes = TaikoPayloadAttributes; + type PayloadBuilderAttributes = TaikoPayloadBuilderAttributes; + type BuiltPayload = TaikoBuiltPayload; + type ExecutionPayloadV1 = ExecutionPayloadV1; + type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadV3 = TaikoExecutionPayloadEnvelope; + + fn validate_version_specific_fields( + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + payload_or_attrs: PayloadOrAttributes<'_, TaikoPayloadAttributes>, + ) -> Result<(), AttributesValidationError> { + validate_version_specific_fields(chain_spec, version, payload_or_attrs) + } +} diff --git a/crates/node-taiko/src/evm.rs b/crates/node-taiko/src/evm.rs new file mode 100644 index 000000000000..52aee24f4adc --- /dev/null +++ b/crates/node-taiko/src/evm.rs @@ -0,0 +1,73 @@ +use reth_node_api::{ConfigureEvm, ConfigureEvmEnv}; +use reth_primitives::{ + revm::{config::revm_spec, env::fill_tx_env}, + revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, + Address, ChainSpec, Head, Header, Transaction, U256, +}; + +/// Taiko-related EVM configuration. +#[derive(Debug, Clone, Copy, Default)] +#[non_exhaustive] +pub struct TaikoEvmConfig; + +impl ConfigureEvmEnv for TaikoEvmConfig { + type TxMeta = (); + + fn fill_tx_env(tx_env: &mut TxEnv, transaction: T, sender: Address, _meta: ()) + where + T: AsRef, + { + fill_tx_env(tx_env, transaction, sender) + } + + fn fill_cfg_env( + cfg_env: &mut CfgEnvWithHandlerCfg, + chain_spec: &ChainSpec, + header: &Header, + total_difficulty: U256, + ) { + let spec_id = revm_spec( + chain_spec, + Head { + number: header.number, + timestamp: header.timestamp, + difficulty: header.difficulty, + total_difficulty, + hash: Default::default(), + }, + ); + + cfg_env.chain_id = chain_spec.chain().id(); + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; + + cfg_env.handler_cfg.spec_id = spec_id; + } +} + +impl ConfigureEvm for TaikoEvmConfig {} + +#[cfg(test)] +mod tests { + use super::*; + use reth_primitives::revm_primitives::{BlockEnv, CfgEnv, SpecId}; + + #[test] + #[ignore] + fn test_fill_cfg_and_block_env() { + let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); + let mut block_env = BlockEnv::default(); + let header = Header::default(); + let chain_spec = ChainSpec::default(); + let total_difficulty = U256::ZERO; + + TaikoEvmConfig::fill_cfg_and_block_env( + &mut cfg_env, + &mut block_env, + &chain_spec, + &header, + total_difficulty, + ); + + assert_eq!(cfg_env.chain_id, chain_spec.chain().id()); + } +} diff --git a/crates/node-taiko/src/lib.rs b/crates/node-taiko/src/lib.rs new file mode 100644 index 000000000000..e2b5e592290b --- /dev/null +++ b/crates/node-taiko/src/lib.rs @@ -0,0 +1,21 @@ +//! Standalone crate for ethereum-specific Reth configuration and builder types. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +/// Exports commonly used concrete instances of the [EngineTypes](reth_node_api::EngineTypes) +/// trait. +pub mod engine; +pub use engine::TaikoEngineTypes; + +/// Exports commonly used concrete instances of the +/// [ConfigureEvmEnv](reth_node_api::ConfigureEvmEnv) trait. +pub mod evm; +pub use evm::TaikoEvmConfig; +pub mod node; +pub use node::TaikoNode; diff --git a/crates/node-taiko/src/node.rs b/crates/node-taiko/src/node.rs new file mode 100644 index 000000000000..b9a17495080b --- /dev/null +++ b/crates/node-taiko/src/node.rs @@ -0,0 +1,207 @@ +//! Ethereum Node types config. + +use crate::{TaikoEngineTypes, TaikoEvmConfig}; +use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; +use reth_network::NetworkHandle; +use reth_node_builder::{ + components::{ComponentsBuilder, NetworkBuilder, PayloadServiceBuilder, PoolBuilder}, + node::{FullNodeTypes, Node, NodeTypes}, + BuilderContext, PayloadBuilderConfig, +}; +use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; +use reth_provider::CanonStateSubscriptions; +use reth_tracing::tracing::{debug, info}; +use reth_transaction_pool::{ + blobstore::DiskFileBlobStore, EthTransactionPool, TransactionPool, + TransactionValidationTaskExecutor, +}; + +/// Type configuration for a regular Ethereum node. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct TaikoNode; + +impl TaikoNode { + /// Creates a new instance of the Optimism node type. + pub const fn new() -> Self { + Self + } + + /// Returns a [ComponentsBuilder] configured for a Taiko node. + pub fn components( + ) -> ComponentsBuilder + where + Node: FullNodeTypes, + { + ComponentsBuilder::default() + .node_types::() + .pool(TaikoPoolBuilder::default()) + .payload(TaikoPayloadBuilder::default()) + .network(TaikoNetworkBuilder::default()) + } +} + +impl NodeTypes for TaikoNode { + type Primitives = (); + type Engine = TaikoEngineTypes; + type Evm = TaikoEvmConfig; + + fn evm_config(&self) -> Self::Evm { + TaikoEvmConfig::default() + } +} + +impl Node for TaikoNode +where + N: FullNodeTypes, +{ + type PoolBuilder = TaikoPoolBuilder; + type NetworkBuilder = TaikoNetworkBuilder; + type PayloadBuilder = TaikoPayloadBuilder; + + fn components( + self, + ) -> ComponentsBuilder { + ComponentsBuilder::default() + .node_types::() + .pool(TaikoPoolBuilder::default()) + .payload(TaikoPayloadBuilder::default()) + .network(TaikoNetworkBuilder::default()) + } +} + +/// A basic Taiko transaction pool. +/// +/// This contains various settings that can be configured and take precedence over the node's +/// config. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct TaikoPoolBuilder { + // TODO add options for txpool args +} + +impl PoolBuilder for TaikoPoolBuilder +where + Node: FullNodeTypes, +{ + type Pool = EthTransactionPool; + + async fn build_pool(self, ctx: &BuilderContext) -> eyre::Result { + let data_dir = ctx.data_dir(); + let blob_store = DiskFileBlobStore::open(data_dir.blobstore_path(), Default::default())?; + let validator = TransactionValidationTaskExecutor::eth_builder(ctx.chain_spec()) + .with_head_timestamp(ctx.head().timestamp) + .kzg_settings(ctx.kzg_settings()?) + .with_additional_tasks(1) + .build_with_tasks( + ctx.provider().clone(), + ctx.task_executor().clone(), + blob_store.clone(), + ); + + let transaction_pool = + reth_transaction_pool::Pool::eth_pool(validator, blob_store, ctx.pool_config()); + info!(target: "reth::cli", "Transaction pool initialized"); + let transactions_path = data_dir.txpool_transactions_path(); + + // spawn txpool maintenance task + { + let pool = transaction_pool.clone(); + let chain_events = ctx.provider().canonical_state_stream(); + let client = ctx.provider().clone(); + let transactions_backup_config = + reth_transaction_pool::maintain::LocalTransactionBackupConfig::with_local_txs_backup(transactions_path); + + ctx.task_executor().spawn_critical_with_graceful_shutdown_signal( + "local transactions backup task", + |shutdown| { + reth_transaction_pool::maintain::backup_local_transactions_task( + shutdown, + pool.clone(), + transactions_backup_config, + ) + }, + ); + + // spawn the maintenance task + ctx.task_executor().spawn_critical( + "txpool maintenance task", + reth_transaction_pool::maintain::maintain_transaction_pool_future( + client, + pool, + chain_events, + ctx.task_executor().clone(), + Default::default(), + ), + ); + debug!(target: "reth::cli", "Spawned txpool maintenance task"); + } + + Ok(transaction_pool) + } +} + +/// A Taiko payload service. +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct TaikoPayloadBuilder; + +impl PayloadServiceBuilder for TaikoPayloadBuilder +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + async fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + let payload_builder = reth_taiko_payload_builder::TaikoPayloadBuilder; + let conf = ctx.payload_builder_config(); + + let payload_job_config = BasicPayloadJobGeneratorConfig::default() + .interval(conf.interval()) + .deadline(conf.deadline()) + .max_payload_tasks(conf.max_payload_tasks()) + .extradata(conf.extradata_rlp_bytes()) + .max_gas_limit(conf.max_gas_limit()); + + let payload_generator = BasicPayloadJobGenerator::with_builder( + ctx.provider().clone(), + pool, + ctx.task_executor().clone(), + payload_job_config, + ctx.chain_spec(), + payload_builder, + ); + let (payload_service, payload_builder) = + PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); + + ctx.task_executor().spawn_critical("payload builder service", Box::pin(payload_service)); + + Ok(payload_builder) + } +} + +/// A basic Taiko network service. +#[derive(Debug, Default, Clone, Copy)] +pub struct TaikoNetworkBuilder { + // TODO add closure to modify network +} + +impl NetworkBuilder for TaikoNetworkBuilder +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + async fn build_network( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result { + let network = ctx.network_builder().await?; + let handle = ctx.start_network(network, pool); + + Ok(handle) + } +} diff --git a/crates/node-taiko/tests/it/builder.rs b/crates/node-taiko/tests/it/builder.rs new file mode 100644 index 000000000000..1998d9bade28 --- /dev/null +++ b/crates/node-taiko/tests/it/builder.rs @@ -0,0 +1,34 @@ +//! Node builder setup tests. + +use reth_db::test_utils::create_test_rw_db; +use reth_node_builder::{components::FullNodeComponents, NodeBuilder, NodeConfig}; +use reth_node_ethereum::node::EthereumNode; + +#[test] +fn test_basic_setup() { + // parse CLI -> config + let config = NodeConfig::test(); + let db = create_test_rw_db(); + let msg = "On components".to_string(); + let _builder = NodeBuilder::new(config) + .with_database(db) + .with_types(EthereumNode::default()) + .with_components(EthereumNode::components()) + .on_component_initialized(move |ctx| { + let _provider = ctx.provider(); + println!("{msg}"); + Ok(()) + }) + .on_node_started(|_full_node| Ok(())) + .on_rpc_started(|_ctx, handles| { + let _client = handles.rpc.http_client(); + Ok(()) + }) + .extend_rpc_modules(|ctx| { + let _ = ctx.config(); + let _ = ctx.node().provider(); + + Ok(()) + }) + .check_launch(); +} diff --git a/crates/node-taiko/tests/it/main.rs b/crates/node-taiko/tests/it/main.rs new file mode 100644 index 000000000000..34ac15ef9f09 --- /dev/null +++ b/crates/node-taiko/tests/it/main.rs @@ -0,0 +1,3 @@ +mod builder; + +fn main() {} diff --git a/crates/node/builder/Cargo.toml b/crates/node/builder/Cargo.toml index 87746ff13571..f83145b052e9 100644 --- a/crates/node/builder/Cargo.toml +++ b/crates/node/builder/Cargo.toml @@ -45,6 +45,7 @@ reth-node-events.workspace = true reth-consensus.workspace = true reth-consensus-debug-client.workspace = true reth-rpc-types.workspace = true +reth-engine-util.workspace = true ## async futures.workspace = true @@ -56,9 +57,6 @@ tokio = { workspace = true, features = [ ] } tokio-stream.workspace = true -## ethereum -discv5.workspace = true - ## crypto secp256k1 = { workspace = true, features = [ "global-context", diff --git a/crates/node/builder/src/builder/mod.rs b/crates/node/builder/src/builder/mod.rs index f23fc873e885..72e56b71a3ea 100644 --- a/crates/node/builder/src/builder/mod.rs +++ b/crates/node/builder/src/builder/mod.rs @@ -9,7 +9,6 @@ use crate::{ rpc::{RethRpcServerHandles, RpcContext}, DefaultNodeLauncher, Node, NodeHandle, }; -use discv5::ListenConfig; use futures::Future; use reth_chainspec::ChainSpec; use reth_db::{ @@ -39,10 +38,7 @@ use reth_tasks::TaskExecutor; use reth_transaction_pool::{PoolConfig, TransactionPool}; use secp256k1::SecretKey; pub use states::*; -use std::{ - net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6}, - sync::Arc, -}; +use std::sync::Arc; mod states; @@ -66,7 +62,7 @@ pub type RethFullAdapter = FullNodeTypesAdapter = FullNodeTypesAdapter = FullNodeTypesAdapter = FullNodeTypesAdapter BuilderContext { pub fn network_config_builder(&self) -> eyre::Result { let secret_key = self.network_secret(&self.config().datadir())?; let default_peers_path = self.config().datadir().known_peers(); - Ok(self.config().network.network_config( - self.reth_config(), - self.config().chain.clone(), - secret_key, - default_peers_path, - )) + let builder = self + .config() + .network + .network_config( + self.reth_config(), + self.config().chain.clone(), + secret_key, + default_peers_path, + ) + .with_task_executor(Box::new(self.executor.clone())) + .set_head(self.head); + + Ok(builder) } /// Get the network secret from the given data dir @@ -551,49 +555,7 @@ impl BuilderContext { &self, network_builder: NetworkConfigBuilder, ) -> NetworkConfig { - network_builder - .with_task_executor(Box::new(self.executor.clone())) - .set_head(self.head) - .listener_addr(SocketAddr::new( - self.config().network.addr, - // set discovery port based on instance number - self.config().network.port + self.config().instance - 1, - )) - .discovery_addr(SocketAddr::new( - self.config().network.discovery.addr, - // set discovery port based on instance number - self.config().network.discovery.port + self.config().instance - 1, - )) - .map_discv5_config_builder(|builder| { - // Use rlpx address if none given - let discv5_addr_ipv4 = self.config().network.discovery.discv5_addr.or( - match self.config().network.addr { - IpAddr::V4(ip) => Some(ip), - IpAddr::V6(_) => None, - }, - ); - let discv5_addr_ipv6 = self.config().network.discovery.discv5_addr_ipv6.or( - match self.config().network.addr { - IpAddr::V4(_) => None, - IpAddr::V6(ip) => Some(ip), - }, - ); - - let discv5_port_ipv4 = - self.config().network.discovery.discv5_port + self.config().instance - 1; - let discv5_port_ipv6 = - self.config().network.discovery.discv5_port_ipv6 + self.config().instance - 1; - - builder.discv5_config( - discv5::ConfigBuilder::new(ListenConfig::from_two_sockets( - discv5_addr_ipv4.map(|addr| SocketAddrV4::new(addr, discv5_port_ipv4)), - discv5_addr_ipv6 - .map(|addr| SocketAddrV6::new(addr, discv5_port_ipv6, 0, 0)), - )) - .build(), - ) - }) - .build(self.provider.clone()) + network_builder.build(self.provider.clone()) } } diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index 1c48fd763041..83e48927df57 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -107,7 +107,7 @@ impl LaunchContext { ) -> eyre::Result<()> { if reth_config.prune.is_none() { if let Some(prune_config) = config.prune_config() { - reth_config.update_prune_confing(prune_config); + reth_config.update_prune_config(prune_config); info!(target: "reth::cli", "Saving prune config to toml file"); reth_config.save(config_path.as_ref())?; } @@ -251,7 +251,7 @@ impl LaunchContextWith> { /// - Making sure the ETL dir is set to the datadir /// - RPC settings are adjusted to the correct port pub fn with_adjusted_configs(self) -> Self { - self.ensure_etl_datadir().with_adjusted_rpc_instance_ports() + self.ensure_etl_datadir().with_adjusted_instance_ports() } /// Make sure ETL doesn't default to /tmp/, but to whatever datadir is set to @@ -265,7 +265,7 @@ impl LaunchContextWith> { } /// Change rpc port numbers based on the instance number. - pub fn with_adjusted_rpc_instance_ports(mut self) -> Self { + pub fn with_adjusted_instance_ports(mut self) -> Self { self.node_config_mut().adjust_instance_ports(); self } diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 9795cead4155..99dc04310d82 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -13,17 +13,16 @@ use reth_beacon_consensus::{ BeaconConsensusEngine, }; use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider}; +use reth_engine_util::EngineMessageStreamExt; use reth_exex::ExExManagerHandle; use reth_network::NetworkEvents; use reth_node_api::FullNodeTypes; use reth_node_core::{ dirs::{ChainPath, DataDirPath}, - engine::EngineMessageStreamExt, exit::NodeExitFuture, version::{CARGO_PKG_VERSION, CLIENT_CODE, NAME_CLIENT, VERGEN_GIT_SHA}, }; use reth_node_events::{cl::ConsensusLayerHealthEvents, node}; - use reth_primitives::format_ether; use reth_provider::providers::BlockchainProvider; use reth_rpc_engine_api::EngineApi; @@ -390,7 +389,10 @@ where on_node_started.on_event(full_node.clone())?; let handle = NodeHandle { - node_exit_future: NodeExitFuture::new(rx, full_node.config.debug.terminate), + node_exit_future: NodeExitFuture::new( + async { Ok(rx.await??) }, + full_node.config.debug.terminate, + ), node: full_node, }; diff --git a/crates/node/builder/src/node.rs b/crates/node/builder/src/node.rs index 76c2117552ee..fe8d99ed6090 100644 --- a/crates/node/builder/src/node.rs +++ b/crates/node/builder/src/node.rs @@ -11,7 +11,7 @@ use reth_payload_builder::PayloadBuilderHandle; use reth_provider::ChainSpecProvider; use reth_rpc_builder::{auth::AuthServerHandle, RpcServerHandle}; use reth_tasks::TaskExecutor; -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; // re-export the node api types use crate::components::NodeComponentsBuilder; @@ -28,6 +28,44 @@ pub trait Node: NodeTypes + Clone { fn components_builder(self) -> Self::ComponentsBuilder; } +/// A [`Node`] type builder +#[derive(Clone, Default, Debug)] +pub struct AnyNode(PhantomData, C); + +impl AnyNode { + /// Configures the types of the node. + pub fn types(self) -> AnyNode { + AnyNode::(PhantomData::, self.1) + } + + /// Sets the node components builder. + pub fn components_builder(self, value: T) -> AnyNode { + AnyNode::(PhantomData::, value) + } +} + +impl NodeTypes for AnyNode +where + N: FullNodeTypes, + C: NodeComponentsBuilder + Sync + Unpin + 'static, +{ + type Primitives = N::Primitives; + + type Engine = N::Engine; +} + +impl Node for AnyNode +where + N: FullNodeTypes + Clone, + C: NodeComponentsBuilder + Clone + Sync + Unpin + 'static, +{ + type ComponentsBuilder = C; + + fn components_builder(self) -> Self::ComponentsBuilder { + self.1 + } +} + /// The launched node with all components including RPC handlers. /// /// This can be used to interact with the launched node. diff --git a/crates/node/builder/src/rpc.rs b/crates/node/builder/src/rpc.rs index 9a6ada8f916d..9a7a86b91b5a 100644 --- a/crates/node/builder/src/rpc.rs +++ b/crates/node/builder/src/rpc.rs @@ -189,8 +189,9 @@ impl Clone for RpcRegistry { /// [`AuthRpcModule`]. /// /// This can be used to access installed modules, or create commonly used handlers like -/// [`reth_rpc::EthApi`], and ultimately merge additional rpc handler into the configured transport -/// modules [`TransportRpcModules`] as well as configured authenticated methods [`AuthRpcModule`]. +/// [`reth_rpc::eth::EthApi`], and ultimately merge additional rpc handler into the configured +/// transport modules [`TransportRpcModules`] as well as configured authenticated methods +/// [`AuthRpcModule`]. #[allow(missing_debug_implementations)] pub struct RpcContext<'a, Node: FullNodeComponents> { /// The node components. diff --git a/crates/node-core/Cargo.toml b/crates/node/core/Cargo.toml similarity index 88% rename from crates/node-core/Cargo.toml rename to crates/node/core/Cargo.toml index d9cae558b29a..6550fdc63b57 100644 --- a/crates/node-core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -21,11 +21,12 @@ reth-storage-errors.workspace = true reth-provider.workspace = true reth-network = { workspace = true, features = ["serde"] } reth-network-p2p.workspace = true -reth-rpc.workspace = true +reth-rpc-eth-types.workspace = true reth-rpc-server-types.workspace = true reth-rpc-types.workspace = true reth-rpc-types-compat.workspace = true reth-rpc-api = { workspace = true, features = ["client"] } +reth-rpc-eth-api = { workspace = true, features = ["client"] } reth-transaction-pool.workspace = true reth-tracing.workspace = true reth-config.workspace = true @@ -33,12 +34,11 @@ reth-discv4.workspace = true reth-discv5.workspace = true reth-net-nat.workspace = true reth-network-peers.workspace = true -reth-engine-primitives.workspace = true reth-tasks.workspace = true reth-consensus-common.workspace = true -reth-beacon-consensus.workspace = true reth-prune-types.workspace = true reth-stages-types.workspace = true +reth-payload-builder = { workspace = true, optional = true } # ethereum alloy-genesis.workspace = true @@ -46,8 +46,6 @@ alloy-rpc-types-engine.workspace = true # async tokio.workspace = true -tokio-util.workspace = true -pin-project.workspace = true # metrics reth-metrics.workspace = true @@ -61,7 +59,7 @@ eyre.workspace = true clap = { workspace = true, features = ["derive"] } humantime.workspace = true thiserror.workspace = true -const-str = "0.5.6" +const_format.workspace = true rand.workspace = true derive_more.workspace = true once_cell.workspace = true @@ -69,7 +67,6 @@ once_cell.workspace = true # io dirs-next = "2.0.0" shellexpand = "3.0.0" -serde.workspace = true serde_json.workspace = true # http/rpc @@ -103,11 +100,12 @@ proptest.workspace = true [features] optimism = [ "reth-primitives/optimism", - "reth-rpc/optimism", "reth-provider/optimism", "reth-rpc-types-compat/optimism", - "reth-beacon-consensus/optimism", + "reth-rpc-eth-api/optimism", + "reth-rpc-eth-types/optimism" ] +taiko = ["reth-primitives/taiko", "dep:reth-payload-builder"] jemalloc = ["dep:tikv-jemalloc-ctl"] diff --git a/crates/node-core/build.rs b/crates/node/core/build.rs similarity index 90% rename from crates/node-core/build.rs rename to crates/node/core/build.rs index 043505cdfb67..1a78793a4746 100644 --- a/crates/node-core/build.rs +++ b/crates/node/core/build.rs @@ -8,19 +8,20 @@ fn main() -> Result<(), Box> { EmitBuilder::builder() .git_describe(false, true, None) .git_dirty(true) - .git_sha(true) + .git_sha(false) .build_timestamp() .cargo_features() .cargo_target_triple() .emit_and_set()?; let sha = env::var("VERGEN_GIT_SHA")?; + let sha_short = &sha[0..7]; let is_dirty = env::var("VERGEN_GIT_DIRTY")? == "true"; // > git describe --always --tags // if not on a tag: v0.2.0-beta.3-82-g1939939b // if on a tag: v0.2.0-beta.3 - let not_on_tag = env::var("VERGEN_GIT_DESCRIBE")?.ends_with(&format!("-g{sha}")); + let not_on_tag = env::var("VERGEN_GIT_DESCRIBE")?.ends_with(&format!("-g{sha_short}")); let is_dev = is_dirty || not_on_tag; println!("cargo:rustc-env=RETH_VERSION_SUFFIX={}", if is_dev { "-dev" } else { "" }); Ok(()) diff --git a/crates/node-core/src/args/benchmark_args.rs b/crates/node/core/src/args/benchmark_args.rs similarity index 100% rename from crates/node-core/src/args/benchmark_args.rs rename to crates/node/core/src/args/benchmark_args.rs diff --git a/crates/node-core/src/args/database.rs b/crates/node/core/src/args/database.rs similarity index 100% rename from crates/node-core/src/args/database.rs rename to crates/node/core/src/args/database.rs diff --git a/crates/node-core/src/args/datadir_args.rs b/crates/node/core/src/args/datadir_args.rs similarity index 100% rename from crates/node-core/src/args/datadir_args.rs rename to crates/node/core/src/args/datadir_args.rs diff --git a/crates/node-core/src/args/debug.rs b/crates/node/core/src/args/debug.rs similarity index 100% rename from crates/node-core/src/args/debug.rs rename to crates/node/core/src/args/debug.rs diff --git a/crates/node-core/src/args/dev.rs b/crates/node/core/src/args/dev.rs similarity index 100% rename from crates/node-core/src/args/dev.rs rename to crates/node/core/src/args/dev.rs diff --git a/crates/node-core/src/args/gas_price_oracle.rs b/crates/node/core/src/args/gas_price_oracle.rs similarity index 98% rename from crates/node-core/src/args/gas_price_oracle.rs rename to crates/node/core/src/args/gas_price_oracle.rs index 5148fdca34b2..abdd8e14214f 100644 --- a/crates/node-core/src/args/gas_price_oracle.rs +++ b/crates/node/core/src/args/gas_price_oracle.rs @@ -1,6 +1,6 @@ use crate::primitives::U256; use clap::Args; -use reth_rpc::eth::gas_oracle::GasPriceOracleConfig; +use reth_rpc_eth_types::GasPriceOracleConfig; use reth_rpc_server_types::constants::gas_oracle::{ DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE, DEFAULT_MAX_GAS_PRICE, diff --git a/crates/node-core/src/args/log.rs b/crates/node/core/src/args/log.rs similarity index 100% rename from crates/node-core/src/args/log.rs rename to crates/node/core/src/args/log.rs diff --git a/crates/node-core/src/args/mod.rs b/crates/node/core/src/args/mod.rs similarity index 100% rename from crates/node-core/src/args/mod.rs rename to crates/node/core/src/args/mod.rs diff --git a/crates/node-core/src/args/network.rs b/crates/node/core/src/args/network.rs similarity index 82% rename from crates/node-core/src/args/network.rs rename to crates/node/core/src/args/network.rs index a5763495cd8d..03bd6a307830 100644 --- a/crates/node-core/src/args/network.rs +++ b/crates/node/core/src/args/network.rs @@ -2,11 +2,11 @@ use crate::version::P2P_CLIENT_VERSION; use clap::Args; -use reth_chainspec::{net::mainnet_nodes, ChainSpec}; +use reth_chainspec::ChainSpec; use reth_config::Config; -use reth_discv4::{DEFAULT_DISCOVERY_ADDR, DEFAULT_DISCOVERY_PORT}; +use reth_discv4::{NodeRecord, DEFAULT_DISCOVERY_ADDR, DEFAULT_DISCOVERY_PORT}; use reth_discv5::{ - DEFAULT_COUNT_BOOTSTRAP_LOOKUPS, DEFAULT_DISCOVERY_V5_PORT, + discv5::ListenConfig, DEFAULT_COUNT_BOOTSTRAP_LOOKUPS, DEFAULT_DISCOVERY_V5_PORT, DEFAULT_SECONDS_BOOTSTRAP_LOOKUP_INTERVAL, DEFAULT_SECONDS_LOOKUP_INTERVAL, }; use reth_net_nat::NatResolver; @@ -18,10 +18,10 @@ use reth_network::{ }, HelloMessageWithProtocols, NetworkConfigBuilder, SessionsConfig, }; -use reth_network_peers::TrustedPeer; +use reth_network_peers::{mainnet_nodes, TrustedPeer}; use secp256k1::SecretKey; use std::{ - net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, ops::Not, path::PathBuf, sync::Arc, @@ -173,23 +173,17 @@ impl NetworkArgs { // apply discovery settings .apply(|builder| { let rlpx_socket = (self.addr, self.port).into(); - self.discovery.apply_to_builder(builder, rlpx_socket) - }) - // modify discv5 settings if enabled in previous step - .map_discv5_config_builder(|builder| { - let DiscoveryArgs { - discv5_lookup_interval, - discv5_bootstrap_lookup_interval, - discv5_bootstrap_lookup_countdown, - .. - } = self.discovery; - - builder - .add_unsigned_boot_nodes(chain_bootnodes) - .lookup_interval(discv5_lookup_interval) - .bootstrap_lookup_interval(discv5_bootstrap_lookup_interval) - .bootstrap_lookup_countdown(discv5_bootstrap_lookup_countdown) + self.discovery.apply_to_builder(builder, rlpx_socket, chain_bootnodes) }) + .listener_addr(SocketAddr::new( + self.addr, // set discovery port based on instance number + self.port, + )) + .discovery_addr(SocketAddr::new( + self.discovery.addr, + // set discovery port based on instance number + self.discovery.port, + )) } /// If `no_persist_peers` is false then this returns the path to the persistent peers file path. @@ -211,6 +205,17 @@ impl NetworkArgs { self.discovery = self.discovery.with_unused_discovery_port(); self } + + /// Change networking port numbers based on the instance number. + /// Ports are updated to `previous_value + instance - 1` + /// + /// # Panics + /// Warning: if `instance` is zero in debug mode, this will panic. + pub fn adjust_instance_ports(&mut self, instance: u16) { + debug_assert_ne!(instance, 0, "instance must be non-zero"); + self.port += instance - 1; + self.discovery.adjust_instance_ports(instance); + } } impl Default for NetworkArgs { @@ -309,6 +314,7 @@ impl DiscoveryArgs { &self, mut network_config_builder: NetworkConfigBuilder, rlpx_tcp_socket: SocketAddr, + boot_nodes: impl IntoIterator, ) -> NetworkConfigBuilder { if self.disable_discovery || self.disable_dns_discovery { network_config_builder = network_config_builder.disable_dns_discovery(); @@ -319,19 +325,72 @@ impl DiscoveryArgs { } if !self.disable_discovery && self.enable_discv5_discovery { - network_config_builder = - network_config_builder.discovery_v5(reth_discv5::Config::builder(rlpx_tcp_socket)); + network_config_builder = network_config_builder + .discovery_v5(self.discovery_v5_builder(rlpx_tcp_socket, boot_nodes)); } network_config_builder } + /// Creates a [`reth_discv5::ConfigBuilder`] filling it with the values from this struct. + pub fn discovery_v5_builder( + &self, + rlpx_tcp_socket: SocketAddr, + boot_nodes: impl IntoIterator, + ) -> reth_discv5::ConfigBuilder { + let Self { + discv5_addr, + discv5_addr_ipv6, + discv5_port, + discv5_port_ipv6, + discv5_lookup_interval, + discv5_bootstrap_lookup_interval, + discv5_bootstrap_lookup_countdown, + .. + } = self; + + // Use rlpx address if none given + let discv5_addr_ipv4 = discv5_addr.or(match rlpx_tcp_socket { + SocketAddr::V4(addr) => Some(*addr.ip()), + SocketAddr::V6(_) => None, + }); + let discv5_addr_ipv6 = discv5_addr_ipv6.or(match rlpx_tcp_socket { + SocketAddr::V4(_) => None, + SocketAddr::V6(addr) => Some(*addr.ip()), + }); + + reth_discv5::Config::builder(rlpx_tcp_socket) + .discv5_config( + reth_discv5::discv5::ConfigBuilder::new(ListenConfig::from_two_sockets( + discv5_addr_ipv4.map(|addr| SocketAddrV4::new(addr, *discv5_port)), + discv5_addr_ipv6.map(|addr| SocketAddrV6::new(addr, *discv5_port_ipv6, 0, 0)), + )) + .build(), + ) + .add_unsigned_boot_nodes(boot_nodes) + .lookup_interval(*discv5_lookup_interval) + .bootstrap_lookup_interval(*discv5_bootstrap_lookup_interval) + .bootstrap_lookup_countdown(*discv5_bootstrap_lookup_countdown) + } + /// Set the discovery port to zero, to allow the OS to assign a random unused port when /// discovery binds to the socket. pub const fn with_unused_discovery_port(mut self) -> Self { self.port = 0; self } + + /// Change networking port numbers based on the instance number. + /// Ports are updated to `previous_value + instance - 1` + /// + /// # Panics + /// Warning: if `instance` is zero in debug mode, this will panic. + pub fn adjust_instance_ports(&mut self, instance: u16) { + debug_assert_ne!(instance, 0, "instance must be non-zero"); + self.port += instance - 1; + self.discv5_port += instance - 1; + self.discv5_port_ipv6 += instance - 1; + } } impl Default for DiscoveryArgs { diff --git a/crates/node-core/src/args/payload_builder.rs b/crates/node/core/src/args/payload_builder.rs similarity index 100% rename from crates/node-core/src/args/payload_builder.rs rename to crates/node/core/src/args/payload_builder.rs diff --git a/crates/node-core/src/args/pruning.rs b/crates/node/core/src/args/pruning.rs similarity index 100% rename from crates/node-core/src/args/pruning.rs rename to crates/node/core/src/args/pruning.rs diff --git a/crates/node-core/src/args/rpc_server.rs b/crates/node/core/src/args/rpc_server.rs similarity index 98% rename from crates/node-core/src/args/rpc_server.rs rename to crates/node/core/src/args/rpc_server.rs index 7ab2dd268fa1..bad1e24213b9 100644 --- a/crates/node-core/src/args/rpc_server.rs +++ b/crates/node/core/src/args/rpc_server.rs @@ -1,22 +1,22 @@ //! clap [Args](clap::Args) for RPC related arguments. -use crate::args::{ - types::{MaxU32, ZeroAsNoneU64}, - GasPriceOracleArgs, RpcStateCacheArgs, +use std::{ + ffi::OsStr, + net::{IpAddr, Ipv4Addr}, + path::PathBuf, }; + use alloy_rpc_types_engine::JwtSecret; use clap::{ builder::{PossibleValue, RangedU64ValueParser, TypedValueParser}, Arg, Args, Command, }; use rand::Rng; -use reth_rpc::eth::RPC_DEFAULT_GAS_CAP; - use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection}; -use std::{ - ffi::OsStr, - net::{IpAddr, Ipv4Addr}, - path::PathBuf, + +use crate::args::{ + types::{MaxU32, ZeroAsNoneU64}, + GasPriceOracleArgs, RpcStateCacheArgs, }; /// Default max number of subscriptions per connection. @@ -152,7 +152,7 @@ pub struct RpcServerArgs { alias = "rpc-gascap", value_name = "GAS_CAP", value_parser = RangedU64ValueParser::::new().range(1..), - default_value_t = RPC_DEFAULT_GAS_CAP.into() + default_value_t = constants::gas_oracle::RPC_DEFAULT_GAS_CAP )] pub rpc_gas_cap: u64, @@ -285,7 +285,7 @@ impl Default for RpcServerArgs { rpc_max_tracing_requests: constants::default_max_tracing_requests(), rpc_max_blocks_per_filter: constants::DEFAULT_MAX_BLOCKS_PER_FILTER.into(), rpc_max_logs_per_response: (constants::DEFAULT_MAX_LOGS_PER_RESPONSE as u64).into(), - rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(), + rpc_gas_cap: constants::gas_oracle::RPC_DEFAULT_GAS_CAP, gas_price_oracle: GasPriceOracleArgs::default(), rpc_state_cache: RpcStateCacheArgs::default(), } diff --git a/crates/node-core/src/args/rpc_state_cache.rs b/crates/node/core/src/args/rpc_state_cache.rs similarity index 100% rename from crates/node-core/src/args/rpc_state_cache.rs rename to crates/node/core/src/args/rpc_state_cache.rs diff --git a/crates/node-core/src/args/secret_key.rs b/crates/node/core/src/args/secret_key.rs similarity index 100% rename from crates/node-core/src/args/secret_key.rs rename to crates/node/core/src/args/secret_key.rs diff --git a/crates/node-core/src/args/stage.rs b/crates/node/core/src/args/stage.rs similarity index 100% rename from crates/node-core/src/args/stage.rs rename to crates/node/core/src/args/stage.rs diff --git a/crates/node-core/src/args/txpool.rs b/crates/node/core/src/args/txpool.rs similarity index 100% rename from crates/node-core/src/args/txpool.rs rename to crates/node/core/src/args/txpool.rs diff --git a/crates/node-core/src/args/types.rs b/crates/node/core/src/args/types.rs similarity index 100% rename from crates/node-core/src/args/types.rs rename to crates/node/core/src/args/types.rs diff --git a/crates/node-core/src/args/utils.rs b/crates/node/core/src/args/utils.rs similarity index 85% rename from crates/node-core/src/args/utils.rs rename to crates/node/core/src/args/utils.rs index 8a54a8942e1c..927204d22441 100644 --- a/crates/node-core/src/args/utils.rs +++ b/crates/node/core/src/args/utils.rs @@ -17,15 +17,21 @@ use reth_chainspec::DEV; #[cfg(feature = "optimism")] use reth_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA}; -#[cfg(not(feature = "optimism"))] +#[cfg(not(any(feature = "optimism", feature = "taiko")))] use reth_chainspec::{GOERLI, HOLESKY, MAINNET, SEPOLIA}; +#[cfg(feature = "taiko")] +use reth_chainspec::{TAIKO_INTERNAL_L2_A, TAIKO_TESTNET}; + #[cfg(feature = "optimism")] /// Chains supported by op-reth. First value should be used as the default. pub const SUPPORTED_CHAINS: &[&str] = &["optimism", "optimism-sepolia", "base", "base-sepolia"]; -#[cfg(not(feature = "optimism"))] +#[cfg(not(any(feature = "optimism", feature = "taiko")))] /// Chains supported by reth. First value should be used as the default. pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "goerli", "holesky", "dev"]; +#[cfg(feature = "taiko")] +/// Chains supported by taiko-reth. First value should be used as default. +pub const SUPPORTED_CHAINS: &[&str] = &["testnet", "internal_devnet_a"]; /// Helper to parse a [Duration] from seconds pub fn parse_duration_from_secs(arg: &str) -> eyre::Result { @@ -44,13 +50,13 @@ pub fn chain_help() -> String { /// to a json file, or a json formatted string in-memory. The json needs to be a Genesis struct. pub fn chain_value_parser(s: &str) -> eyre::Result, eyre::Error> { Ok(match s { - #[cfg(not(feature = "optimism"))] + #[cfg(not(any(feature = "optimism", feature = "taiko")))] "mainnet" => MAINNET.clone(), - #[cfg(not(feature = "optimism"))] + #[cfg(not(any(feature = "optimism", feature = "taiko")))] "goerli" => GOERLI.clone(), - #[cfg(not(feature = "optimism"))] + #[cfg(not(any(feature = "optimism", feature = "taiko")))] "sepolia" => SEPOLIA.clone(), - #[cfg(not(feature = "optimism"))] + #[cfg(not(any(feature = "optimism", feature = "taiko")))] "holesky" => HOLESKY.clone(), "dev" => DEV.clone(), #[cfg(feature = "optimism")] @@ -61,6 +67,10 @@ pub fn chain_value_parser(s: &str) -> eyre::Result, eyre::Error> "base" => BASE_MAINNET.clone(), #[cfg(feature = "optimism")] "base_sepolia" | "base-sepolia" => BASE_SEPOLIA.clone(), + #[cfg(feature = "taiko")] + "testnet" => TAIKO_TESTNET.clone(), + #[cfg(feature = "taiko")] + "internal_devnet_a" => TAIKO_INTERNAL_L2_A.clone(), _ => { // try to read json from path first let raw = match fs::read_to_string(PathBuf::from(shellexpand::full(s)?.into_owned())) { @@ -70,7 +80,7 @@ pub fn chain_value_parser(s: &str) -> eyre::Result, eyre::Error> if s.contains('{') { s.to_string() } else { - return Err(io_err.into()) // assume invalid path + return Err(io_err.into()); // assume invalid path } } }; @@ -120,15 +130,15 @@ pub enum SocketAddressParsingError { /// An error is returned if the value is empty. pub fn parse_socket_address(value: &str) -> eyre::Result { if value.is_empty() { - return Err(SocketAddressParsingError::Empty) + return Err(SocketAddressParsingError::Empty); } if let Some(port) = value.strip_prefix(':').or_else(|| value.strip_prefix("localhost:")) { let port: u16 = port.parse()?; - return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) + return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)); } if let Ok(port) = value.parse::() { - return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)) + return Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port)); } value .to_socket_addrs()? diff --git a/crates/node-core/src/cli/config.rs b/crates/node/core/src/cli/config.rs similarity index 100% rename from crates/node-core/src/cli/config.rs rename to crates/node/core/src/cli/config.rs diff --git a/crates/node-core/src/cli/mod.rs b/crates/node/core/src/cli/mod.rs similarity index 100% rename from crates/node-core/src/cli/mod.rs rename to crates/node/core/src/cli/mod.rs diff --git a/crates/node-core/src/dirs.rs b/crates/node/core/src/dirs.rs similarity index 100% rename from crates/node-core/src/dirs.rs rename to crates/node/core/src/dirs.rs diff --git a/crates/node-core/src/exit.rs b/crates/node/core/src/exit.rs similarity index 53% rename from crates/node-core/src/exit.rs rename to crates/node/core/src/exit.rs index 7957af1854fc..5dc6e5638d80 100644 --- a/crates/node-core/src/exit.rs +++ b/crates/node/core/src/exit.rs @@ -1,32 +1,39 @@ //! Helper types for waiting for the node to exit. -use futures::FutureExt; -use reth_beacon_consensus::BeaconConsensusEngineError; +use futures::{future::BoxFuture, FutureExt}; use std::{ + fmt, future::Future, pin::Pin, task::{ready, Context, Poll}, }; -use tokio::sync::oneshot; /// A Future which resolves when the node exits -#[derive(Debug)] pub struct NodeExitFuture { - /// The receiver half of the channel for the consensus engine. - /// This can be used to wait for the consensus engine to exit. - consensus_engine_rx: Option>>, + /// The consensus engine future. + /// This can be polled to wait for the consensus engine to exit. + consensus_engine_fut: Option>>, /// Flag indicating whether the node should be terminated after the pipeline sync. terminate: bool, } +impl fmt::Debug for NodeExitFuture { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NodeExitFuture") + .field("consensus_engine_fut", &"...") + .field("terminate", &self.terminate) + .finish() + } +} + impl NodeExitFuture { /// Create a new `NodeExitFuture`. - pub const fn new( - consensus_engine_rx: oneshot::Receiver>, - terminate: bool, - ) -> Self { - Self { consensus_engine_rx: Some(consensus_engine_rx), terminate } + pub fn new(consensus_engine_fut: F, terminate: bool) -> Self + where + F: Future> + 'static + Send, + { + Self { consensus_engine_fut: Some(Box::pin(consensus_engine_fut)), terminate } } } @@ -35,18 +42,17 @@ impl Future for NodeExitFuture { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); - if let Some(rx) = this.consensus_engine_rx.as_mut() { + if let Some(rx) = this.consensus_engine_fut.as_mut() { match ready!(rx.poll_unpin(cx)) { - Ok(res) => { - this.consensus_engine_rx.take(); - res?; + Ok(_) => { + this.consensus_engine_fut.take(); if this.terminate { Poll::Ready(Ok(())) } else { Poll::Pending } } - Err(err) => Poll::Ready(Err(err.into())), + Err(err) => Poll::Ready(Err(err)), } } else { Poll::Pending @@ -61,11 +67,9 @@ mod tests { #[tokio::test] async fn test_node_exit_future_terminate_true() { - let (tx, rx) = oneshot::channel::>(); + let fut = async { Ok(()) }; - let _ = tx.send(Ok(())); - - let node_exit_future = NodeExitFuture::new(rx, true); + let node_exit_future = NodeExitFuture::new(fut, true); let res = node_exit_future.await; @@ -74,11 +78,9 @@ mod tests { #[tokio::test] async fn test_node_exit_future_terminate_false() { - let (tx, rx) = oneshot::channel::>(); - - let _ = tx.send(Ok(())); + let fut = async { Ok(()) }; - let mut node_exit_future = NodeExitFuture::new(rx, false); + let mut node_exit_future = NodeExitFuture::new(fut, false); poll_fn(|cx| { assert!(node_exit_future.poll_unpin(cx).is_pending()); Poll::Ready(()) diff --git a/crates/node-core/src/lib.rs b/crates/node/core/src/lib.rs similarity index 93% rename from crates/node-core/src/lib.rs rename to crates/node/core/src/lib.rs index a8761110aeae..27a81cc26e7c 100644 --- a/crates/node-core/src/lib.rs +++ b/crates/node/core/src/lib.rs @@ -11,7 +11,6 @@ pub mod args; pub mod cli; pub mod dirs; -pub mod engine; pub mod exit; pub mod metrics; pub mod node_config; @@ -39,12 +38,12 @@ pub mod rpc { } /// Re-exported from `reth_rpc::eth`. pub mod eth { - pub use reth_rpc::eth::*; + pub use reth_rpc_eth_api::*; } /// Re-exported from `reth_rpc::rpc`. pub mod result { - pub use reth_rpc::result::*; + pub use reth_rpc_server_types::result::*; } /// Re-exported from `reth_rpc::eth`. diff --git a/crates/node-core/src/metrics/mod.rs b/crates/node/core/src/metrics/mod.rs similarity index 100% rename from crates/node-core/src/metrics/mod.rs rename to crates/node/core/src/metrics/mod.rs diff --git a/crates/node-core/src/metrics/prometheus_exporter.rs b/crates/node/core/src/metrics/prometheus_exporter.rs similarity index 98% rename from crates/node-core/src/metrics/prometheus_exporter.rs rename to crates/node/core/src/metrics/prometheus_exporter.rs index b7a3ba7015c3..5e049cc977fe 100644 --- a/crates/node-core/src/metrics/prometheus_exporter.rs +++ b/crates/node/core/src/metrics/prometheus_exporter.rs @@ -1,6 +1,6 @@ //! Prometheus exporter -use crate::metrics::version_metrics::register_version_metrics; +use crate::metrics::version_metrics::VersionInfo; use eyre::WrapErr; use futures::{future::FusedFuture, FutureExt}; use http::Response; @@ -151,7 +151,7 @@ where process.describe(); describe_memory_stats(); describe_io_stats(); - register_version_metrics(); + VersionInfo::default().register_version_metrics(); Ok(()) } diff --git a/crates/node/core/src/metrics/version_metrics.rs b/crates/node/core/src/metrics/version_metrics.rs new file mode 100644 index 000000000000..cea907fc3ca0 --- /dev/null +++ b/crates/node/core/src/metrics/version_metrics.rs @@ -0,0 +1,50 @@ +//! This exposes reth's version information over prometheus. + +use crate::version::{build_profile_name, VERGEN_GIT_SHA}; +use metrics::gauge; + +/// Contains version information for the application. +#[derive(Debug, Clone)] +pub struct VersionInfo { + /// The version of the application. + pub version: &'static str, + /// The build timestamp of the application. + pub build_timestamp: &'static str, + /// The cargo features enabled for the build. + pub cargo_features: &'static str, + /// The Git SHA of the build. + pub git_sha: &'static str, + /// The target triple for the build. + pub target_triple: &'static str, + /// The build profile (e.g., debug or release). + pub build_profile: &'static str, +} + +impl Default for VersionInfo { + fn default() -> Self { + Self { + version: env!("CARGO_PKG_VERSION"), + build_timestamp: env!("VERGEN_BUILD_TIMESTAMP"), + cargo_features: env!("VERGEN_CARGO_FEATURES"), + git_sha: VERGEN_GIT_SHA, + target_triple: env!("VERGEN_CARGO_TARGET_TRIPLE"), + build_profile: build_profile_name(), + } + } +} + +impl VersionInfo { + /// This exposes reth's version information over prometheus. + pub fn register_version_metrics(&self) { + let labels: [(&str, &str); 6] = [ + ("version", self.version), + ("build_timestamp", self.build_timestamp), + ("cargo_features", self.cargo_features), + ("git_sha", self.git_sha), + ("target_triple", self.target_triple), + ("build_profile", self.build_profile), + ]; + + let _gauge = gauge!("info", &labels); + } +} diff --git a/crates/node-core/src/node_config.rs b/crates/node/core/src/node_config.rs similarity index 99% rename from crates/node-core/src/node_config.rs rename to crates/node/core/src/node_config.rs index 932c12e70436..8f9ff42f9eae 100644 --- a/crates/node-core/src/node_config.rs +++ b/crates/node/core/src/node_config.rs @@ -390,6 +390,7 @@ impl NodeConfig { /// [`RpcServerArgs::adjust_instance_ports`] method. pub fn adjust_instance_ports(&mut self) { self.rpc.adjust_instance_ports(self.instance); + self.network.adjust_instance_ports(self.instance); } /// Sets networking and RPC ports to zero, causing the OS to choose random unused ports when diff --git a/crates/node-core/src/utils.rs b/crates/node/core/src/utils.rs similarity index 100% rename from crates/node-core/src/utils.rs rename to crates/node/core/src/utils.rs diff --git a/crates/node-core/src/version.rs b/crates/node/core/src/version.rs similarity index 80% rename from crates/node-core/src/version.rs rename to crates/node/core/src/version.rs index db8bf09d1fe5..5151b861d586 100644 --- a/crates/node-core/src/version.rs +++ b/crates/node/core/src/version.rs @@ -11,8 +11,11 @@ pub const NAME_CLIENT: &str = "Reth"; /// The latest version from Cargo.toml. pub const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); -/// The short SHA of the latest commit. -pub const VERGEN_GIT_SHA: &str = env!("VERGEN_GIT_SHA"); +/// The full SHA of the latest commit. +pub const VERGEN_GIT_SHA_LONG: &str = env!("VERGEN_GIT_SHA"); + +/// The 8 character short SHA of the latest commit. +pub const VERGEN_GIT_SHA: &str = const_format::str_index!(VERGEN_GIT_SHA_LONG, ..8); /// The build timestamp. pub const VERGEN_BUILD_TIMESTAMP: &str = env!("VERGEN_BUILD_TIMESTAMP"); @@ -27,11 +30,11 @@ pub const VERGEN_BUILD_TIMESTAMP: &str = env!("VERGEN_BUILD_TIMESTAMP"); /// ```text /// 0.1.0 (defa64b2) /// ``` -pub const SHORT_VERSION: &str = concat!( +pub const SHORT_VERSION: &str = const_format::concatcp!( env!("CARGO_PKG_VERSION"), env!("RETH_VERSION_SUFFIX"), " (", - env!("VERGEN_GIT_SHA"), + VERGEN_GIT_SHA, ")" ); @@ -52,13 +55,13 @@ pub const SHORT_VERSION: &str = concat!( /// Build Features: jemalloc /// Build Profile: maxperf /// ``` -pub const LONG_VERSION: &str = const_str::concat!( +pub const LONG_VERSION: &str = const_format::concatcp!( "Version: ", env!("CARGO_PKG_VERSION"), env!("RETH_VERSION_SUFFIX"), "\n", "Commit SHA: ", - env!("VERGEN_GIT_SHA"), + VERGEN_GIT_SHA_LONG, "\n", "Build Timestamp: ", env!("VERGEN_BUILD_TIMESTAMP"), @@ -81,11 +84,11 @@ pub const LONG_VERSION: &str = const_str::concat!( /// reth/v{major}.{minor}.{patch}-{sha1}/{target} /// ``` /// e.g.: `reth/v0.1.0-alpha.1-428a6dc2f/aarch64-apple-darwin` -pub(crate) const P2P_CLIENT_VERSION: &str = concat!( +pub(crate) const P2P_CLIENT_VERSION: &str = const_format::concatcp!( "reth/v", env!("CARGO_PKG_VERSION"), "-", - env!("VERGEN_GIT_SHA"), + VERGEN_GIT_SHA, "/", env!("VERGEN_CARGO_TARGET_TRIPLE") ); @@ -118,9 +121,13 @@ pub(crate) const fn build_profile_name() -> &'static str { // We split on the path separator of the *host* machine, which may be different from // `std::path::MAIN_SEPARATOR_STR`. const OUT_DIR: &str = env!("OUT_DIR"); - const SEP: char = if const_str::contains!(OUT_DIR, "/") { '/' } else { '\\' }; - let parts = const_str::split!(OUT_DIR, SEP); - parts[parts.len() - 4] + let unix_parts = const_format::str_split!(OUT_DIR, '/'); + if unix_parts.len() >= 4 { + unix_parts[unix_parts.len() - 4] + } else { + let win_parts = const_format::str_split!(OUT_DIR, '\\'); + win_parts[win_parts.len() - 4] + } } #[cfg(test)] diff --git a/crates/optimism/cli/Cargo.toml b/crates/optimism/cli/Cargo.toml new file mode 100644 index 000000000000..05201b658f76 --- /dev/null +++ b/crates/optimism/cli/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "reth-optimism-cli" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] diff --git a/crates/optimism/cli/src/lib.rs b/crates/optimism/cli/src/lib.rs new file mode 100644 index 000000000000..a5133bea139c --- /dev/null +++ b/crates/optimism/cli/src/lib.rs @@ -0,0 +1,9 @@ +//! OP-Reth CLI implementation. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 0c5439bf7448..61aa23bde15f 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -9,7 +9,7 @@ // The `optimism` feature must be enabled to use this crate. #![cfg(feature = "optimism")] -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardforks}; use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ validate_against_parent_4844, validate_against_parent_eip1559_base_fee, diff --git a/crates/optimism/consensus/src/validation.rs b/crates/optimism/consensus/src/validation.rs index 8aa00c53cec4..d7bb7681c517 100644 --- a/crates/optimism/consensus/src/validation.rs +++ b/crates/optimism/consensus/src/validation.rs @@ -1,4 +1,4 @@ -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus::ConsensusError; use reth_primitives::{ gas_spent_by_transactions, proofs::calculate_receipt_root_optimism, BlockWithSenders, Bloom, diff --git a/crates/optimism/evm/Cargo.toml b/crates/optimism/evm/Cargo.toml index 47c8cedee294..f53293edeebf 100644 --- a/crates/optimism/evm/Cargo.toml +++ b/crates/optimism/evm/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # Reth reth-chainspec.workspace = true +reth-ethereum-forks.workspace = true reth-evm.workspace = true reth-primitives.workspace = true reth-revm.workspace = true diff --git a/crates/optimism/evm/src/config.rs b/crates/optimism/evm/src/config.rs new file mode 100644 index 000000000000..1cdc917eac85 --- /dev/null +++ b/crates/optimism/evm/src/config.rs @@ -0,0 +1,133 @@ +use reth_chainspec::{ChainSpec, OptimismHardfork}; +use reth_ethereum_forks::{EthereumHardfork, Head}; + +/// Returns the spec id at the given timestamp. +/// +/// Note: This is only intended to be used after the merge, when hardforks are activated by +/// timestamp. +pub fn revm_spec_by_timestamp_after_bedrock( + chain_spec: &ChainSpec, + timestamp: u64, +) -> revm_primitives::SpecId { + if chain_spec.fork(OptimismHardfork::Fjord).active_at_timestamp(timestamp) { + revm_primitives::FJORD + } else if chain_spec.fork(OptimismHardfork::Ecotone).active_at_timestamp(timestamp) { + revm_primitives::ECOTONE + } else if chain_spec.fork(OptimismHardfork::Canyon).active_at_timestamp(timestamp) { + revm_primitives::CANYON + } else if chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(timestamp) { + revm_primitives::REGOLITH + } else { + revm_primitives::BEDROCK + } +} + +/// return `revm_spec` from spec configuration. +pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecId { + if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) { + revm_primitives::FJORD + } else if chain_spec.fork(OptimismHardfork::Ecotone).active_at_head(block) { + revm_primitives::ECOTONE + } else if chain_spec.fork(OptimismHardfork::Canyon).active_at_head(block) { + revm_primitives::CANYON + } else if chain_spec.fork(OptimismHardfork::Regolith).active_at_head(block) { + revm_primitives::REGOLITH + } else if chain_spec.fork(OptimismHardfork::Bedrock).active_at_head(block) { + revm_primitives::BEDROCK + } else if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { + revm_primitives::PRAGUE + } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(block) { + revm_primitives::CANCUN + } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) { + revm_primitives::SHANGHAI + } else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(block) { + revm_primitives::MERGE + } else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) { + revm_primitives::LONDON + } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(block) { + revm_primitives::BERLIN + } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(block) { + revm_primitives::ISTANBUL + } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(block) { + revm_primitives::PETERSBURG + } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(block) { + revm_primitives::BYZANTIUM + } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(block) { + revm_primitives::SPURIOUS_DRAGON + } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(block) { + revm_primitives::TANGERINE + } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(block) { + revm_primitives::HOMESTEAD + } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(block) { + revm_primitives::FRONTIER + } else { + panic!( + "invalid hardfork chainspec: expected at least one hardfork, got {:?}", + chain_spec.hardforks + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use reth_chainspec::ChainSpecBuilder; + + #[test] + fn test_revm_spec_by_timestamp_after_merge() { + #[inline(always)] + fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec { + let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)); + f(cs).build() + } + assert_eq!( + revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.fjord_activated()), 0), + revm_primitives::FJORD + ); + assert_eq!( + revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.ecotone_activated()), 0), + revm_primitives::ECOTONE + ); + assert_eq!( + revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.canyon_activated()), 0), + revm_primitives::CANYON + ); + assert_eq!( + revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.bedrock_activated()), 0), + revm_primitives::BEDROCK + ); + assert_eq!( + revm_spec_by_timestamp_after_bedrock(&op_cs(|cs| cs.regolith_activated()), 0), + revm_primitives::REGOLITH + ); + } + + #[test] + fn test_to_revm_spec() { + #[inline(always)] + fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec { + let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)); + f(cs).build() + } + assert_eq!( + revm_spec(&op_cs(|cs| cs.fjord_activated()), &Head::default()), + revm_primitives::FJORD + ); + assert_eq!( + revm_spec(&op_cs(|cs| cs.ecotone_activated()), &Head::default()), + revm_primitives::ECOTONE + ); + assert_eq!( + revm_spec(&op_cs(|cs| cs.canyon_activated()), &Head::default()), + revm_primitives::CANYON + ); + assert_eq!( + revm_spec(&op_cs(|cs| cs.bedrock_activated()), &Head::default()), + revm_primitives::BEDROCK + ); + assert_eq!( + revm_spec(&op_cs(|cs| cs.regolith_activated()), &Head::default()), + revm_primitives::REGOLITH + ); + } +} diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index e6130295f455..1f873d234a46 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -1,7 +1,7 @@ //! Optimism block executor. use crate::{l1::ensure_create2_deployer, OptimismBlockExecutionError, OptimismEvmConfig}; -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork}; use reth_evm::{ execute::{ BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, @@ -11,9 +11,7 @@ use reth_evm::{ }; use reth_execution_types::ExecutionOutcome; use reth_optimism_consensus::validate_block_post_execution; -use reth_primitives::{ - BlockNumber, BlockWithSenders, Header, Receipt, Receipts, TxType, Withdrawals, U256, -}; +use reth_primitives::{BlockNumber, BlockWithSenders, Header, Receipt, Receipts, TxType, U256}; use reth_prune_types::PruneModes; use reth_revm::{ batch::{BlockBatchRecord, BlockExecutorStats}, @@ -23,7 +21,7 @@ use reth_revm::{ }; use revm_primitives::{ db::{Database, DatabaseCommit}, - BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, + BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, ResultAndState, }; use std::sync::Arc; use tracing::trace; @@ -55,7 +53,7 @@ where { fn op_executor(&self, db: DB) -> OpBlockExecutor where - DB: Database, + DB: Database + std::fmt::Display>, { OpBlockExecutor::new( self.chain_spec.clone(), @@ -69,19 +67,21 @@ impl BlockExecutorProvider for OpExecutorProvider where EvmConfig: ConfigureEvm, { - type Executor> = OpBlockExecutor; + type Executor + std::fmt::Display>> = + OpBlockExecutor; - type BatchExecutor> = OpBatchExecutor; + type BatchExecutor + std::fmt::Display>> = + OpBatchExecutor; fn executor(&self, db: DB) -> Self::Executor where - DB: Database, + DB: Database + std::fmt::Display>, { self.op_executor(db) } fn batch_executor(&self, db: DB, prune_modes: PruneModes) -> Self::BatchExecutor where - DB: Database, + DB: Database + std::fmt::Display>, { let executor = self.op_executor(db); OpBatchExecutor { @@ -118,7 +118,7 @@ where mut evm: Evm<'_, Ext, &mut State>, ) -> Result<(Vec, u64), BlockExecutionError> where - DB: Database, + DB: Database + std::fmt::Display>, { // apply pre execution changes apply_beacon_root_contract_call( @@ -131,7 +131,7 @@ where // execute transactions let is_regolith = - self.chain_spec.fork(Hardfork::Regolith).active_at_timestamp(block.timestamp); + self.chain_spec.fork(OptimismHardfork::Regolith).active_at_timestamp(block.timestamp); // Ensure that the create2deployer is force-deployed at the canyon transition. Optimism // blocks will always have at least a single transaction in them (the L1 info transaction), @@ -175,14 +175,21 @@ where .transpose() .map_err(|_| OptimismBlockExecutionError::AccountLoadFailed(*sender))?; - EvmConfig::fill_tx_env(evm.tx_mut(), transaction, *sender); + self.evm_config.fill_tx_env(evm.tx_mut(), transaction, *sender); // Execute transaction. let ResultAndState { result, state } = evm.transact().map_err(move |err| { + let new_err = match err { + EVMError::Transaction(e) => EVMError::Transaction(e), + EVMError::Header(e) => EVMError::Header(e), + EVMError::Database(e) => EVMError::Database(e.into()), + EVMError::Custom(e) => EVMError::Custom(e), + EVMError::Precompile(e) => EVMError::Precompile(e), + }; // Ensure hash is calculated for error log, if not already done BlockValidationError::EVM { hash: transaction.recalculate_hash(), - error: err.into(), + error: Box::new(new_err), } })?; @@ -211,7 +218,7 @@ where // this is only set for post-Canyon deposit transactions. deposit_receipt_version: (transaction.is_deposit() && self.chain_spec - .is_fork_active_at_timestamp(Hardfork::Canyon, block.timestamp)) + .is_fork_active_at_timestamp(OptimismHardfork::Canyon, block.timestamp)) .then_some(1), }); } @@ -255,7 +262,7 @@ impl OpBlockExecutor { impl OpBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + std::fmt::Display>, { /// Configures a new evm configuration and block environment for the given block. /// @@ -315,16 +322,8 @@ where block: &BlockWithSenders, total_difficulty: U256, ) -> Result<(), BlockExecutionError> { - let balance_increments = post_block_balance_increments( - self.chain_spec(), - block.number, - block.difficulty, - block.beneficiary, - block.timestamp, - total_difficulty, - &block.ommers, - block.withdrawals.as_ref().map(Withdrawals::as_ref), - ); + let balance_increments = + post_block_balance_increments(self.chain_spec(), block, total_difficulty); // increment balances self.state .increment_balances(balance_increments) @@ -337,7 +336,7 @@ where impl Executor for OpBlockExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + std::fmt::Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = BlockExecutionOutput; @@ -394,7 +393,7 @@ impl OpBatchExecutor { impl BatchExecutor for OpBatchExecutor where EvmConfig: ConfigureEvm, - DB: Database, + DB: Database + std::fmt::Display>, { type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>; type Output = ExecutionOutcome; diff --git a/crates/optimism/evm/src/l1.rs b/crates/optimism/evm/src/l1.rs index a750c8f4f0a9..62b412891f64 100644 --- a/crates/optimism/evm/src/l1.rs +++ b/crates/optimism/evm/src/l1.rs @@ -1,7 +1,7 @@ //! Optimism-specific implementation and utilities for the executor use crate::OptimismBlockExecutionError; -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, OptimismHardfork}; use reth_execution_errors::BlockExecutionError; use reth_primitives::{address, b256, hex, Address, Block, Bytes, B256, U256}; use revm::{ @@ -191,13 +191,14 @@ impl RethL1BlockInfo for L1BlockInfo { return Ok(U256::ZERO) } - let spec_id = if chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, timestamp) { + let spec_id = if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, timestamp) + { SpecId::FJORD - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Ecotone, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Ecotone, timestamp) { SpecId::ECOTONE - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) { SpecId::REGOLITH - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Bedrock, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Bedrock, timestamp) { SpecId::BEDROCK } else { return Err(OptimismBlockExecutionError::L1BlockInfoError { @@ -214,11 +215,12 @@ impl RethL1BlockInfo for L1BlockInfo { timestamp: u64, input: &[u8], ) -> Result { - let spec_id = if chain_spec.is_fork_active_at_timestamp(Hardfork::Fjord, timestamp) { + let spec_id = if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Fjord, timestamp) + { SpecId::FJORD - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Regolith, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Regolith, timestamp) { SpecId::REGOLITH - } else if chain_spec.is_fork_active_at_timestamp(Hardfork::Bedrock, timestamp) { + } else if chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Bedrock, timestamp) { SpecId::BEDROCK } else { return Err(OptimismBlockExecutionError::L1BlockInfoError { @@ -245,8 +247,9 @@ where // previous block timestamp (heuristically, block time is not perfectly constant at 2s), and the // chain is an optimism chain, then we need to force-deploy the create2 deployer contract. if chain_spec.is_optimism() && - chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, timestamp) && - !chain_spec.is_fork_active_at_timestamp(Hardfork::Canyon, timestamp.saturating_sub(2)) + chain_spec.is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(OptimismHardfork::Canyon, timestamp.saturating_sub(2)) { trace!(target: "evm", "Forcing create2 deployer contract deployment on Canyon transition"); diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index d13168bfe0c6..5dff8d5de312 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -12,12 +12,14 @@ use reth_chainspec::ChainSpec; use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::{ - revm::{config::revm_spec, env::fill_op_tx_env}, + revm::env::fill_op_tx_env, revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv}, Address, Head, Header, TransactionSigned, U256, }; use reth_revm::{inspector_handle_register, Database, Evm, EvmBuilder, GetInspector}; +mod config; +pub use config::{revm_spec, revm_spec_by_timestamp_after_bedrock}; mod execute; pub use execute::*; pub mod l1; @@ -32,7 +34,7 @@ pub use error::OptimismBlockExecutionError; pub struct OptimismEvmConfig; impl ConfigureEvmEnv for OptimismEvmConfig { - fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { + fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { let mut buf = Vec::with_capacity(transaction.length_without_header()); transaction.encode_enveloped(&mut buf); fill_op_tx_env(tx_env, transaction, sender, buf.into()); @@ -46,7 +48,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig { ) { let spec_id = revm_spec( chain_spec, - Head { + &Head { number: header.number, timestamp: header.timestamp, difficulty: header.difficulty, diff --git a/crates/optimism/node/Cargo.toml b/crates/optimism/node/Cargo.toml index f85e7baf696d..5d172ec93b73 100644 --- a/crates/optimism/node/Cargo.toml +++ b/crates/optimism/node/Cargo.toml @@ -35,6 +35,8 @@ reth-beacon-consensus.workspace = true reth-optimism-consensus.workspace = true revm-primitives.workspace = true reth-discv5.workspace = true +reth-rpc-eth-types.workspace = true +reth-rpc-eth-api.workspace = true # async async-trait.workspace = true @@ -44,11 +46,14 @@ tracing.workspace = true # misc clap.workspace = true serde.workspace = true -serde_json.workspace = true eyre.workspace = true parking_lot.workspace = true thiserror.workspace = true + +# rpc jsonrpsee.workspace = true +jsonrpsee-types.workspace = true +serde_json.workspace = true [dev-dependencies] reth.workspace = true @@ -71,4 +76,5 @@ optimism = [ "reth-beacon-consensus/optimism", "reth-revm/optimism", "reth-auto-seal-consensus/optimism", + "reth-rpc-eth-types/optimism" ] diff --git a/crates/optimism/node/src/engine.rs b/crates/optimism/node/src/engine.rs index 6507d5c9290f..d0fc9b53ef1e 100644 --- a/crates/optimism/node/src/engine.rs +++ b/crates/optimism/node/src/engine.rs @@ -1,4 +1,4 @@ -use reth_chainspec::{ChainSpec, Hardfork}; +use reth_chainspec::{ChainSpec, OptimismHardfork}; use reth_node_api::{ payload::{ validate_parent_beacon_block_root_presence, EngineApiMessageVersion, @@ -69,7 +69,7 @@ pub fn validate_withdrawals_presence( timestamp: u64, has_withdrawals: bool, ) -> Result<(), EngineObjectValidationError> { - let is_shanghai = chain_spec.fork(Hardfork::Canyon).active_at_timestamp(timestamp); + let is_shanghai = chain_spec.fork(OptimismHardfork::Canyon).active_at_timestamp(timestamp); match version { EngineApiMessageVersion::V1 => { diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index d8628dc6bf85..2ea24da6754a 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -283,27 +283,17 @@ where // purposefully disable discv4 .disable_discv4_discovery() // apply discovery settings - .apply(|builder| { + .apply(|mut builder| { let rlpx_socket = (args.addr, args.port).into(); - let mut builder = args.discovery.apply_to_builder(builder, rlpx_socket); if !args.discovery.disable_discovery { - builder = builder.discovery_v5(reth_discv5::Config::builder(rlpx_socket)); + builder = builder.discovery_v5(args.discovery.discovery_v5_builder( + rlpx_socket, + ctx.chain_spec().bootnodes().unwrap_or_default(), + )); } builder - }) - // ensure we configure discv5 - .map_discv5_config_builder(|builder| { - builder - .add_unsigned_boot_nodes(ctx.chain_spec().bootnodes().unwrap_or_default()) - .lookup_interval(ctx.config().network.discovery.discv5_lookup_interval) - .bootstrap_lookup_interval( - ctx.config().network.discovery.discv5_bootstrap_lookup_interval, - ) - .bootstrap_lookup_countdown( - ctx.config().network.discovery.discv5_bootstrap_lookup_countdown, - ) }); let mut network_config = ctx.build_network_config(network_builder); diff --git a/crates/optimism/node/src/rpc.rs b/crates/optimism/node/src/rpc.rs index 5ae1ba7b2538..d7c3f49efbc9 100644 --- a/crates/optimism/node/src/rpc.rs +++ b/crates/optimism/node/src/rpc.rs @@ -1,13 +1,12 @@ //! Helpers for optimism specific RPC implementations. -use jsonrpsee::types::ErrorObject; +use std::sync::{atomic::AtomicUsize, Arc}; + +use jsonrpsee_types::error::{ErrorObject, INTERNAL_ERROR_CODE}; use reqwest::Client; -use reth_rpc::eth::{ - error::{EthApiError, EthResult}, - traits::RawTransactionForwarder, -}; +use reth_rpc_eth_api::RawTransactionForwarder; +use reth_rpc_eth_types::error::{EthApiError, EthResult}; use reth_rpc_types::ToRpcError; -use std::sync::{atomic::AtomicUsize, Arc}; /// Error type when interacting with the Sequencer #[derive(Debug, thiserror::Error)] @@ -22,11 +21,7 @@ pub enum SequencerRpcError { impl ToRpcError for SequencerRpcError { fn to_rpc_error(&self) -> ErrorObject<'static> { - ErrorObject::owned( - jsonrpsee::types::error::INTERNAL_ERROR_CODE, - self.to_string(), - None::, - ) + ErrorObject::owned(INTERNAL_ERROR_CODE, self.to_string(), None::) } } diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index fa17982cb8c6..3b08b8df0a18 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -5,7 +5,7 @@ use crate::{ payload::{OptimismBuiltPayload, OptimismPayloadBuilderAttributes}, }; use reth_basic_payload_builder::*; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks, OptimismHardfork}; use reth_evm::ConfigureEvm; use reth_execution_types::ExecutionOutcome; use reth_payload_builder::error::PayloadBuilderError; @@ -14,8 +14,7 @@ use reth_primitives::{ eip4844::calculate_excess_blob_gas, proofs, revm::env::tx_env_with_recovered, - Block, Hardfork, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, - U256, + Block, Header, IntoRecoveredTransaction, Receipt, TxType, EMPTY_OMMER_ROOT_HASH, U256, }; use reth_provider::StateProviderFactory; use reth_revm::database::StateProviderDatabase; @@ -281,8 +280,10 @@ where let block_number = initialized_block_env.number.to::(); - let is_regolith = chain_spec - .is_fork_active_at_timestamp(Hardfork::Regolith, attributes.payload_attributes.timestamp); + let is_regolith = chain_spec.is_fork_active_at_timestamp( + OptimismHardfork::Regolith, + attributes.payload_attributes.timestamp, + ); // apply eip-4788 pre block contract call pre_block_beacon_root_contract_call( @@ -393,7 +394,7 @@ where // ensures this is only set for post-Canyon deposit transactions. deposit_receipt_version: chain_spec .is_fork_active_at_timestamp( - Hardfork::Canyon, + OptimismHardfork::Canyon, attributes.payload_attributes.timestamp, ) .then_some(1), diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index ae63246558dd..47db0d571ed8 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -3,11 +3,11 @@ //! Optimism builder support use alloy_rlp::Encodable; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_evm_optimism::revm_spec_by_timestamp_after_bedrock; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_payload_primitives::{BuiltPayload, PayloadBuilderAttributes}; use reth_primitives::{ - revm::config::revm_spec_by_timestamp_after_merge, revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, Address, BlobTransactionSidecar, Header, SealedBlock, TransactionSigned, Withdrawals, B256, U256, @@ -113,7 +113,7 @@ impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes { let cfg = CfgEnv::default().with_chain_id(chain_spec.chain().id()); // ensure we're not missing any timestamp based hardforks - let spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp()); + let spec_id = revm_spec_by_timestamp_after_bedrock(chain_spec, self.timestamp()); // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is // cancun now, we need to set the excess blob gas to the default value diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 26dc06293404..d677ce842ffd 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -11,7 +11,7 @@ use crate::metrics::PayloadBuilderMetrics; use futures_core::ready; use futures_util::FutureExt; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_payload_builder::{ database::CachedReads, error::PayloadBuilderError, KeepPayloadJobAlive, PayloadId, PayloadJob, PayloadJobGenerator, diff --git a/crates/payload/builder/Cargo.toml b/crates/payload/builder/Cargo.toml index 735831e41ca1..b43825de36a2 100644 --- a/crates/payload/builder/Cargo.toml +++ b/crates/payload/builder/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] # reth -reth-primitives.workspace = true +reth-primitives = { workspace = true, features = ["taiko"] } reth-rpc-types.workspace = true reth-transaction-pool.workspace = true reth-errors.workspace = true @@ -21,6 +21,10 @@ reth-provider.workspace = true reth-payload-primitives.workspace = true reth-ethereum-engine-primitives.workspace = true +# ethereum +alloy-rlp.workspace = true +revm-primitives.workspace = true + # async tokio = { workspace = true, features = ["sync"] } tokio-stream.workspace = true @@ -32,11 +36,14 @@ metrics.workspace = true # misc thiserror.workspace = true +sha2 = { version = "0.10", default-features = false } tracing.workspace = true +serde = { workspace = true, features = ["derive"] } [dev-dependencies] revm.workspace = true serde_json.workspace = true [features] -test-utils = [] \ No newline at end of file +test-utils = [] +taiko = ["reth-primitives/taiko"] diff --git a/crates/payload/builder/src/lib.rs b/crates/payload/builder/src/lib.rs index b3baf11991de..504a65c80928 100644 --- a/crates/payload/builder/src/lib.rs +++ b/crates/payload/builder/src/lib.rs @@ -106,6 +106,8 @@ pub mod error; mod events; mod metrics; mod service; +#[cfg(feature = "taiko")] +mod taiko; mod traits; pub mod noop; @@ -116,6 +118,11 @@ pub mod test_utils; pub use events::Events; pub use reth_rpc_types::engine::PayloadId; pub use service::{PayloadBuilderHandle, PayloadBuilderService, PayloadStore}; +#[cfg(feature = "taiko")] +pub use taiko::{ + TaikoBuiltPayload, TaikoExecutionPayload, TaikoExecutionPayloadEnvelope, + TaikoPayloadAttributes, TaikoPayloadBuilderAttributes, +}; pub use traits::{KeepPayloadJobAlive, PayloadJob, PayloadJobGenerator}; // re-export the Ethereum engine primitives for convenience diff --git a/crates/payload/builder/src/taiko.rs b/crates/payload/builder/src/taiko.rs new file mode 100644 index 000000000000..2c7efdba63ea --- /dev/null +++ b/crates/payload/builder/src/taiko.rs @@ -0,0 +1,372 @@ +use crate::EthPayloadBuilderAttributes; +use alloy_rlp::Error as DecodeError; +use reth_chainspec::ChainSpec; +use reth_evm_ethereum::revm_spec_by_timestamp_after_merge; +use reth_payload_primitives::{BuiltPayload, EngineApiMessageVersion, EngineObjectValidationError}; +use reth_primitives::{ + revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}, + Address, BlobTransactionSidecar, Header, L1Origin, SealedBlock, TaikoBlockMetadata, + Withdrawals, B256, U256, +}; +use reth_rpc_types::{ + engine::{ + self, BlobsBundleV1, ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, + ExecutionPayloadV1, PayloadId, + }, + ExecutionPayload, Withdrawal, +}; +use reth_rpc_types_compat::engine::payload::{ + block_to_payload_v1, block_to_payload_v3, convert_block_to_payload_field_v2, +}; +use serde::{Deserialize, Serialize}; +// use std::sync::Arc; + +/// Taiko Payload Attributes +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TaikoPayloadAttributes { + /// The payload attributes + #[serde(flatten)] + pub payload_attributes: engine::PayloadAttributes, + #[serde(skip_serializing_if = "Option::is_none")] + pub base_fee_per_gas: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub block_metadata: Option, + pub l1_origin: L1Origin, +} + +impl reth_payload_primitives::PayloadAttributes for TaikoPayloadAttributes { + fn timestamp(&self) -> u64 { + self.payload_attributes.timestamp() + } + + fn withdrawals(&self) -> Option<&Vec> { + self.payload_attributes.withdrawals() + } + + fn parent_beacon_block_root(&self) -> Option { + self.payload_attributes.parent_beacon_block_root() + } + + fn ensure_well_formed_attributes( + &self, + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + ) -> Result<(), EngineObjectValidationError> { + self.payload_attributes.ensure_well_formed_attributes(chain_spec, version) + } +} + +/// Taiko Payload Builder Attributes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TaikoPayloadBuilderAttributes { + /// Inner ethereum payload builder attributes + pub payload_attributes: EthPayloadBuilderAttributes, + /// The base layer fee per gas + pub base_fee_per_gas: Option, + /// Taiko specific block metadata + pub block_metadata: Option, + /// The L1 origin of the L2 block + pub l1_origin: L1Origin, +} + +impl reth_payload_primitives::PayloadBuilderAttributes for TaikoPayloadBuilderAttributes { + type RpcPayloadAttributes = TaikoPayloadAttributes; + type Error = DecodeError; + + /// Creates a new payload builder for the given parent block and the attributes. + /// + /// Derives the unique [PayloadId] for the given parent and attributes + fn try_new(parent: B256, attributes: TaikoPayloadAttributes) -> Result { + let payload_attributes = + EthPayloadBuilderAttributes::new(parent, attributes.payload_attributes); + + Ok(Self { + payload_attributes, + base_fee_per_gas: attributes.base_fee_per_gas, + block_metadata: attributes.block_metadata, + l1_origin: attributes.l1_origin, + }) + } + + fn payload_id(&self) -> PayloadId { + self.payload_attributes.id + } + + fn parent(&self) -> B256 { + self.payload_attributes.parent + } + + fn timestamp(&self) -> u64 { + self.payload_attributes.timestamp + } + + fn parent_beacon_block_root(&self) -> Option { + self.payload_attributes.parent_beacon_block_root + } + + fn suggested_fee_recipient(&self) -> Address { + self.payload_attributes.suggested_fee_recipient + } + + fn prev_randao(&self) -> B256 { + self.payload_attributes.prev_randao + } + + fn withdrawals(&self) -> &Withdrawals { + &self.payload_attributes.withdrawals + } + + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + // configure evm env based on parent block + let mut cfg = CfgEnv::default(); + cfg.chain_id = chain_spec.chain().id(); + + // ensure we're not missing any timestamp based hardforks + let spec_id = revm_spec_by_timestamp_after_merge(chain_spec, self.timestamp()); + + // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is + // cancun now, we need to set the excess blob gas to the default value + let blob_excess_gas_and_price = parent + .next_block_excess_blob_gas() + .or_else(|| { + if spec_id.is_enabled_in(SpecId::CANCUN) { + // default excess blob gas is zero + Some(0) + } else { + None + } + }) + .map(BlobExcessGasAndPrice::new); + + // calculate basefee based on parent block's gas usage + let basefee = U256::from(if let Some(base_fee_per_gas) = &self.base_fee_per_gas { + *base_fee_per_gas + } else { + parent + .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp())) + .unwrap_or_default() + }); + + let gas_limit = U256::from(if let Some(block_metadata) = &self.block_metadata { + block_metadata.gas_limit + } else { + parent.gas_limit + }); + + let block_env = BlockEnv { + number: U256::from(parent.number + 1), + coinbase: self.suggested_fee_recipient(), + timestamp: U256::from(self.timestamp()), + difficulty: U256::ZERO, + prevrandao: Some(self.prev_randao()), + gas_limit, + basefee, + // calculate excess gas based on parent block's blob gas usage + blob_excess_gas_and_price, + }; + + (CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env) + } +} + +/// Contains the built payload. +#[derive(Debug, Clone)] +pub struct TaikoBuiltPayload { + /// Identifier of the payload + pub(crate) id: PayloadId, + /// The built block + pub(crate) block: SealedBlock, + /// The fees of the block + pub(crate) fees: U256, + /// The blobs, proofs, and commitments in the block. If the block is pre-cancun, this will be + /// empty. + pub(crate) sidecars: Vec, + // /// The payload attributes. + // pub(crate) attributes: TaikoPayloadBuilderAttributes, +} + +// === impl BuiltPayload === + +impl TaikoBuiltPayload { + /// Initializes the payload with the given initial block. + pub fn new( + id: PayloadId, + block: SealedBlock, + fees: U256, + // chain_spec: Arc, + // attributes: TaikoPayloadBuilderAttributes, + ) -> Self { + Self { id, block, fees, sidecars: Vec::new() } + } + + /// Returns the identifier of the payload. + pub fn id(&self) -> PayloadId { + self.id + } + + /// Returns the built block(sealed) + pub fn block(&self) -> &SealedBlock { + &self.block + } + + /// Fees of the block + pub fn fees(&self) -> U256 { + self.fees + } + + /// Adds sidecars to the payload. + pub fn extend_sidecars(&mut self, sidecars: Vec) { + self.sidecars.extend(sidecars) + } +} + +impl BuiltPayload for TaikoBuiltPayload { + fn block(&self) -> &SealedBlock { + &self.block + } + + fn fees(&self) -> U256 { + self.fees + } +} + +impl<'a> BuiltPayload for &'a TaikoBuiltPayload { + fn block(&self) -> &SealedBlock { + (**self).block() + } + + fn fees(&self) -> U256 { + (**self).fees() + } +} + +// V1 engine_getPayloadV1 response +impl From for ExecutionPayloadV1 { + fn from(value: TaikoBuiltPayload) -> Self { + block_to_payload_v1(value.block) + } +} + +// V2 engine_getPayloadV2 response +impl From for ExecutionPayloadEnvelopeV2 { + fn from(value: TaikoBuiltPayload) -> Self { + let TaikoBuiltPayload { block, fees, .. } = value; + + ExecutionPayloadEnvelopeV2 { + block_value: fees, + execution_payload: convert_block_to_payload_field_v2(block), + } + } +} + +impl From for ExecutionPayloadEnvelopeV3 { + fn from(value: TaikoBuiltPayload) -> Self { + let TaikoBuiltPayload { block, fees, sidecars, .. } = value; + + ExecutionPayloadEnvelopeV3 { + execution_payload: block_to_payload_v3(block.clone()).0, + block_value: fees, + // From the engine API spec: + // + // > Client software **MAY** use any heuristics to decide whether to set + // `shouldOverrideBuilder` flag or not. If client software does not implement any + // heuristic this flag **SHOULD** be set to `false`. + // + // Spec: + // + should_override_builder: false, + blobs_bundle: sidecars.into_iter().map(Into::into).collect::>().into(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TaikoExecutionPayload { + /// Inner V3 payload + #[serde(flatten)] + pub payload_inner: ExecutionPayload, + + /// Allow passing txHash directly instead of transactions list + pub tx_hash: B256, + /// Allow passing WithdrawalsHash directly instead of withdrawals + pub withdrawals_hash: B256, + /// Whether this is a Taiko L2 block, only used by ExecutableDataToBlock + pub taiko_block: bool, +} + +impl TaikoExecutionPayload { + pub fn block_hash(&self) -> B256 { + self.payload_inner.block_hash() + } + + pub fn block_number(&self) -> u64 { + self.payload_inner.block_number() + } + + pub fn parent_hash(&self) -> B256 { + self.payload_inner.parent_hash() + } +} + +impl From for TaikoExecutionPayload { + fn from(value: ExecutionPayload) -> Self { + Self { + payload_inner: value, + tx_hash: B256::default(), + withdrawals_hash: B256::default(), + taiko_block: false, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TaikoExecutionPayloadEnvelope { + /// Taiko execution payload + pub execution_payload: TaikoExecutionPayload, + /// The expected value to be received by the feeRecipient in wei + pub block_value: U256, + /// The blobs, commitments, and proofs associated with the executed payload. + pub blobs_bundle: BlobsBundleV1, + /// Introduced in V3, this represents a suggestion from the execution layer if the payload + /// should be used instead of an externally provided one. + pub should_override_builder: bool, +} + +impl From for TaikoExecutionPayloadEnvelope { + fn from(value: TaikoBuiltPayload) -> Self { + let TaikoBuiltPayload { block, fees, sidecars, .. } = value; + + Self { + execution_payload: TaikoExecutionPayload { + tx_hash: block.header.transactions_root, + withdrawals_hash: block.header.withdrawals_root.unwrap_or_default(), + taiko_block: true, + + payload_inner: ExecutionPayload::V3(block_to_payload_v3(block).0), + }, + block_value: fees, + blobs_bundle: sidecars.into_iter().map(Into::into).collect::>().into(), + should_override_builder: false, + } + } +} + +impl From for TaikoExecutionPayload { + fn from(value: TaikoBuiltPayload) -> Self { + let TaikoBuiltPayload { block, .. } = value; + + Self { + tx_hash: block.header.transactions_root, + withdrawals_hash: block.header.withdrawals_root.unwrap_or_default(), + taiko_block: true, + payload_inner: ExecutionPayload::V3(block_to_payload_v3(block).0), + } + } +} diff --git a/crates/payload/primitives/src/lib.rs b/crates/payload/primitives/src/lib.rs index 52029a3c4a37..99601301710c 100644 --- a/crates/payload/primitives/src/lib.rs +++ b/crates/payload/primitives/src/lib.rs @@ -20,8 +20,7 @@ pub use traits::{BuiltPayload, PayloadAttributes, PayloadBuilderAttributes}; mod payload; pub use payload::PayloadOrAttributes; -use reth_chainspec::ChainSpec; - +use reth_chainspec::{ChainSpec, EthereumHardforks}; /// The types that are used by the engine API. pub trait PayloadTypes: Send + Sync + Unpin + core::fmt::Debug + Clone { /// The built payload type. diff --git a/crates/payload/taiko/Cargo.toml b/crates/payload/taiko/Cargo.toml new file mode 100644 index 000000000000..78030b73b421 --- /dev/null +++ b/crates/payload/taiko/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "reth-taiko-payload-builder" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +# reth +reth-primitives = { workspace = true, features = ["taiko"] } +reth-revm.workspace = true +reth-transaction-pool.workspace = true +reth-provider.workspace = true +reth-payload-builder = { workspace = true, features = ["taiko"] } +reth-basic-payload-builder.workspace = true + +# ethereum +revm.workspace = true + +# misc +tracing.workspace = true +thiserror.workspace = true diff --git a/crates/payload/taiko/src/builder.rs b/crates/payload/taiko/src/builder.rs new file mode 100644 index 000000000000..ca1e844646b0 --- /dev/null +++ b/crates/payload/taiko/src/builder.rs @@ -0,0 +1,461 @@ +use crate::consts::{anchor_selector, golden_touch, ANCHOR_GAS_LIMIT, TAIKO_L2_ADDRESS_SUFFIX}; +use crate::error::TaikoPayloadBuilderError; +use reth_basic_payload_builder::*; +use reth_payload_builder::{ + error::PayloadBuilderError, TaikoBuiltPayload, TaikoPayloadBuilderAttributes, +}; +use reth_primitives::L1Origin; +use reth_primitives::{ + constants::{BEACON_NONCE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS}, + eip4844::calculate_excess_blob_gas, + hex::FromHex, + proofs, + revm::env::tx_env_with_recovered, + Address, Block, EthereumHardforks, Header, Receipt, Receipts, TransactionSigned, + EMPTY_OMMER_ROOT_HASH, U256, +}; +use reth_provider::{L1OriginWriter, StateProviderFactory}; +use reth_revm::database::StateProviderDatabase; +use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; +use revm::{ + db::states::bundle_state::BundleRetention, + primitives::{EVMError, EnvWithHandlerCfg, ResultAndState}, + DatabaseCommit, StateBuilder, +}; +use tracing::{debug, trace, warn}; + +/// Taiko's payload builder +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct TaikoPayloadBuilder; + +/// Implementation of the [PayloadBuilder] trait for [TaikoPayloadBuilder]. +impl PayloadBuilder for TaikoPayloadBuilder +where + Client: StateProviderFactory + L1OriginWriter, + Pool: TransactionPool, +{ + type Attributes = TaikoPayloadBuilderAttributes; + type BuiltPayload = TaikoBuiltPayload; + + fn try_build( + &self, + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + taiko_payload_builder(args) + } + + fn on_missing_payload( + &self, + _args: BuildArguments, + ) -> MissingPayloadBehaviour { + MissingPayloadBehaviour::AwaitInProgress + } + + fn build_empty_payload( + &self, + client: &Client, + config: PayloadConfig, + ) -> Result { + let extra_data = config.extra_data(); + let PayloadConfig { + initialized_block_env, + parent_block, + attributes, + chain_spec, + initialized_cfg, + .. + } = config; + + debug!(target: "payload_builder", parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building empty payload"); + + let state = client.state_by_block_hash(parent_block.hash()).map_err(|err| { + warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to get state for empty payload"); + err + })?; + let mut db = StateBuilder::new() + .with_database_boxed(Box::new(StateProviderDatabase::new(&state))) + .with_bundle_update() + .build(); + + let base_fee = initialized_block_env.basefee.to::(); + let block_number = initialized_block_env.number.to::(); + let block_gas_limit: u64 = initialized_block_env.gas_limit.try_into().unwrap_or(u64::MAX); + + // apply eip-4788 pre block contract call + pre_block_beacon_root_contract_call( + &mut db, + &chain_spec, + block_number, + &initialized_cfg, + &initialized_block_env, + &attributes, + ).map_err(|err| { + warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to apply beacon root contract call for empty payload"); + err + })?; + + let WithdrawalsOutcome { withdrawals_root, withdrawals } = + commit_withdrawals(&mut db, &chain_spec, attributes.payload_attributes.timestamp, attributes.payload_attributes.withdrawals.clone()).map_err(|err| { + warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to commit withdrawals for empty payload"); + err + })?; + + // merge all transitions into bundle state, this would apply the withdrawal balance + // changes and 4788 contract call + db.merge_transitions(BundleRetention::PlainState); + + // calculate the state root + let bundle_state = db.take_bundle(); + let state_root = state.state_root(&bundle_state).map_err(|err| { + warn!(target: "payload_builder", parent_hash=%parent_block.hash(), %err, "failed to calculate state root for empty payload"); + err + })?; + + let mut excess_blob_gas = None; + let mut blob_gas_used = None; + + if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { + excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { + let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); + let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); + Some(calculate_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used)) + } else { + // for the first post-fork block, both parent.blob_gas_used and + // parent.excess_blob_gas are evaluated as 0 + Some(calculate_excess_blob_gas(0, 0)) + }; + + blob_gas_used = Some(0); + } + + let header = Header { + parent_hash: parent_block.hash(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: initialized_block_env.coinbase, + state_root, + transactions_root: EMPTY_TRANSACTIONS, + withdrawals_root, + receipts_root: EMPTY_RECEIPTS, + logs_bloom: Default::default(), + timestamp: attributes.payload_attributes.timestamp, + mix_hash: attributes.payload_attributes.prev_randao, + nonce: BEACON_NONCE, + base_fee_per_gas: Some(base_fee), + number: parent_block.number + 1, + gas_limit: block_gas_limit, + difficulty: U256::ZERO, + gas_used: 0, + extra_data, + blob_gas_used, + excess_blob_gas, + parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, + requests_root: None, + }; + + let block = Block { header, body: vec![], ommers: vec![], withdrawals, requests: None }; + let sealed_block = block.seal_slow(); + + Ok(TaikoBuiltPayload::new( + attributes.payload_attributes.payload_id(), + sealed_block, + U256::ZERO, + // chain_spec, + // attributes, + )) + } +} + +/// Constructs an Ethereum transaction payload using the best transactions from the pool. +/// +/// Given build arguments including an Ethereum client, transaction pool, +/// and configuration, this function creates a transaction payload. Returns +/// a result indicating success with the payload or an error in case of failure. +#[inline] +pub(crate) fn taiko_payload_builder( + args: BuildArguments, +) -> Result, PayloadBuilderError> +where + Client: StateProviderFactory + L1OriginWriter, + Pool: TransactionPool, +{ + let BuildArguments { client, pool, mut cached_reads, config, cancel, best_payload } = args; + + let state_provider = client.state_by_block_hash(config.parent_block.hash())?; + let state = StateProviderDatabase::new(&state_provider); + let mut db = StateBuilder::new() + .with_database_ref(cached_reads.as_db(&state)) + .with_bundle_update() + .build(); + let extra_data = config.extra_data(); + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + attributes, + chain_spec, + .. + } = config; + + debug!(target: "payload_builder", id=%attributes.payload_attributes.payload_id(), parent_hash = ?parent_block.hash(), parent_number = parent_block.number, "building new payload"); + let mut cumulative_gas_used = 0; + let block_gas_limit: u64 = attributes + .block_metadata + .as_ref() + .map(|block_metadata| block_metadata.gas_limit) + .unwrap_or(u64::MAX); + let base_fee = initialized_block_env.basefee.to::(); + + let mut executed_txs = Vec::new(); + let best_txs = pool.best_transactions_with_attributes(BestTransactionsAttributes::new( + base_fee, + initialized_block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), + )); + + let total_fees = U256::ZERO; + + let block_number = initialized_block_env.number.to::(); + + // apply eip-4788 pre block contract call + pre_block_beacon_root_contract_call( + &mut db, + &chain_spec, + block_number, + &initialized_cfg, + &initialized_block_env, + &attributes, + )?; + + let transactions = attributes + .block_metadata + .as_ref() + .map(|bm| bm.tx_list.clone().unwrap_or_default()) + .unwrap_or(vec![]); + + let mut receipts = Vec::new(); + for (index, tx) in transactions.into_iter().enumerate() { + // Check if the job was cancelled, if so we can exit early. + if cancel.is_cancelled() { + return Ok(BuildOutcome::Cancelled); + } + + let mut tx = { + let bytes = tx.to_vec(); + let mut bytes = bytes.as_slice(); + TransactionSigned::decode_enveloped(&mut bytes).map_err(|_| { + PayloadBuilderError::Other(Box::new(TaikoPayloadBuilderError::FailedToDecodeTx)) + })? + }; + + if index == 0 { + tx.transaction.mark_as_anchor().map_err(|_| { + PayloadBuilderError::Other(Box::new(TaikoPayloadBuilderError::FailedToMarkAnchor)) + })?; + } + + let tx = tx.try_into_ecrecovered().map_err(|_| { + PayloadBuilderError::other(Box::new( + TaikoPayloadBuilderError::TransactionEcRecoverFailed, + )) + })?; + + let mut evm = revm::Evm::builder() + .with_db(&mut db) + .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + tx_env_with_recovered(&tx), + )) + .build(); + + let ResultAndState { result, state } = match evm.transact() { + Ok(res) => res, + Err(err) => { + match err { + EVMError::Transaction(err) => { + trace!(target: "payload_builder", %err, ?tx, "Error in sequencer transaction, skipping."); + continue; + } + err => { + // this is an error that we should treat as fatal for this attempt + return Err(PayloadBuilderError::EvmExecutionError(err)); + } + } + } + }; + + // to release the db reference drop evm. + drop(evm); + // commit changes + db.commit(state); + + let gas_used = result.gas_used(); + + // add gas used by the transaction to cumulative gas used, before creating the receipt + cumulative_gas_used += gas_used; + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push(Some(Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + })); + + // append transaction to the list of executed transactions + executed_txs.push(tx.into_signed()); + } + + // check if we have a better block + if !is_better_payload(best_payload.as_ref(), total_fees) { + // can skip building the block + return Ok(BuildOutcome::Aborted { fees: total_fees, cached_reads }); + } + + let WithdrawalsOutcome { withdrawals_root, withdrawals } = commit_withdrawals( + &mut db, + &chain_spec, + attributes.payload_attributes.timestamp, + attributes.clone().payload_attributes.withdrawals, + )?; + + // merge all transitions into bundle state, this would apply the withdrawal balance changes + // and 4788 contract call + db.merge_transitions(BundleRetention::PlainState); + + let bundle = db.take_bundle(); + let receipts_root = bundle.receipts_root_slow(block_number).expect("Number is in range"); + let logs_bloom = bundle.block_logs_bloom(block_number).expect("Number is in range"); + + // calculate the state root + let state_root = state_provider.state_root(&bundle)?; + + // create the block header + let transactions_root = proofs::calculate_transaction_root(&executed_txs); + + // initialize empty blob sidecars. There are no blob transactions on L2. + let blob_sidecars = Vec::new(); + let mut excess_blob_gas = None; + let mut blob_gas_used = None; + + // only determine cancun fields when active + if chain_spec.is_cancun_active_at_timestamp(attributes.payload_attributes.timestamp) { + excess_blob_gas = if chain_spec.is_cancun_active_at_timestamp(parent_block.timestamp) { + let parent_excess_blob_gas = parent_block.excess_blob_gas.unwrap_or_default(); + let parent_blob_gas_used = parent_block.blob_gas_used.unwrap_or_default(); + Some(calculate_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used)) + } else { + // for the first post-fork block, both parent.blob_gas_used and + // parent.excess_blob_gas are evaluated as 0 + Some(calculate_excess_blob_gas(0, 0)) + }; + + blob_gas_used = Some(0); + } + + let header = Header { + parent_hash: parent_block.hash(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: initialized_block_env.coinbase, + state_root, + transactions_root, + receipts_root, + withdrawals_root, + logs_bloom, + timestamp: attributes.payload_attributes.timestamp, + mix_hash: attributes.payload_attributes.prev_randao, + nonce: BEACON_NONCE, + base_fee_per_gas: Some(base_fee), + number: parent_block.number + 1, + gas_limit: block_gas_limit, + difficulty: U256::ZERO, + gas_used: cumulative_gas_used, + extra_data, + parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, + blob_gas_used, + excess_blob_gas, + }; + + // Validate the anchor Tx + if let Some(anchor) = executed_txs.first() { + if !validate_anchor_tx(&anchor, &header) { + return Err(PayloadBuilderError::Other(Box::new( + TaikoPayloadBuilderError::InvalidAnchorTransaction, + ))); + } + } + + // seal the block + let block = Block { header, body: executed_txs, ommers: vec![], withdrawals }; + + let sealed_block = block.seal_slow(); + + // L1Origin **MUST NOT** be nil, it's a required field in PayloadAttributesV1. + let l1_origin = L1Origin { + // Set the block hash before inserting the L1Origin into database. + l2_block_hash: sealed_block.hash(), + ..attributes.l1_origin.clone() + }; + // Write L1Origin. + client.insert_l1_origin(sealed_block.number, l1_origin)?; + // Write the head L1Origin. + client.insert_head_l1_origin(sealed_block.number)?; + + debug!(target: "payload_builder", ?sealed_block, "sealed built block"); + + let mut payload = + TaikoBuiltPayload::new(attributes.payload_attributes.id, sealed_block, total_fees); + + // extend the payload with the blob sidecars from the executed txs + payload.extend_sidecars(blob_sidecars); + + Ok(BuildOutcome::Better { payload, cached_reads }) +} + +fn get_taiko_l2_address(chain_id: u64) -> Address { + let prefix = chain_id.to_string(); + let zeros = "0".repeat(Address::len_bytes() * 2 - prefix.len() - TAIKO_L2_ADDRESS_SUFFIX.len()); + Address::from_hex(&format!("0x{prefix}{zeros}{TAIKO_L2_ADDRESS_SUFFIX}")).unwrap() +} + +/// Checks if the given transaction is a valid TaikoL2.anchor transaction. +fn validate_anchor_tx(tx: &TransactionSigned, header: &Header) -> bool { + if !tx.is_eip1559() { + return false; + } + + let Some(to) = tx.to() else { + return false; + }; + + let Some(chain_id) = tx.chain_id() else { + return false; + }; + + if to != get_taiko_l2_address(chain_id) { + return false; + } + + if !tx.input().starts_with(&anchor_selector().to_vec()) { + return false; + } + + if !tx.value().is_zero() { + return false; + } + + if tx.gas_limit() != ANCHOR_GAS_LIMIT { + return false; + } + + if let Some(base_fee_per_gas) = header.base_fee_per_gas { + if tx.max_fee_per_gas() != base_fee_per_gas as u128 { + return false; + } + } + + let Some(signer) = tx.recover_signer() else { + return false; + }; + + signer == golden_touch() +} diff --git a/crates/payload/taiko/src/consts.rs b/crates/payload/taiko/src/consts.rs new file mode 100644 index 000000000000..f03732bb84e0 --- /dev/null +++ b/crates/payload/taiko/src/consts.rs @@ -0,0 +1,15 @@ +use reth_primitives::{hex::FromHex, keccak256, Address}; +use revm::primitives::FixedBytes; + +pub fn golden_touch() -> Address { + Address::from_hex("0x0000777735367b36bC9B61C50022d9D0700dB4Ec").unwrap() +} + +pub static TAIKO_L2_ADDRESS_SUFFIX: &'static str = "10001"; + +pub fn anchor_selector() -> FixedBytes<4> { + let hash = keccak256(b"anchor(bytes32,bytes32,uint64,uint32)"); + hash.get(0..4).unwrap().try_into().unwrap() +} + +pub static ANCHOR_GAS_LIMIT: u64 = 250_000; diff --git a/crates/payload/taiko/src/error.rs b/crates/payload/taiko/src/error.rs new file mode 100644 index 000000000000..4824f1b433a4 --- /dev/null +++ b/crates/payload/taiko/src/error.rs @@ -0,0 +1,32 @@ +//! Error type + +/// Taiko specific payload building errors. +#[derive(Debug, thiserror::Error)] +pub enum TaikoPayloadBuilderError { + /// Thrown when a transaction fails to convert to a + /// [reth_primitives::TransactionSignedEcRecovered]. + #[error("failed to convert deposit transaction to TransactionSignedEcRecovered")] + TransactionEcRecoverFailed, + /// Thrown when the L1 block info could not be parsed from the calldata of the + /// first transaction supplied in the payload attributes. + #[error("failed to parse L1 block info from L1 info tx calldata")] + L1BlockInfoParseFailed, + /// Thrown when a database account could not be loaded. + #[error("failed to load account {0}")] + AccountLoadFailed(reth_primitives::Address), + /// Thrown when force deploy of create2deployer code fails. + #[error("failed to force create2deployer account code")] + ForceCreate2DeployerFail, + /// Thrown when a blob transaction is included in a sequencer's block. + #[error("blob transaction included in sequencer block")] + BlobTransactionRejected, + /// Thrown when a invalid anchor transaction is included in a sequencer's block. + #[error("invalid anchor transaction included in sequencer block")] + InvalidAnchorTransaction, + /// Thrown when a transaction is not able to be marked as anchor. + #[error("failed to mark anchor")] + FailedToMarkAnchor, + /// Thrown when a transaction is not able to be decoded from the payload. + #[error("failed to decode tx")] + FailedToDecodeTx, +} diff --git a/crates/payload/taiko/src/lib.rs b/crates/payload/taiko/src/lib.rs new file mode 100644 index 000000000000..b3913fca684b --- /dev/null +++ b/crates/payload/taiko/src/lib.rs @@ -0,0 +1,16 @@ +//! Taiko's payload builder implementation. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(all(not(test), feature = "taiko"), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +pub use builder::*; + +pub mod error; + +mod builder; +pub mod consts; diff --git a/crates/payload/validator/Cargo.toml b/crates/payload/validator/Cargo.toml index 66efe865ceba..7b727f729e0c 100644 --- a/crates/payload/validator/Cargo.toml +++ b/crates/payload/validator/Cargo.toml @@ -17,3 +17,7 @@ reth-chainspec.workspace = true reth-primitives.workspace = true reth-rpc-types.workspace = true reth-rpc-types-compat.workspace = true +reth-payload-builder.workspace = true + +[features] +taiko = ["reth-primitives/taiko"] diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index afc19037732d..d4f892ae8a2c 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -8,13 +8,17 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use reth_chainspec::ChainSpec; +#[cfg(feature = "taiko")] +use reth_payload_builder::TaikoExecutionPayload; +#[cfg(feature = "taiko")] +use reth_primitives::{Block, Header, B256, EMPTY_OMMER_ROOT_HASH}; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::SealedBlock; use reth_rpc_types::{engine::MaybeCancunPayloadFields, ExecutionPayload, PayloadError}; use reth_rpc_types_compat::engine::payload::try_into_block; use std::sync::Arc; -/// Execution payload validator. +/// Execution payload validator.; #[derive(Clone, Debug)] pub struct ExecutionPayloadValidator { /// Chain spec to validate against. @@ -59,20 +63,20 @@ impl ExecutionPayloadValidator { if let Some(versioned_hashes) = cancun_fields.versioned_hashes() { if num_blob_versioned_hashes != versioned_hashes.len() { // Number of blob versioned hashes does not match - return Err(PayloadError::InvalidVersionedHashes) + return Err(PayloadError::InvalidVersionedHashes); } // we can use `zip` safely here because we already compared their length for (payload_versioned_hash, block_versioned_hash) in versioned_hashes.iter().zip(sealed_block.blob_versioned_hashes_iter()) { if payload_versioned_hash != block_versioned_hash { - return Err(PayloadError::InvalidVersionedHashes) + return Err(PayloadError::InvalidVersionedHashes); } } } else { // No Cancun fields, if block includes any blobs, this is an error if num_blob_versioned_hashes > 0 { - return Err(PayloadError::InvalidVersionedHashes) + return Err(PayloadError::InvalidVersionedHashes); } } @@ -104,21 +108,33 @@ impl ExecutionPayloadValidator { /// pub fn ensure_well_formed_payload( &self, - payload: ExecutionPayload, + #[cfg(not(feature = "taiko"))] payload: ExecutionPayload, + #[cfg(feature = "taiko")] payload: TaikoExecutionPayload, cancun_fields: MaybeCancunPayloadFields, ) -> Result { let expected_hash = payload.block_hash(); // First parse the block + #[cfg(not(feature = "taiko"))] let sealed_block = try_into_block(payload, cancun_fields.parent_beacon_block_root())?.seal_slow(); + #[cfg(feature = "taiko")] + let sealed_block = if payload.payload_inner.as_v1().transactions.is_empty() + && (payload.payload_inner.withdrawals().is_none() + || payload.payload_inner.withdrawals().is_some_and(|w| w.is_empty())) + { + create_taiko_block(payload, cancun_fields.parent_beacon_block_root())?.seal_slow() + } else { + try_into_block(payload.payload_inner, cancun_fields.parent_beacon_block_root())? + .seal_slow() + }; // Ensure the hash included in the payload matches the block hash if expected_hash != sealed_block.hash() { return Err(PayloadError::BlockHash { execution: sealed_block.hash(), consensus: expected_hash, - }) + }); } if self.is_cancun_active_at_timestamp(sealed_block.timestamp) { @@ -165,3 +181,42 @@ impl ExecutionPayloadValidator { Ok(sealed_block) } } + +#[cfg(feature = "taiko")] +fn create_taiko_block( + payload: TaikoExecutionPayload, + parent_beacon_block_root: Option, +) -> Result { + Ok(Block { + header: Header { + parent_hash: payload.payload_inner.parent_hash(), + beneficiary: payload.payload_inner.as_v1().fee_recipient, + state_root: payload.payload_inner.as_v1().state_root, + transactions_root: payload.tx_hash, + receipts_root: payload.payload_inner.as_v1().receipts_root, + withdrawals_root: Some(payload.withdrawals_hash), + logs_bloom: payload.payload_inner.as_v1().logs_bloom, + number: payload.payload_inner.block_number(), + gas_limit: payload.payload_inner.as_v1().gas_limit, + gas_used: payload.payload_inner.as_v1().gas_used, + timestamp: payload.payload_inner.timestamp(), + mix_hash: payload.payload_inner.prev_randao(), + base_fee_per_gas: Some( + payload.payload_inner.as_v1().base_fee_per_gas.try_into().map_err(|_| { + PayloadError::BaseFee(payload.payload_inner.as_v1().base_fee_per_gas) + })?, + ), + blob_gas_used: None, + excess_blob_gas: None, + parent_beacon_block_root, + extra_data: payload.payload_inner.as_v1().extra_data.clone(), + // Defaults + ommers_hash: EMPTY_OMMER_ROOT_HASH, + difficulty: Default::default(), + nonce: Default::default(), + }, + body: vec![], + withdrawals: None, + ommers: Default::default(), + }) +} diff --git a/crates/primitives-traits/src/header/mod.rs b/crates/primitives-traits/src/header/mod.rs index e817965a6d52..21a596ce7bd2 100644 --- a/crates/primitives-traits/src/header/mod.rs +++ b/crates/primitives-traits/src/header/mod.rs @@ -489,7 +489,7 @@ impl Decodable for Header { } } -#[cfg(feature = "arbitrary")] +#[cfg(any(test, feature = "test-utils", feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for Header { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { // Generate an arbitrary header, passing it to the generate_valid_header function to make diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index 22d4c86a0fda..590e9573dc4c 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -6,8 +6,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 1bd31171c1ed..7022189d6fbc 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -40,10 +40,12 @@ c-kzg = { workspace = true, features = ["serde"], optional = true } # misc bytes.workspace = true derive_more.workspace = true +itertools.workspace = true modular-bitfield.workspace = true once_cell.workspace = true rayon.workspace = true serde.workspace = true +serde_json.workspace = true tempfile = { workspace = true, optional = true } thiserror-no-std = { workspace = true, default-features = false } zstd = { version = "0.13", features = ["experimental"], optional = true } @@ -107,6 +109,7 @@ optimism = [ ] alloy-compat = ["reth-primitives-traits/alloy-compat", "dep:alloy-rpc-types"] std = ["thiserror-no-std/std"] +taiko = [] test-utils = ["reth-primitives-traits/test-utils"] [[bench]] diff --git a/crates/primitives/res/genesis/taiko/askja.json b/crates/primitives/res/genesis/taiko/askja.json new file mode 100644 index 000000000000..c2aff0b40766 --- /dev/null +++ b/crates/primitives/res/genesis/taiko/askja.json @@ -0,0 +1,108 @@ +{ + "alloc": { + "0x6C671d2C641CE1b99F17755fd45441fa4326C3B1": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x09d4121CD4123F039390c7f5e99b15BED5e07222": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x9E5da4B6D25Ee5A68aa8c29B6B87C82f7F463893": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0xB51f0f2bdCbf6cfabB35239921A5c672519F74ba": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063960304391461003a575b600080fd5b61004d610048366004611938565b610061565b604051901515815260200160405180910390f35b6000808061007184860186611acc565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b166020820152919350915060009081906100c790603401604051602081830303815290604052858d610197565b915091508161011d5760405162461bcd60e51b815260206004820152601960248201527f4c54503a696e76616c6964206163636f756e742070726f6f660000000000000060448201526064015b60405180910390fd5b6000610128826101c0565b9050600061014f8260028151811061014257610142611b30565b60200260200101516101f9565b90506101868b60405160200161016791815260200190565b60405160208183030381529060405261017f8c6102fc565b878461030f565b9d9c50505050505050505050505050565b6000606060006101a686610329565b90506101b381868661035b565b9250925050935093915050565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906101f390610436565b92915050565b60006021826000015111156102505760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610114565b600080600061025e85610635565b91945092509050600081600181111561027957610279611b5f565b146102c65760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610114565b60008386602001516102d89190611bbd565b805190915060208410156102f25760208490036101000a90045b9695505050505050565b60606101f361030a83610986565b610aea565b60008061031b86610329565b90506102f281868686610b59565b6060818051906020012060405160200161034591815260200190565b6040516020818303038152906040529050919050565b60006060600061036a85610b96565b9050600080600061037c848a89610c8f565b815192955090935091501580806103905750815b6103dc5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610114565b6000816103f85760405180602001604052806000815250610424565b61042486610407600188611bd0565b8151811061041757610417611b30565b6020026020010151611144565b919b919a509098505050505050505050565b606060008061044484610635565b9193509091506001905081600181111561046057610460611b5f565b146104ad5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610114565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816104c65790505090506000835b865181101561062a57602082106105725760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e000000000000000000000000000000000000000000006064820152608401610114565b6000806105af6040518060400160405280858c600001516105939190611bd0565b8152602001858c602001516105a89190611bbd565b9052610635565b5091509150604051806040016040528083836105cb9190611bbd565b8152602001848b602001516105e09190611bbd565b8152508585815181106105f5576105f5611b30565b602090810291909101015261060b600185611bbd565b93506106178183611bbd565b6106219084611bbd565b925050506104f3565b508152949350505050565b60008060008084600001511161068d5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610114565b6020840151805160001a607f81116106b257600060016000945094509450505061097f565b60b7811161072e5760006106c7608083611bd0565b90508087600001511161071c5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610114565b6001955093506000925061097f915050565b60bf811161081d57600061074360b783611bd0565b9050808760000151116107985760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610114565b600183015160208290036101000a90046107b28183611bbd565b8851116108015760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610114565b61080c826001611bbd565b965094506000935061097f92505050565b60f7811161089857600061083260c083611bd0565b9050808760000151116108875760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610114565b60019550935084925061097f915050565b60006108a560f783611bd0565b9050808760000151116108fa5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610114565b600183015160208290036101000a90046109148183611bbd565b8851116109635760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e000000000000000000006044820152606401610114565b61096e826001611bbd565b965094506001935061097f92505050565b9193909250565b606060008260405160200161099d91815260200190565b604051602081830303815290604052905060005b6020811015610a0a578181815181106109cc576109cc611b30565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016600003610a0a57610a0381611be3565b90506109b1565b6000610a17826020611bd0565b67ffffffffffffffff811115610a2f57610a2f6119f2565b6040519080825280601f01601f191660200182016040528015610a59576020820181803683370190505b50905060005b8151811015610ae1578383610a7381611be3565b945081518110610a8557610a85611b30565b602001015160f81c60f81b828281518110610aa257610aa2611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610ada81611be3565b9050610a5f565b50949350505050565b60608082516001148015610b185750608083600081518110610b0e57610b0e611b30565b016020015160f81c105b15610b245750816101f3565b610b308351608061116b565b83604051602001610b42929190611c4b565b604051602081830303815290604052905092915050565b6000806000610b6987868661035b565b91509150818015610b8b57508051602080830191909120875191880191909120145b979650505050505050565b60606000610ba3836101c0565b90506000815167ffffffffffffffff811115610bc157610bc16119f2565b604051908082528060200260200182016040528015610c0657816020015b6040805180820190915260608082526020820152815260200190600190039081610bdf5790505b50905060005b8251811015610c87576000610c39848381518110610c2c57610c2c611b30565b602002602001015161135d565b90506040518060400160405280610c4f836101c0565b815260200182815250838381518110610c6a57610c6a611b30565b60200260200101819052505080610c8090611be3565b9050610c0c565b509392505050565b600060606000806000610ca1876113ed565b90506000869050600080610cc8604051806040016040528060608152602001606081525090565b60005b8c51811015611100578c8181518110610ce657610ce6611b30565b602002602001015191508284610cfc9190611bbd565b9350610d09600188611bbd565b965083600003610d72578482602001518051906020012014610d6d5760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f7420686173680000000000000000000000000000006044820152606401610114565b610e34565b602082602001515110610dd9578482602001518051906020012014610d6d5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610114565b84610de7836020015161156e565b14610e345760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610114565b610e4060106001611c68565b60ff1682600001515103610eae5785518414611100576000868581518110610e6a57610e6a611b30565b01602001518351805160f89290921c925060009183908110610e8e57610e8e611b30565b60200260200101519050610ea181611596565b96506001945050506110f0565b8151517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016110a8576000610ee2836115cc565b9050600081600081518110610ef957610ef9611b30565b016020015160f81c90506000610f10600283611cb0565b610f1b906002611cd2565b90506000610f2c848360ff166115f0565b90506000610f3a8b8a6115f0565b90506000610f488383611626565b905060ff851660021480610f5f575060ff85166003145b15610fb557808351148015610f745750808251145b15610f8657610f83818b611bbd565b99505b507f80000000000000000000000000000000000000000000000000000000000000009950611100945050505050565b60ff85161580610fc8575060ff85166001145b1561103a578251811461100457507f80000000000000000000000000000000000000000000000000000000000000009950611100945050505050565b61102b886000015160018151811061101e5761101e611b30565b6020026020010151611596565b9a5097506110f0945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f70726566697800000000000000000000000000000000000000000000000000006064820152608401610114565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610114565b6110f981611be3565b9050610ccb565b507f800000000000000000000000000000000000000000000000000000000000000084148661112f87866115f0565b909e909d50909b509950505050505050505050565b805180516060916101f39161115b90600190611bd0565b81518110610c2c57610c2c611b30565b60608060388410156111ea57604080516001808252818301909252906020820181803683370190505090506111a08385611c68565b60f81b816000815181106111b6576111b6611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611356565b600060015b6111f98187611ceb565b1561121c5761120782611be3565b915061121561010082611cff565b90506111ef565b611227826001611bbd565b67ffffffffffffffff81111561123f5761123f6119f2565b6040519080825280601f01601f191660200182016040528015611269576020820181803683370190505b5092506112768583611c68565b611281906037611c68565b60f81b8360008151811061129757611297611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b818111611353576101006112df8284611bd0565b6112eb90610100611e36565b6112f59088611ceb565b6112ff9190611e42565b60f81b83828151811061131457611314611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061134c81611be3565b90506112cb565b50505b9392505050565b6060600080600061136d85610635565b91945092509050600081600181111561138857611388611b5f565b146113d55760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610114565b6113e4856020015184846116d0565b95945050505050565b60606000825160026113ff9190611cff565b67ffffffffffffffff811115611417576114176119f2565b6040519080825280601f01601f191660200182016040528015611441576020820181803683370190505b50905060005b835181101561156757600484828151811061146457611464611b30565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c82611499836002611cff565b815181106114a9576114a9611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060108482815181106114ec576114ec611b30565b01602001516114fe919060f81c611cb0565b60f81b8261150d836002611cff565b611518906001611bbd565b8151811061152857611528611b30565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061156081611be3565b9050611447565b5092915050565b600060208251101561158257506020015190565b818060200190518101906101f39190611e56565b600060606020836000015110156115b7576115b083611779565b90506115c3565b6115c08361135d565b90505b6113568161156e565b60606101f36115eb8360000151600081518110610c2c57610c2c611b30565b6113ed565b60608251821061160f57506040805160208101909152600081526101f3565b61135683838486516116219190611bd0565b611784565b6000805b80845111801561163a5750808351115b80156116bb575082818151811061165357611653611b30565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191684828151811061169257611692611b30565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b15611356576116c981611be3565b905061162a565b606060008267ffffffffffffffff8111156116ed576116ed6119f2565b6040519080825280601f01601f191660200182016040528015611717576020820181803683370190505b509050805160000361172a579050611356565b8484016020820160005b8581101561174c578281015182820152602001611734565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606101f382611922565b60608161179281601f611bbd565b10156117e05760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610114565b826117eb8382611bbd565b10156118395760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610114565b6118438284611bbd565b845110156118935760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610114565b6060821580156118b25760405191506000825260208201604052610ae1565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156118eb5780518352602092830192016118d3565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166040525050949350505050565b60606101f38260200151600084600001516116d0565b60008060008060008060a0878903121561195157600080fd5b86359550602087013573ffffffffffffffffffffffffffffffffffffffff8116811461197c57600080fd5b94506040870135935060608701359250608087013567ffffffffffffffff808211156119a757600080fd5b818901915089601f8301126119bb57600080fd5b8135818111156119ca57600080fd5b8a60208285010111156119dc57600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112611a3257600080fd5b813567ffffffffffffffff80821115611a4d57611a4d6119f2565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611a9357611a936119f2565b81604052838152866020858801011115611aac57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611adf57600080fd5b823567ffffffffffffffff80821115611af757600080fd5b611b0386838701611a21565b93506020850135915080821115611b1957600080fd5b50611b2685828601611a21565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156101f3576101f3611b8e565b818103818111156101f3576101f3611b8e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611c1457611c14611b8e565b5060010190565b6000815160005b81811015611c3c5760208185018101518683015201611c22565b50600093019283525090919050565b6000611c60611c5a8386611c1b565b84611c1b565b949350505050565b60ff81811683821601908111156101f3576101f3611b8e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680611cc357611cc3611c81565b8060ff84160691505092915050565b60ff82811682821603908111156101f3576101f3611b8e565b600082611cfa57611cfa611c81565b500490565b80820281158282048414176101f3576101f3611b8e565b600181815b80851115611d6f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611d5557611d55611b8e565b80851615611d6257918102915b93841c9390800290611d1b565b509250929050565b600082611d86575060016101f3565b81611d93575060006101f3565b8160018114611da95760028114611db357611dcf565b60019150506101f3565b60ff841115611dc457611dc4611b8e565b50506001821b6101f3565b5060208310610133831016604e8410600b8410161715611df2575081810a6101f3565b611dfc8383611d16565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611e2e57611e2e611b8e565b029392505050565b60006113568383611d77565b600082611e5157611e51611c81565b500690565b600060208284031215611e6857600080fd5b505191905056fea264697066735822122022f5cdb126db09c3c43e2fa6a17aab0115cbc5363507839bf8f77203759fb3af64736f6c63430008120033", + "balance": "0x0" + }, + "0x7C96157d384E99B04fE912f7E8Fa6d032073a0DD": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220032710b16720cdb7bfee28fecace22d2e4fd9f5731db2aaefd90be3a941623a364736f6c63430008120033", + "balance": "0x0" + }, + "0x13E419A8F4A246Fe22F3Acc054354258B068A7A3": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d4832ed4ef0b67bed2c2d982e30c1a789312b6584967438335056c5c4005497e64736f6c63430008120033", + "balance": "0x0" + }, + "0x658d9Ff6257D5254FC536d29641E43144Fbe8d8C": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100405760003560e01c80634eb7f19914610045578063a946c1de1461006e575b600080fd5b61005861005336600461175f565b61008e565b60405161006591906118cf565b60405180910390f35b61008161007c366004611988565b610214565b6040516100659190611a61565b604080516020810190915260608152811561020d5760006100e484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104d992505050565b90506000815167ffffffffffffffff81111561010257610102611959565b60405190808252806020026020018201604052801561019757816020015b610184604051806101000160405280600060ff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160008152602001600060ff1681526020016000815260200160008152602001606081525090565b8152602001906001900390816101205790505b50905060005b82518110156101fa576101cc8761007c8584815181106101bf576101bf611a74565b6020026020010151610512565b8282815181106101de576101de611a74565b6020026020010181905250806101f390611ad2565b905061019d565b5060408051602081019091529081529150505b9392505050565b610278604051806101000160405280600060ff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160008152602001600060ff1681526020016000815260200160008152602001606081525090565b602082015160e0820183905260001a60c0811080159061029c575060fe8160ff1611155b156103235760008083526102af846104d9565b905060006102bd86836105a2565b60408082015160608088019190915282015173ffffffffffffffffffffffffffffffffffffffff16602087015260c08083015160ff16608088015260e083015160a080890191909152610100840151918801919091529091015190850152506104d29050565b607f8160ff161161048a5760ff8116825260006103496103448560016107ba565b6104d9565b90508160ff166001036103c0576000610361826107f0565b6060808201519086015260808082015173ffffffffffffffffffffffffffffffffffffffff16602087015261010082015160ff169086015261012081015160a086015261014081015160c0808701919091520151604085015250610484565b825160ff166002036104375760006103d782610a31565b608080820151606087015260a08083015173ffffffffffffffffffffffffffffffffffffffff16602088015261012083015160ff16918701919091526101408201519086015261016081015160c086015260e00151604085015250610484565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074785479706500000000000000000000000000000000000060448201526064015b60405180910390fd5b506104d2565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c696420707265666978000000000000000000000000000000000000604482015260640161047b565b5092915050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061050c90610c86565b92915050565b6060600080600061052285610e85565b91945092509050600081600181111561053d5761053d611b0a565b1461058a5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e0000000000000000604482015260640161047b565b610599856020015184846111d6565b95945050505050565b61060a604051806101200160405280600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600060ff16815260200160008152602001600081525090565b815160091461065b5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e677468000000000000000000000000604482015260640161047b565b61067e8260008151811061067157610671611a74565b602002602001015161127f565b81528151610699908390600190811061067157610671611a74565b602082015281516106b7908390600290811061067157610671611a74565b604082015281516106e290839060039081106106d5576106d5611a74565b602002602001015161128a565b73ffffffffffffffffffffffffffffffffffffffff1660608201528151610716908390600490811061067157610671611a74565b6080820152815161073490839060059081106101bf576101bf611a74565b60a0820152610744836002611b39565b61075a8360068151811061067157610671611a74565b6107649190611b50565b61076f906023611b63565b60ff1660c08201528151610790908390600790811061067157610671611a74565b60e082015281516107ae908390600890811061067157610671611a74565b61010082015292915050565b6060825182106107d9575060408051602081019091526000815261050c565b61020d83838486516107eb9190611b50565b6112f8565b61086660405180610160016040528060008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016060815260200160608152602001600060ff16815260200160008152602001600081525090565b8151600b146108b75760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e677468000000000000000000000000604482015260640161047b565b6108cd8260008151811061067157610671611a74565b815281516108e8908390600190811061067157610671611a74565b60208201528151610906908390600290811061067157610671611a74565b60408201528151610924908390600390811061067157610671611a74565b6060820152815161094290839060049081106106d5576106d5611a74565b73ffffffffffffffffffffffffffffffffffffffff1660808201528151610976908390600590811061067157610671611a74565b60a0820152815161099490839060069081106101bf576101bf611a74565b8160c001819052506109c76109c2836007815181106109b5576109b5611a74565b6020026020010151610c86565b611497565b8160e001819052506109e58260088151811061067157610671611a74565b60ff166101008201528151610a07908390600990811061067157610671611a74565b6101208201528151610a26908390600a90811061067157610671611a74565b610140820152919050565b610aae6040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016060815260200160608152602001600060ff16815260200160008152602001600081525090565b8151600c14610aff5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e677468000000000000000000000000604482015260640161047b565b610b158260008151811061067157610671611a74565b81528151610b30908390600190811061067157610671611a74565b60208201528151610b4e908390600290811061067157610671611a74565b60408201528151610b6c908390600390811061067157610671611a74565b60608201528151610b8a908390600490811061067157610671611a74565b60808201528151610ba890839060059081106106d5576106d5611a74565b73ffffffffffffffffffffffffffffffffffffffff1660a08201528151610bdc908390600690811061067157610671611a74565b60c08201528151610bfa90839060079081106101bf576101bf611a74565b8160e00181905250610c1b6109c2836008815181106109b5576109b5611a74565b816101000181905250610c3a8260098151811061067157610671611a74565b60ff166101208201528151610c5c908390600a90811061067157610671611a74565b6101408201528151610c7b908390600b90811061067157610671611a74565b610160820152919050565b6060600080610c9484610e85565b91935090915060019050816001811115610cb057610cb0611b0a565b14610cfd5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e000000000000000000604482015260640161047b565b6040805160208082526104208201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081610d165790505090506000835b8651811015610e7a5760208210610dc25760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e00000000000000000000000000000000000000000000606482015260840161047b565b600080610dff6040518060400160405280858c60000151610de39190611b50565b8152602001858c60200151610df89190611b63565b9052610e85565b509150915060405180604001604052808383610e1b9190611b63565b8152602001848b60200151610e309190611b63565b815250858581518110610e4557610e45611a74565b6020908102919091010152610e5b600185611b63565b9350610e678183611b63565b610e719084611b63565b92505050610d43565b508152949350505050565b600080600080846000015111610edd5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e0000000000000000604482015260640161047b565b6020840151805160001a607f8111610f025760006001600094509450945050506111cf565b60b78111610f7e576000610f17608083611b50565b905080876000015111610f6c5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e00000000000000604482015260640161047b565b600195509350600092506111cf915050565b60bf811161106d576000610f9360b783611b50565b905080876000015111610fe85760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e00604482015260640161047b565b600183015160208290036101000a90046110028183611b63565b8851116110515760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e0000000000000000604482015260640161047b565b61105c826001611b63565b96509450600093506111cf92505050565b60f781116110e857600061108260c083611b50565b9050808760000151116110d75760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e000000000000000000604482015260640161047b565b6001955093508492506111cf915050565b60006110f560f783611b50565b90508087600001511161114a5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e000000604482015260640161047b565b600183015160208290036101000a90046111648183611b63565b8851116111b35760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e00000000000000000000604482015260640161047b565b6111be826001611b63565b96509450600193506111cf92505050565b9193909250565b606060008267ffffffffffffffff8111156111f3576111f3611959565b6040519080825280601f01601f19166020018201604052801561121d576020820181803683370190505b509050805160000361123057905061020d565b8484016020820160005b8581101561125257828101518282015260200161123a565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b600061050c8261165c565b805160009060010361129e57506000919050565b81516015146112ef5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e000000000000604482015260640161047b565b61050c8261127f565b60608161130681601f611b63565b10156113545760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161047b565b8261135f8382611b63565b10156113ad5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161047b565b6113b78284611b63565b845110156114075760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161047b565b606082158015611426576040519150600082526020820160405261148e565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561145f578051835260209283019201611447565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b6060815167ffffffffffffffff8111156114b3576114b3611959565b6040519080825280602002602001820160405280156114f957816020015b6040805180820190915260008152606060208201528152602001906001900390816114d15790505b50905060005b825181101561165657600061151f8483815181106109b5576109b5611a74565b90506000611539826000815181106106d5576106d5611a74565b90506000611553836001815181106109b5576109b5611a74565b90506000815167ffffffffffffffff81111561157157611571611959565b60405190808252806020026020018201604052801561159a578160200160208202803683370190505b50905060005b82518110156115f8576115cb8382815181106115be576115be611a74565b602002602001015161165c565b8282815181106115dd576115dd611a74565b60209081029190910101526115f181611ad2565b90506115a0565b5060405180604001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018281525086868151811061163657611636611a74565b6020026020010181905250505050508061164f90611ad2565b90506114ff565b50919050565b60006021826000015111156116b35760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161047b565b60008060006116c185610e85565b9194509250905060008160018111156116dc576116dc611b0a565b146117295760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e000000000000604482015260640161047b565b600083866020015161173b9190611b63565b805190915060208410156117555760208490036101000a90045b9695505050505050565b60008060006040848603121561177457600080fd5b83359250602084013567ffffffffffffffff8082111561179357600080fd5b818601915086601f8301126117a757600080fd5b8135818111156117b657600080fd5b8760208285010111156117c857600080fd5b6020830194508093505050509250925092565b6000815180845260005b81811015611801576020818501810151868301820152016117e5565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b600061010060ff835116845273ffffffffffffffffffffffffffffffffffffffff60208401511660208501526040830151816040860152611882828601826117db565b9150506060830151606085015260808301516118a3608086018260ff169052565b5060a083015160a085015260c083015160c085015260e083015184820360e086015261059982826117db565b60006020808352604083018451828386015281815180845260608701915060608160051b8801019350848301925060005b8181101561194c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088860301835261193a85855161183f565b94509285019291850191600101611900565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561199b57600080fd5b82359150602083013567ffffffffffffffff808211156119ba57600080fd5b818501915085601f8301126119ce57600080fd5b8135818111156119e0576119e0611959565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611a2657611a26611959565b81604052828152886020848701011115611a3f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b60208152600061020d602083018461183f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611b0357611b03611aa3565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b808202811582820484141761050c5761050c611aa3565b8181038181111561050c5761050c611aa3565b8082018082111561050c5761050c611aa356fea2646970667358221220977255eb91ee0bc83da7d64c4ccd4610769dfef0575766e3b1d355d99af47f7d64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0xfb2e436f19bdbec4da734cf0919b4423eb4c7a14d4f249db9211e6070a6a653d": "0x0000000000000000000000000000777700000000000000000000000000000001", + "0x0aa3204ceb554139e74fc959b75d2c0961a8274eee43ddfb4c452fa0d56e55c3": "0x0000000000000000000000000000777700000000000000000000000000000004", + "0xc19602c1e190099bda9f0217b29220086721ab0cc7df1664d5392c1062c6d6a0": "0x0000000000000000000000000000777700000000000000000000000000000002", + "0x2230df1245aba8de92051ca9155400ea7ed51d37f62ecf6ceb23a360b8066ac7": "0x0000000000000000000000000000777700000000000000000000000000000003", + "0x61566bd8aa85fc0cba510177307735c5887d55659d67a1f0f76bfcaa381cbca5": "0x0000000000000000000000000000777700000000000000000000000000000007" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063bf40fac111610050578063bf40fac1146100d7578063e1c7392a14610115578063f2fde38b1461011d57600080fd5b8063715018a6146100775780638da5cb5b146100815780639b2ea4bd146100c4575b600080fd5b61007f610130565b005b60335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61007f6100d2366004610796565b610144565b61009b6100e53660046107e4565b805160209182012060009081526065909152604090205473ffffffffffffffffffffffffffffffffffffffff1690565b61007f610216565b61007f61012b366004610821565b6103ad565b610138610461565b61014260006104e2565b565b61014c610461565b815160208084019190912060008181526065909252604091829020805473ffffffffffffffffffffffffffffffffffffffff8581167fffffffffffffffffffffffff00000000000000000000000000000000000000008316179092559251919216906101b9908590610843565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f9416a153a346f93d95f94b064ae3f148b6460473c6e82b3f9fc2521b873fcd6c910160405180910390a250505050565b600054610100900460ff16158080156102365750600054600160ff909116105b806102505750303b158015610250575060005460ff166001145b6102e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561033f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610347610559565b80156103aa57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6103b5610461565b73ffffffffffffffffffffffffffffffffffffffff8116610458576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102d8565b6103aa816104e2565b60335473ffffffffffffffffffffffffffffffffffffffff163314610142576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102d8565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166105f0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102d8565b610142600054610100900460ff1661068a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102d8565b610142336104e2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126106d357600080fd5b813567ffffffffffffffff808211156106ee576106ee610693565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561073457610734610693565b8160405283815286602085880101111561074d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461079157600080fd5b919050565b600080604083850312156107a957600080fd5b823567ffffffffffffffff8111156107c057600080fd5b6107cc858286016106c2565b9250506107db6020840161076d565b90509250929050565b6000602082840312156107f657600080fd5b813567ffffffffffffffff81111561080d57600080fd5b610819848285016106c2565b949350505050565b60006020828403121561083357600080fd5b61083c8261076d565b9392505050565b6000825160005b81811015610864576020818601810151858301520161084a565b50600092019182525091905056fea2646970667358221220d05082af8e0e2cbc9ddc35de7e94b4f45055b3cbd8e60239532b1697a91218c864736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000777700000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0x68ce81c266ebf073d5146e3a6a2145d4d2c1ed50490002a530826beee087fd9e" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100be5760003560e01c8063975e09a011610076578063c3f909d41161005b578063c3f909d41461019e578063c7b96908146102dd578063ee82ac5e146102e657600080fd5b8063975e09a014610176578063a0ca2d081461018b57600080fd5b806325bf86f2116100a757806325bf86f2146101135780633ab76e9f146101415780635155ce9f1461015f57600080fd5b80630ca4dffd146100c35780631be2bfa714610100575b600080fd5b6100d66100d1366004612415565b6102f9565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d661010e366004612463565b61030f565b6101336101213660046124ba565b60009081526034602052604090205490565b6040519081526020016100f7565b60005473ffffffffffffffffffffffffffffffffffffffff166100d6565b603654600090815260346020526040902054610133565b6101896101843660046124d3565b610326565b005b610189610199366004612560565b61040f565b6101a6610485565b6040516100f79190815181526020808301519082015260408083015190820152606080830151908201526080808301519082015260a0808301519082015260c0808301519082015260e08083015190820152610100808301519082015261012080830151908201526101408083015190820152610160808301519082015261018080830151908201526101a080830151908201526101c080830151908201526101e080830151908201526102008083015167ffffffffffffffff90811691830191909152610220808401518216908301526102408084015182169083015261026080840151821690830152610280808401518216908301526102a080840151909116908201526102c0808301511515908201526102e080830151151590820152610300918201511515918101919091526103200190565b61013360365481565b6101336102f43660046124ba565b610596565b6000610306468484610677565b90505b92915050565b600061031c848484610677565b90505b9392505050565b3371777735367b36bc9b61c50022d9d0700db4ec14610371576040517f6494e9f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3a156103a9576040517f497d3b1500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006103b3610485565b90506103c281868686866107ad565b806102e00151156103d5576103d5610a53565b6103df8585610b5e565b6040517f64b299ff9f8ba674288abb53380419048a4271dda03b837ecba6b40e6ddea4a290600090a25050505050565b6000610419610485565b9050806102e001511561042e5761042e610a53565b6036839055600083815260346020526040908190208390555183907f58313b60ec6c5bfc381e52f0de3ede0faac3cdffea26f7d6bcc3d09b61018691906104789085815260200190565b60405180910390a2505050565b61058660405180610320016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff1681526020016000151581526020016000151581526020016000151581525090565b61058e610b80565b468152919050565b60004382106105a757506000919050565b43821080156105c157506105bd610100436125b1565b8210155b156105cb57504090565b5060009081526033602052604090205490565b919050565b73ffffffffffffffffffffffffffffffffffffffff8116610630576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008061068385610d60565b846040516020016106959291906125e8565b60408051601f19818403018152908290526000547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac1906106fa908490600401612640565b602060405180830381865afa158015610717573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073b9190612697565b9150826107a55760405173ffffffffffffffffffffffffffffffffffffffff831615159061076d9083906020016126b2565b604051602081830303815290604052906107a35760405162461bcd60e51b815260040161079a9190612640565b60405180910390fd5b505b509392505050565b60e08501518311156107c8576107c38282610e1e565b610a4c565b84516040517f4eb7f19900000000000000000000000000000000000000000000000000000000815273658d9Ff6257D5254FC536d29641E43144Fbe8d8C91634eb7f1999161081d9190889088906004016126f7565b600060405180830381865af492505050801561085b57506040513d6000823e601f3d908101601f19168201604052610858919081019061278b565b60015b61089f573d808015610889576040519150601f19603f3d011682016040523d82523d6000602084013e61088e565b606091505b506108998383610e1e565b50610a4c565b60c086015181515111156108b7576108998383610e1e565b8560a001516108c582610e79565b11156108d5576108998383610e1e565b8051518210610910576040517fb431f3fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000816000015183815181106109285761092861292b565b60200260200101519050600160028111156109455761094561295a565b8460028111156109575761095761295a565b036109bf57865160009061096b9083610ecb565b73ffffffffffffffffffffffffffffffffffffffff16146109b8576040517ff8092d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050610a4c565b60028460028111156109d3576109d361295a565b03610a1a578661010001518160600151106109b8576040517ff8092d1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9343055600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b610a5b6122bb565b434660025b6101008111158015610a725750808310155b15610abe57610a8181846125b1565b408460ff610a8f84876125b1565b610a9991906129b8565b60ff8110610aa957610aa961292b565b6020020152610ab7816129cc565b9050610a60565b506000610acc6001846125b1565b90508040610add8383600088610f5c565b60355414610b17576040517fd719258d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8085610b2460ff856129b8565b60ff8110610b3457610b3461292b565b6020020152610b468385600088610f5c565b60355560009182526033602052604090912055505050565b60008282604051610b70929190612a04565b6040518091039020905092915050565b610c8160405180610320016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff1681526020016000151581526020016000151581526020016000151581525090565b50604080516103208101825262028c5c81526108016020820152602891810191909152600a606082015260006080820152625b8d8060a0820152604f60c08201526201d4c060e08201526152086101008201526203d090610120820152620e71d9610140820152606461016082015260196101808201526104006101a082018190526101c082018190526101e0820152610190610200820181905260c8610220830152610240820152603c61026082015261070861028082015262278d006102a082015260016102c082018190526102e0820181905261030082015290565b60606000610d6d83610f95565b600101905060008167ffffffffffffffff811115610d8d57610d8d6122da565b6040519080825280601f01601f191660200182016040528015610db7576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084610dc157509392505050565b6000826002811115610e3257610e3261295a565b141580610e3e57508015155b15610e75576040517f11abdc5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b8051600090815b8151811015610ec457818181518110610e9b57610e9b61292b565b60200260200101516060015183610eb29190612a14565b9250610ebd816129cc565b9050610e80565b5050919050565b60006001610ed98484611077565b6080840151610ee990601b612a27565b60a085015160c0860151604080516000815260200190819052610f28949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610f4a573d6000803e3d6000fd5b5050604051601f190151949350505050565b600084848484604051602001610f759493929190612a40565b604051602081830303815290604052805190602001209050949350505050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310610fde577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef8100000000831061100a576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061102857662386f26fc10000830492506010015b6305f5e1008310611040576305f5e100830492506008015b612710831061105457612710830492506004015b60648310611066576064830492506002015b600a83106103095760010192915050565b60006060826000015160ff1660000361109e576110978360e00151611465565b90506110b8565b6110b56110b08460e001516001611498565b611465565b90505b825160ff1660000361111a5780516009146111155760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d73000000000000000000000000000000604482015260640161079a565b61121c565b825160ff16600103611177578051600b146111155760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d73000000000000000000000000000000604482015260640161079a565b825160ff166002036111d4578051600c146111155760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d73000000000000000000000000000000604482015260640161079a565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c696420747854797065000000000000000000000000000000000000604482015260640161079a565b825160009060ff161561123c576003825161123791906125b1565b61123f565b81515b67ffffffffffffffff811115611257576112576122da565b60405190808252806020026020018201604052801561128a57816020015b60608152602001906001900390816112755790505b50905060005b815181101561141257845160ff16158015906112b85750600182516112b591906125b1565b81145b15611301576112df8382815181106112d2576112d261292b565b60200260200101516114ce565b8282815181106112f1576112f161292b565b6020026020010181905250611402565b61132b6113268483815181106113195761131961292b565b60200260200101516114d9565b611569565b82828151811061133d5761133d61292b565b6020908102919091010152845160ff1615801561136657506004825161136391906125b1565b81145b1561140257611374866115d8565b82611380836001612a14565b815181106113905761139061292b565b60200260200101819052506113a560006115e6565b826113b1836002612a14565b815181106113c1576113c161292b565b60200260200101819052506113d660006115e6565b826113e2836003612a14565b815181106113f2576113f261292b565b6020026020010181905250611412565b61140b816129cc565b9050611290565b50600061141e826115fe565b855190915060ff16156114545784516040516114429160f81b908390602001612a8b565b60405160208183030381529060405290505b805160209091012095945050505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061030990611642565b6060825182106114b75750604080516020810190915260008152610309565b61030683838486516114c991906125b1565b611841565b6060610309826119c2565b606060008060006114e9856119d8565b9194509250905060008160018111156115045761150461295a565b146115515760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e0000000000000000604482015260640161079a565b61156085602001518484611d29565b95945050505050565b60608082516001148015611597575060808360008151811061158d5761158d61292b565b016020015160f81c105b156115a3575081610309565b6115af83516080611dd2565b836040516020016115c1929190612ad3565b604051602081830303815290604052905092915050565b606061030961132683611fba565b60606103096113268367ffffffffffffffff16611fba565b6060600061160b83612115565b9050611619815160c0611dd2565b8160405160200161162b929190612ad3565b604051602081830303815290604052915050919050565b6060600080611650846119d8565b9193509091506001905081600181111561166c5761166c61295a565b146116b95760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e000000000000000000604482015260640161079a565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816116d25790505090506000835b8651811015611836576020821061177e5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e00000000000000000000000000000000000000000000606482015260840161079a565b6000806117bb6040518060400160405280858c6000015161179f91906125b1565b8152602001858c602001516117b49190612a14565b90526119d8565b5091509150604051806040016040528083836117d79190612a14565b8152602001848b602001516117ec9190612a14565b8152508585815181106118015761180161292b565b6020908102919091010152611817600185612a14565b93506118238183612a14565b61182d9084612a14565b925050506116ff565b508152949350505050565b60608161184f81601f612a14565b101561189d5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161079a565b826118a88382612a14565b10156118f65760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015260640161079a565b6119008284612a14565b845110156119505760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015260640161079a565b60608215801561196f57604051915060008252602082016040526119b9565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119a8578051835260209283019201611990565b5050858452601f01601f1916604052505b50949350505050565b6060610309826020015160008460000151611d29565b600080600080846000015111611a305760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e0000000000000000604482015260640161079a565b6020840151805160001a607f8111611a55576000600160009450945094505050611d22565b60b78111611ad1576000611a6a6080836125b1565b905080876000015111611abf5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e00000000000000604482015260640161079a565b60019550935060009250611d22915050565b60bf8111611bc0576000611ae660b7836125b1565b905080876000015111611b3b5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e00604482015260640161079a565b600183015160208290036101000a9004611b558183612a14565b885111611ba45760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e0000000000000000604482015260640161079a565b611baf826001612a14565b9650945060009350611d2292505050565b60f78111611c3b576000611bd560c0836125b1565b905080876000015111611c2a5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e000000000000000000604482015260640161079a565b600195509350849250611d22915050565b6000611c4860f7836125b1565b905080876000015111611c9d5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e000000604482015260640161079a565b600183015160208290036101000a9004611cb78183612a14565b885111611d065760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e00000000000000000000604482015260640161079a565b611d11826001612a14565b9650945060019350611d2292505050565b9193909250565b606060008267ffffffffffffffff811115611d4657611d466122da565b6040519080825280601f01601f191660200182016040528015611d70576020820181803683370190505b5090508051600003611d8357905061031f565b8484016020820160005b85811015611da5578281015182820152602001611d8d565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b6060806038841015611e515760408051600180825281830190925290602082018180368337019050509050611e078385612a27565b60f81b81600081518110611e1d57611e1d61292b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610306565b600060015b611e608187612b02565b15611e8357611e6e826129cc565b9150611e7c61010082612b16565b9050611e56565b611e8e826001612a14565b67ffffffffffffffff811115611ea657611ea66122da565b6040519080825280601f01601f191660200182016040528015611ed0576020820181803683370190505b509250611edd8583612a27565b611ee8906037612a27565b60f81b83600081518110611efe57611efe61292b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b8181116107a357610100611f4682846125b1565b611f5290610100612c4d565b611f5c9088612b02565b611f6691906129b8565b60f81b838281518110611f7b57611f7b61292b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611fb3816129cc565b9050611f32565b6060600082604051602001611fd191815260200190565b604051602081830303815290604052905060005b602081101561203e578181815181106120005761200061292b565b01602001517fff000000000000000000000000000000000000000000000000000000000000001660000361203e57612037816129cc565b9050611fe5565b600061204b8260206125b1565b67ffffffffffffffff811115612063576120636122da565b6040519080825280601f01601f19166020018201604052801561208d576020820181803683370190505b50905060005b81518110156119b95783836120a7816129cc565b9450815181106120b9576120b961292b565b602001015160f81c60f81b8282815181106120d6576120d661292b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061210e816129cc565b9050612093565b6060815160000361213457505060408051600081526020810190915290565b6000805b8351811015612179578381815181106121535761215361292b565b602002602001015151826121679190612a14565b9150612172816129cc565b9050612138565b60008267ffffffffffffffff811115612194576121946122da565b6040519080825280601f01601f1916602001820160405280156121be576020820181803683370190505b50600092509050602081015b85518310156119b95760008684815181106121e7576121e761292b565b60200260200101519050600060208201905061220583828451612240565b8785815181106122175761221761292b565b6020026020010151518361222b9190612a14565b9250505082612239906129cc565b92506121ca565b8282825b6020811061227c578151835261225b602084612a14565b9250612268602083612a14565b91506122756020826125b1565b9050612244565b905182516020929092036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199091169116179052505050565b60405180611fe0016040528060ff906020820280368337509192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff8111828210171561232c5761232c6122da565b60405290565b604051610100810167ffffffffffffffff8111828210171561232c5761232c6122da565b604051601f8201601f1916810167ffffffffffffffff8111828210171561237f5761237f6122da565b604052919050565b600067ffffffffffffffff8211156123a1576123a16122da565b50601f01601f191660200190565b600082601f8301126123c057600080fd5b81356123d36123ce82612387565b612356565b8181528460208386010111156123e857600080fd5b816020850160208301376000918101602001919091529392505050565b803580151581146105de57600080fd5b6000806040838503121561242857600080fd5b823567ffffffffffffffff81111561243f57600080fd5b61244b858286016123af565b92505061245a60208401612405565b90509250929050565b60008060006060848603121561247857600080fd5b83359250602084013567ffffffffffffffff81111561249657600080fd5b6124a2868287016123af565b9250506124b160408501612405565b90509250925092565b6000602082840312156124cc57600080fd5b5035919050565b600080600080606085870312156124e957600080fd5b843567ffffffffffffffff8082111561250157600080fd5b818701915087601f83011261251557600080fd5b81358181111561252457600080fd5b88602082850101111561253657600080fd5b602092830196509450508501356003811061255057600080fd5b9396929550929360400135925050565b6000806040838503121561257357600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561030957610309612582565b60005b838110156125df5781810151838201526020016125c7565b50506000910152565b600083516125fa8184602088016125c4565b7f2e0000000000000000000000000000000000000000000000000000000000000090830190815283516126348160018401602088016125c4565b01600101949350505050565b602081526000825180602084015261265f8160408501602087016125c4565b601f01601f19169190910160400192915050565b805173ffffffffffffffffffffffffffffffffffffffff811681146105de57600080fd5b6000602082840312156126a957600080fd5b61030682612673565b7f41523a7a65726f416464723a00000000000000000000000000000000000000008152600082516126ea81600c8501602087016125c4565b91909101600c0192915050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b805160ff811681146105de57600080fd5b600082601f83011261274f57600080fd5b815161275d6123ce82612387565b81815284602083860101111561277257600080fd5b6127838260208301602087016125c4565b949350505050565b6000602080838503121561279e57600080fd5b825167ffffffffffffffff808211156127b657600080fd5b81850191508282870312156127ca57600080fd5b6127d2612309565b8251828111156127e157600080fd5b80840193505086601f8401126127f657600080fd5b825182811115612808576128086122da565b8060051b612817868201612356565b918252848101860191868101908a84111561283157600080fd5b87870192505b8383101561291b5782518681111561284e57600080fd5b8701610100818d03601f190181131561286657600080fd5b61286e612332565b6128798b840161272d565b815261288760408401612673565b8b82015260608301518981111561289d57600080fd5b6128ab8f8d8387010161273e565b6040830152506080830151606082015260a06128c881850161272d565b608083015260c0808501518284015260e09150818501518184015250828401519250898311156128f85760008081fd5b6129068f8d8587010161273e565b90820152845250509187019190870190612837565b8452509198975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826129c7576129c7612989565b500690565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036129fd576129fd612582565b5060010190565b8183823760009101908152919050565b8082018082111561030957610309612582565b60ff818116838216019081111561030957610309612582565b848152600060208581840152846040840152606083018460005b60ff811015612a7757815183529183019190830190600101612a5a565b505050506120408201905095945050505050565b7fff000000000000000000000000000000000000000000000000000000000000008316815260008251612ac58160018501602087016125c4565b919091016001019392505050565b60008351612ae58184602088016125c4565b835190830190612af98183602088016125c4565b01949350505050565b600082612b1157612b11612989565b500490565b808202811582820484141761030957610309612582565b600181815b80851115612b8657817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612b6c57612b6c612582565b80851615612b7957918102915b93841c9390800290612b32565b509250929050565b600082612b9d57506001610309565b81612baa57506000610309565b8160018114612bc05760028114612bca57612be6565b6001915050610309565b60ff841115612bdb57612bdb612582565b50506001821b610309565b5060208310610133831016604e8410600b8410161715612c09575081810a610309565b612c138383612b2d565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115612c4557612c45612582565b029392505050565b60006103068383612b8e56fea2646970667358221220b0e2d2df211dd589d063e24dc61098a0aec86ea03c1fcd3241c1634bae25d5dd64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006" + }, + "code": "0x6080604052600436106101635760003560e01c8063715018a6116100c0578063ce70f39b11610074578063f2fde38b11610059578063f2fde38b1461051a578063f98039191461053a578063fee99b221461055a57600080fd5b8063ce70f39b1461048b578063d0496d6a146104ab57600080fd5b806396e17852116100a557806396e1785214610438578063a4444efd1461044b578063bac443e21461046b57600080fd5b8063715018a6146104055780638da5cb5b1461041a57600080fd5b80635075a9d4116101175780635817b0c3116100fc5780635817b0c3146103975780635d0bd986146103c5578063606b5b74146103e557600080fd5b80635075a9d41461034a578063540be6a31461037757600080fd5b80631be2bfa7116101485780631be2bfa7146102cc578063343b643c146102ec5780633ab76e9f1461032c57600080fd5b80630ca4dffd1461026f57806319ab453c146102ac57600080fd5b3661026a576101a86040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250600161057a565b6001600160a01b0316336001600160a01b03161415801561021a57506102046040518060400160405280600b81526020017f65746865725f7661756c74000000000000000000000000000000000000000000815250600161057a565b6001600160a01b0316336001600160a01b031614155b801561023157506065546001600160a01b03163314155b15610268576040517f8bba088a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b34801561027b57600080fd5b5061028f61028a366004613914565b61057a565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102b857600080fd5b506102686102c7366004613986565b610590565b3480156102d857600080fd5b5061028f6102e73660046139a3565b610729565b3480156102f857600080fd5b5061031c6103073660046139fe565b600090815260cd602052604090205460ff1690565b60405190151581526020016102a3565b34801561033857600080fd5b506097546001600160a01b031661028f565b34801561035657600080fd5b5061036a6103653660046139fe565b61073e565b6040516102a39190613a81565b34801561038357600080fd5b5061031c6103923660046139fe565b610749565b3480156103a357600080fd5b506103b76103b2366004613aa8565b610755565b6040519081526020016102a3565b3480156103d157600080fd5b5061031c6103e03660046139fe565b610768565b3480156103f157600080fd5b506103b76104003660046139fe565b61077b565b34801561041157600080fd5b50610268610786565b34801561042657600080fd5b506065546001600160a01b031661028f565b6103b7610446366004613aa8565b61079a565b34801561045757600080fd5b5061031c610466366004613b26565b6107c8565b34801561047757600080fd5b50610268610486366004613b79565b6107e0565b34801561049757600080fd5b5061031c6104a6366004613b26565b610804565b3480156104b757600080fd5b50604080516060808201835260008083526020808401829052928401528251808201845260ca5480825260cb546001600160a01b0390811683860190815260cc5493870193845286519283525116938101939093525192820192909252016102a3565b34801561052657600080fd5b50610268610535366004613986565b610813565b34801561054657600080fd5b50610268610555366004613be2565b6108bd565b34801561056657600080fd5b50610268610575366004613b79565b6108db565b60006105874684846108f1565b90505b92915050565b600054610100900460ff16158080156105b05750600054600160ff909116105b806105ca5750303b1580156105ca575060005460ff166001145b61065b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156106b957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6106c282610a3c565b801561072557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006107368484846108f1565b949350505050565b600061058a82610a55565b600061058a3083610a78565b600061058a61076383613c18565b610bbd565b60006107743083610bed565b5092915050565b600061058a82610cc5565b61078e610d00565b6107986000610d74565b565b60006107a4610dde565b6107b860c9306107b385613c18565b610e51565b90506107c360018055565b919050565b60006107d73086868686611239565b95945050505050565b6107e8610dde565b6107f660c930858585611435565b6107ff60018055565b505050565b60006107d73086868686611823565b61081b610d00565b6001600160a01b0381166108b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610652565b6108ba81610d74565b50565b6108c5610dde565b6108d260c9308484611ba6565b61072560018055565b6108e3610dde565b6107f660c930858585611e82565b6000806108fd856124f5565b8460405160200161090f929190613d3e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac10000000000000000000000000000000000000000000000000000000083529092506001600160a01b03169063bf40fac190610985908490600401613de0565b602060405180830381865afa1580156109a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c69190613df3565b915082610a34576040516001600160a01b0383161515906109eb908390602001613e10565b60405160208183030381529060405290610a32576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106529190613de0565b505b509392505050565b610a44612595565b610a4c612634565b6108ba816126d3565b600080610a6183610cc5565b805490915080600381111561073657610736613a17565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600e60448201527f7369676e616c5f736572766963650000000000000000000000000000000000006064820152600060248201819052906001600160a01b03841690630ca4dffd90608401602060405180830381865afa158015610b0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b339190613df3565b6040517f32676bc6000000000000000000000000000000000000000000000000000000008152306004820152602481018490526001600160a01b0391909116906332676bc690604401602060405180830381865afa158015610b99573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105879190613e55565b600081604051602001610bd09190613f65565b604051602081830303815290604052805190602001209050919050565b6040517f1be2bfa70000000000000000000000000000000000000000000000000000000081526004810182905260606024820152600660648201527f627269646765000000000000000000000000000000000000000000000000000060848201526001604482015260009081906001600160a01b03851690631be2bfa79060a401602060405180830381865afa158015610c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610caf9190613df3565b6001600160a01b03811615159590945092505050565b6040517f4d4553534147455f5354415455530000000000000000000000000000000000006020820152602e8101829052600090604e01610bd0565b6065546001600160a01b03163314610798576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610652565b606580546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600260015403610e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610652565b6002600155565b60808101516000906001600160a01b0316610e98576040517fd8c3418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080610ea9858560600151610bed565b91509150811580610ebd5750468460600151145b15610ef4576040517fe822b48d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08401516001600160a01b03161580610f235750806001600160a01b03168460a001516001600160a01b0316145b15610f5a576040517fb9ad6a0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008461012001518561010001518660e00151610f779190613fdb565b610f819190613fdb565b9050348114610fbc576040517f9826865c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600b60448201527f65746865725f7661756c740000000000000000000000000000000000000000006064820152600160248201526000906001600160a01b03881690630ca4dffd90608401602060405180830381865afa158015611053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110779190613df3565b90506001600160a01b0381161561109b5761109b6001600160a01b0382168361274d565b87548860006110a983613fee565b9091555086523360208701524660408701526110c486610bbd565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600e60448201527f7369676e616c5f736572766963650000000000000000000000000000000000006064820152600060248201529095506001600160a01b03881690630ca4dffd90608401602060405180830381865afa15801561115b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117f9190613df3565b6001600160a01b03166366ca2bc0866040518263ffffffff1660e01b81526004016111ac91815260200190565b6020604051808303816000875af11580156111cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ef9190614008565b50847f47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f3876040516112209190614021565b60405180910390a2505050509392505050565b60018055565b6040517f1be2bfa70000000000000000000000000000000000000000000000000000000081526004810184905260606024820152600660648201527f627269646765000000000000000000000000000000000000000000000000000060848201526000604482018190529081906001600160a01b03881690631be2bfa79060a401602060405180830381865afa1580156112d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fb9190613df3565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600e60448201527f7369676e616c5f736572766963650000000000000000000000000000000000006064820152600060248201529091506001600160a01b03881690630ca4dffd90608401602060405180830381865afa158015611392573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113b69190613df3565b6001600160a01b0316635221f61386838988886040518663ffffffff1660e01b81526004016113e9959493929190614034565b602060405180830381865afa158015611406573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142a9190613e55565b979650505050505050565b600061144760a0850160808601613986565b6001600160a01b031603611487576040517fd8c3418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b468360400135146114c4576040517fe822b48d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006114d261076385613c18565b600081815260048801602052604090205490915060ff161515600103611524576040517fafde133500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611535858286606001358686611823565b61156b576040517f498b0b1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600487016020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556115b761010086013560e0870135613fdb565b905080156117c757604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600b60448201527f65746865725f7661756c740000000000000000000000000000000000000000006064820152600160248201526000906001600160a01b03881690630ca4dffd90608401602060405180830381865afa158015611656573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167a9190613df3565b90506001600160a01b03811615611727576001600160a01b03811663ba0bbd956116aa60a0890160808a01613986565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260248101859052604401600060405180830381600087803b15801561170a57600080fd5b505af115801561171e573d6000803e3d6000fd5b505050506117c5565b600061173960a0880160808901613986565b6001600160a01b03168360405160006040518083038185875af1925050503d8060008114611783576040519150601f19603f3d011682016040523d82523d6000602084013e611788565b606091505b50509050806117c3576040517ff6664cf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505b817fea00c741e39d1d9ab1c6703152d71f9da09a782ed4ae128414730dadbb9bd8476117f960a0880160808901613986565b604080516001600160a01b039092168252602082018590520160405180910390a250505050505050565b600046840361185e576040517fe822b48d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000859003611899576040517fa6407c9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118a783850185614145565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600560448201527f7461696b6f00000000000000000000000000000000000000000000000000000060648201526000602482018190529192506001600160a01b03891690630ca4dffd90608401602060405180830381865afa158015611940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119649190613df3565b825161010001516040517f25bf86f20000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90911660048201526001600160a01b0391909116906325bf86f290602401602060405180830381865afa1580156119dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a019190614008565b9050801580611a1a57508151611a1690612810565b8114155b15611a2a576000925050506107d7565b81516060908101516040517f1be2bfa7000000000000000000000000000000000000000000000000000000008152600481018990526024810192909252600660648301527f627269646765000000000000000000000000000000000000000000000000000060848301526000604483015273B51f0f2bdCbf6cfabB35239921A5c672519F74ba91639603043991906001600160a01b038c1690631be2bfa79060a401602060405180830381865afa158015611ae9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0d9190613df3565b611b168b610cc5565b602087015160405160e086901b7fffffffff00000000000000000000000000000000000000000000000000000000168152611b59949392916003916004016142ea565b602060405180830381865af4158015611b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9a9190613e55565b98975050505050505050565b6101408201351580611bb55750805b15611c1457611bca60a0830160808401613986565b6001600160a01b0316336001600160a01b031614611c14576040517fd7f4fc9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611c2261076384613c18565b90506001611c2f82610a55565b6003811115611c4057611c40613a17565b14611c77576040517f1f6646b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600b60448201527f65746865725f7661756c740000000000000000000000000000000000000000006064820152600160248201526000906001600160a01b03861690630ca4dffd90608401602060405180830381865afa158015611d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d329190613df3565b90506001600160a01b03811615611dbb576040517fd73bb3d000000000000000000000000000000000000000000000000000000000815261010085013560048201526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b158015611da257600080fd5b505af1158015611db6573d6000803e3d6000fd5b505050505b611dc78685845a612835565b15611ddc57611dd78260026129d6565b611e7a565b8215611e5357611ded8260036129d6565b600080611e0060e0870160c08801613986565b6001600160a01b031614611e2357611e1e60e0860160c08701613986565b611e33565b611e3360a0860160808701613986565b9050611e4d6001600160a01b03821661010087013561274d565b50611e7a565b6001600160a01b03811615611e7a57611e7a6001600160a01b03821661010086013561274d565b505050505050565b610140830135158015611eb65750611ea060a0840160808501613986565b6001600160a01b0316336001600160a01b031614155b15611eed576040517fe62d8d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836060013514611f2a576040517fe822b48d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611f3861076385613c18565b90506000611f4582610a55565b6003811115611f5657611f56613a17565b14611f8d576040517f2c3b0c4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080517f1be2bfa700000000000000000000000000000000000000000000000000000000815290850135600482015260606024820152600660648201527f62726964676500000000000000000000000000000000000000000000000000006084820152600060448201819052906001600160a01b03871690631be2bfa79060a401602060405180830381865afa15801561202c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120509190613df3565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600e60448201527f7369676e616c5f736572766963650000000000000000000000000000000000006064820152600060248201529091506001600160a01b03871690630ca4dffd90608401602060405180830381865afa1580156120e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210b9190613df3565b6001600160a01b0316635221f6138660400135838588886040518663ffffffff1660e01b8152600401612142959493929190614034565b602060405180830381865afa15801561215f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121839190613e55565b6121b9576040517fa282639800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006101208601356121d461010088013560e0890135613fdb565b6121de9190613fdb565b604080517f0ca4dffd0000000000000000000000000000000000000000000000000000000081526004810191909152600b60448201527f65746865725f7661756c740000000000000000000000000000000000000000006064820152600160248201529091506000906001600160a01b03891690630ca4dffd90608401602060405180830381865afa158015612278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229c9190613df3565b90506001600160a01b038116158015906122b65750600082115b1561232f576040517fd73bb3d0000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b15801561231657600080fd5b505af115801561232a573d6000803e3d6000fd5b505050505b60e0870135156123605761236060e088013561235160a08a0160808b01613986565b6001600160a01b03169061274d565b6000803061237460c08b0160a08c01613986565b6001600160a01b031614806123a15750600061239660c08b0160a08c01613986565b6001600160a01b0316145b156123b657506002905061010088013561243c565b60006123c860a08b0160808c01613986565b6001600160a01b0316336001600160a01b0316146123eb578961014001356123ed565b5a5b905060006123fd8d8c8a85612835565b9050801561240e5760029350612439565b600193506001600160a01b03851615612439576124396001600160a01b0386166101008d013561274d565b50505b61244686836129d6565b60008061245960e08c0160c08d01613986565b6001600160a01b03161461247c5761247760e08b0160c08c01613986565b61248c565b61248c60a08b0160808c01613986565b90506001600160a01b03811633036124c5576124c06124b0836101208d0135613fdb565b6001600160a01b0383169061274d565b6124e7565b6124d4336101208c013561274d565b6124e76001600160a01b0382168361274d565b505050505050505050505050565b6060600061250283612a4f565b600101905060008167ffffffffffffffff811115612522576125226137bb565b6040519080825280601f01601f19166020018201604052801561254c576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461255657509392505050565b600054610100900460ff1661262c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610652565b610798612b31565b600054610100900460ff166126cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610652565b610798612bc8565b6001600160a01b038116612713576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b8015610725576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146127a0576040519150601f19603f3d011682016040523d82523d6000602084013e6127a5565b606091505b50509050806107ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610652565b600080612826612821846000612c68565b6130ac565b80516020909101209392505050565b600081600003612871576040517ffe1d2c1200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180606001604052808481526020018560200160208101906128959190613986565b6001600160a01b039081168252604087810135602093840152835160018a0155918301516002890180547fffffffffffffffffffffffff00000000000000000000000000000000000000001691909216179055015160038601556128ff60c0850160a08601613986565b6001600160a01b03168261010086013561291d61016088018861434d565b60405161292b9291906143b2565b600060405180830381858888f193505050503d8060008114612969576040519150601f19603f3d011682016040523d82523d6000602084013e61296e565b606091505b505060408051606081018252600180825260208201819052600019919092018190528782018290556002880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690921790915560039096019590955550929392505050565b8060038111156129e8576129e8613a17565b6129f183610a55565b6003811115612a0257612a02613a17565b1461072557612a1182826130f0565b817f0af4d5247f6a4028d6699afb62871a76b398da1d1a626c8a9b90e0bd5f54c73c8233604051612a439291906143c2565b60405180910390a25050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612a98577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310612ac4576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310612ae257662386f26fc10000830492506010015b6305f5e1008310612afa576305f5e100830492506008015b6127108310612b0e57612710830492506004015b60648310612b20576064830492506002015b600a831061058a5760010192915050565b600054610100900460ff16611233576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610652565b600054610100900460ff16612c5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610652565b61079833610d74565b61020082015160609015612cd457612c81826011613fdb565b67ffffffffffffffff811115612c9957612c996137bb565b604051908082528060200260200182016040528015612ccc57816020015b6060815260200190600190039081612cb75790505b509050612d44565b6101e083015115612cea57612c81826010613fdb565b612cf582600f613fdb565b67ffffffffffffffff811115612d0d57612d0d6137bb565b604051908082528060200260200182016040528015612d4057816020015b6060815260200190600190039081612d2b5790505b5090505b8251612d4f90613119565b81600081518110612d6257612d626143e6565b6020026020010181905250612d7a8360200151613119565b81600181518110612d8d57612d8d6143e6565b6020026020010181905250612da5836040015161312c565b81600281518110612db857612db86143e6565b6020026020010181905250612dd08360600151613119565b81600381518110612de357612de36143e6565b6020026020010181905250612dfb8360800151613119565b81600481518110612e0e57612e0e6143e6565b6020026020010181905250612e268360a00151613119565b81600581518110612e3957612e396143e6565b6020026020010181905250612e708360c00151604051602001612e5c9190614415565b604051602081830303815290604052613168565b81600681518110612e8357612e836143e6565b6020026020010181905250612e9b8360e001516131d7565b81600781518110612eae57612eae6143e6565b6020026020010181905250612ed98361010001516fffffffffffffffffffffffffffffffff166131d7565b81600881518110612eec57612eec6143e6565b6020026020010181905250612f058361012001516131e5565b81600981518110612f1857612f186143e6565b6020026020010181905250612f318361014001516131e5565b81600a81518110612f4457612f446143e6565b6020026020010181905250612f5d8361016001516131e5565b81600b81518110612f7057612f706143e6565b6020026020010181905250612f89836101800151613168565b81600c81518110612f9c57612f9c6143e6565b6020026020010181905250612fb5836101a00151613119565b81600d81518110612fc857612fc86143e6565b6020026020010181905250613017836101c00151604051602001612e5c919060c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016815260080190565b81600e8151811061302a5761302a6143e6565b6020026020010181905250826101e0015160001461306f57613050836101e001516131d7565b81600f81518110613063576130636143e6565b60200260200101819052505b6102008301511561058a57613088836102000151613119565b8160108151811061309b5761309b6143e6565b602002602001018190525092915050565b606060006130b9836131fd565b90506130c7815160c0613333565b816040516020016130d992919061444a565b604051602081830303815290604052915050919050565b60006130fb83610cc5565b9050600082600381111561311157613111613a17565b909155505050565b606061058a6131278361351b565b613168565b604051606082811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208301529061058a90603401612e5c565b60608082516001148015613196575060808360008151811061318c5761318c6143e6565b016020015160f81c105b156131a257508161058a565b6131ae83516080613333565b836040516020016131c092919061444a565b604051602081830303815290604052905092915050565b606061058a61312783613603565b606061058a6131278367ffffffffffffffff16613603565b6060815160000361321e576040805160008082526020820190925290610774565b6000805b83518110156132635783818151811061323d5761323d6143e6565b602002602001015151826132519190613fdb565b915061325c81613fee565b9050613222565b60008267ffffffffffffffff81111561327e5761327e6137bb565b6040519080825280601f01601f1916602001820160405280156132a8576020820181803683370190505b50600092509050602081015b855183101561332a5760008684815181106132d1576132d16143e6565b6020026020010151905060006020820190506132ef8382845161375e565b878581518110613301576133016143e6565b602002602001015151836133159190613fdb565b925050508261332390613fee565b92506132b4565b50949350505050565b60608060388410156133b257604080516001808252818301909252906020820181803683370190505090506133688385614479565b60f81b8160008151811061337e5761337e6143e6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610587565b600060015b6133c18187614492565b156133e4576133cf82613fee565b91506133dd610100826144a6565b90506133b7565b6133ef826001613fdb565b67ffffffffffffffff811115613407576134076137bb565b6040519080825280601f01601f191660200182016040528015613431576020820181803683370190505b50925061343e8583614479565b613449906037614479565b60f81b8360008151811061345f5761345f6143e6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b818111610a32576101006134a782846144bd565b6134b3906101006145b4565b6134bd9088614492565b6134c791906145c0565b60f81b8382815181106134dc576134dc6143e6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061351481613fee565b9050613493565b606060008260405160200161353291815260200190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260208084528383019092529250600091829160208201818036833701905050905060005b815181101561332a57838361359581613fee565b9450815181106135a7576135a76143e6565b602001015160f81c60f81b8282815181106135c4576135c46143e6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506135fc81613fee565b9050613581565b606060008260405160200161361a91815260200190565b604051602081830303815290604052905060005b602081101561368757818181518110613649576136496143e6565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036136875761368081613fee565b905061362e565b60006136948260206144bd565b67ffffffffffffffff8111156136ac576136ac6137bb565b6040519080825280601f01601f1916602001820160405280156136d6576020820181803683370190505b50905060005b815181101561332a5783836136f081613fee565b945081518110613702576137026143e6565b602001015160f81c60f81b82828151811061371f5761371f6143e6565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061375781613fee565b90506136dc565b8282825b6020811061379a5781518352613779602084613fdb565b9250613786602083613fdb565b91506137936020826144bd565b9050613762565b905182516020929092036101000a6000190180199091169116179052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff8111828210171561380e5761380e6137bb565b60405290565b6040805190810167ffffffffffffffff8111828210171561380e5761380e6137bb565b604051610220810167ffffffffffffffff8111828210171561380e5761380e6137bb565b600082601f83011261386c57600080fd5b813567ffffffffffffffff80821115613887576138876137bb565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156138cd576138cd6137bb565b816040528381528660208588010111156138e657600080fd5b836020870160208301376000602085830101528094505050505092915050565b80151581146108ba57600080fd5b6000806040838503121561392757600080fd5b823567ffffffffffffffff81111561393e57600080fd5b61394a8582860161385b565b925050602083013561395b81613906565b809150509250929050565b6001600160a01b03811681146108ba57600080fd5b80356107c381613966565b60006020828403121561399857600080fd5b813561058781613966565b6000806000606084860312156139b857600080fd5b83359250602084013567ffffffffffffffff8111156139d657600080fd5b6139e28682870161385b565b92505060408401356139f381613906565b809150509250925092565b600060208284031215613a1057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110613a7d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161058a8284613a46565b60006101a08284031215613aa257600080fd5b50919050565b600060208284031215613aba57600080fd5b813567ffffffffffffffff811115613ad157600080fd5b61073684828501613a8f565b60008083601f840112613aef57600080fd5b50813567ffffffffffffffff811115613b0757600080fd5b602083019150836020828501011115613b1f57600080fd5b9250929050565b60008060008060608587031215613b3c57600080fd5b8435935060208501359250604085013567ffffffffffffffff811115613b6157600080fd5b613b6d87828801613add565b95989497509550505050565b600080600060408486031215613b8e57600080fd5b833567ffffffffffffffff80821115613ba657600080fd5b613bb287838801613a8f565b94506020860135915080821115613bc857600080fd5b50613bd586828701613add565b9497909650939450505050565b60008060408385031215613bf557600080fd5b823567ffffffffffffffff811115613c0c57600080fd5b61394a85828601613a8f565b60006101a08236031215613c2b57600080fd5b613c336137ea565b82358152613c436020840161397b565b60208201526040830135604082015260608301356060820152613c686080840161397b565b6080820152613c7960a0840161397b565b60a0820152613c8a60c0840161397b565b60c082015260e083810135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013567ffffffffffffffff80821115613cd757600080fd5b613ce33683880161385b565b83850152610180925082860135915080821115613cff57600080fd5b50613d0c3682870161385b565b918301919091525092915050565b60005b83811015613d35578181015183820152602001613d1d565b50506000910152565b60008351613d50818460208801613d1a565b7f2e000000000000000000000000000000000000000000000000000000000000009083019081528351613d8a816001840160208801613d1a565b01600101949350505050565b60008151808452613dae816020860160208601613d1a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006105876020830184613d96565b600060208284031215613e0557600080fd5b815161058781613966565b7f41523a7a65726f416464723a0000000000000000000000000000000000000000815260008251613e4881600c850160208701613d1a565b91909101600c0192915050565b600060208284031215613e6757600080fd5b815161058781613906565b60006101a0825184526020830151613e9560208601826001600160a01b03169052565b5060408301516040850152606083015160608501526080830151613ec460808601826001600160a01b03169052565b5060a0830151613edf60a08601826001600160a01b03169052565b5060c0830151613efa60c08601826001600160a01b03169052565b5060e0838101519085015261010080840151908501526101208084015190850152610140808401519085015261016080840151818601839052613f3f83870182613d96565b925050506101808084015185830382870152613f5b8382613d96565b9695505050505050565b60408152601460408201527f5441494b4f5f4252494447455f4d45535341474500000000000000000000000060608201526080602082015260006105876080830184613e72565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561058a5761058a613fac565b6000600019820361400157614001613fac565b5060010190565b60006020828403121561401a57600080fd5b5051919050565b6020815260006105876020830184613e72565b8581526001600160a01b038516602082015283604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101949350505050565b600082601f8301126140b057600080fd5b60405161010080820182811067ffffffffffffffff821117156140d5576140d56137bb565b604052830181858211156140e857600080fd5b845b828110156141025780358252602091820191016140ea565b509195945050505050565b80356fffffffffffffffffffffffffffffffff811681146107c357600080fd5b803567ffffffffffffffff811681146107c357600080fd5b60006020828403121561415757600080fd5b813567ffffffffffffffff8082111561416f57600080fd5b908301906040828603121561418357600080fd5b61418b613814565b82358281111561419a57600080fd5b830161030081880312156141ad57600080fd5b6141b5613837565b81358152602082013560208201526141cf6040830161397b565b6040820152606082013560608201526080820135608082015260a082013560a08201526141ff8860c0840161409f565b60c08201526101c08083013560e08301526101e061421e81850161410d565b61010084015261020061423281860161412d565b610120850152614245610220860161412d565b610140850152614258610240860161412d565b6101608501526102608501358781111561427157600080fd5b61427d8c82880161385b565b610180860152506102808501356101a085015261429d6102a0860161412d565b838501526102c0850135828501526102e08501358185015250505080835250506020830135828111156142cf57600080fd5b6142db8782860161385b565b60208301525095945050505050565b8581526001600160a01b038516602082015283604082015282606082015260a06080820152600061142a60a0830184613d96565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261438257600080fd5b83018035915067ffffffffffffffff82111561439d57600080fd5b602001915036819003821315613b1f57600080fd5b8183823760009101908152919050565b604081016143d08285613a46565b6001600160a01b03831660208301529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008183825b600881101561443a57815183526020928301929091019060010161441b565b5050506101008201905092915050565b6000835161445c818460208801613d1a565b835190830190614470818360208801613d1a565b01949350505050565b60ff818116838216019081111561058a5761058a613fac565b6000826144a1576144a161431e565b500490565b808202811582820484141761058a5761058a613fac565b8181038181111561058a5761058a613fac565b600181815b8085111561450b5781600019048211156144f1576144f1613fac565b808516156144fe57918102915b93841c93908002906144d5565b509250929050565b6000826145225750600161058a565b8161452f5750600061058a565b8160018114614545576002811461454f5761456b565b600191505061058a565b60ff84111561456057614560613fac565b50506001821b61058a565b5060208310610133831016604e8410600b841016171561458e575081810a61058a565b61459883836144d0565b80600019048211156145ac576145ac613fac565b029392505050565b60006105878383614513565b6000826145cf576145cf61431e565b50069056fea2646970667358221220ec239ef73d6cbee8dbd31c663f4221c77b52ed6e7ce663cdda28f4eaa6af115964736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006" + }, + "code": "0x6080604052600436106100e85760003560e01c8063715018a61161008a5780639aa8605c116100595780639aa8605c146102b0578063c287e578146102e1578063ee1490b214610321578063f2fde38b1461033457600080fd5b8063715018a6146101fe578063780b64f0146102135780638da5cb5b146102725780639754149b1461029057600080fd5b80631be2bfa7116100c65780631be2bfa71461016c57806339da33ba1461018c5780633ab76e9f1461019f57806367090ccf146101bd57600080fd5b80630c6fab82146100ed5780630ca4dffd1461010f57806319ab453c1461014c575b600080fd5b3480156100f957600080fd5b5061010d6101083660046128f5565b610354565b005b34801561011b57600080fd5b5061012f61012a366004612a50565b610609565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015857600080fd5b5061010d610167366004612aa2565b61061f565b34801561017857600080fd5b5061012f610187366004612abf565b61079e565b61010d61019a366004612b1a565b6107b5565b3480156101ab57600080fd5b506097546001600160a01b031661012f565b3480156101c957600080fd5b5061012f6101d8366004612b98565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b34801561020a57600080fd5b5061010d610adb565b34801561021f57600080fd5b5061025361022e366004612bbd565b60cc60205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b039093168352602083019190915201610143565b34801561027e57600080fd5b506065546001600160a01b031661012f565b34801561029c57600080fd5b5061010d6102ab366004612bd6565b610aef565b3480156102bc57600080fd5b506102d06102cb366004612aa2565b610f16565b604051610143959493929190612cc6565b3480156102ed57600080fd5b506103116102fc366004612aa2565b60c96020526000908152604090205460ff1681565b6040519015158152602001610143565b61010d61032f366004612d15565b611078565b34801561034057600080fd5b5061010d61034f366004612aa2565b611a29565b61035c611ab9565b6040518060400160405280600681526020017f627269646765000000000000000000000000000000000000000000000000000081525061039d816000610609565b6001600160a01b0316336001600160a01b0316146103e7576040517f1b0b999e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610427573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044b9190612db1565b905061049281604001516040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250600061079e565b6001600160a01b031681602001516001600160a01b0316146104e0576040517f80962e1c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600046873503610515576104fa6040880160208901612aa2565b90506105106001600160a01b0382168686611b12565b61059e565b61051e87611bbb565b6040517f42e91bb30000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908216906342e91bb390604401600060405180830381600087803b15801561058557600080fd5b505af1158015610599573d6000803e3d6000fd5b505050505b815160408084015181519081526001600160a01b0384811660208301529181018790528188169291891691907fe5da926519fc972010fe65b35c1e3339e6dc72b35ffaec203999c2a2a2593eac9060600160405180910390a450505061060360018055565b50505050565b6000610616468484611c1a565b90505b92915050565b600054610100900460ff161580801561063f5750600054600160ff909116105b806106595750303b158015610659575060005460ff166001145b6106d05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561072e57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61073782611d2d565b801561079a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006107ab848484611c1a565b90505b9392505050565b6107bd611ab9565b6001600160a01b0385161580610824575061080f866040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250600061079e565b6001600160a01b0316856001600160a01b0316145b1561085b576040517f4694641b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b823411610894576040517fae3718b400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610923604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018790523360808201526001600160a01b03861660a0820152610140810185905261012081018490526109598434612e13565b60e08201526001600160a01b03831660c08201526101808101829052610100810151156109b2576040517f3dd99f7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006109f46040518060400160405280600681526020017f62726964676500000000000000000000000000000000000000000000000000008152506000610609565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b8152600401610a209190612e4d565b60206040518083038185885af1158015610a3e573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a639190612f47565b90508160a001516001600160a01b031682608001516001600160a01b0316827fe2f39179c279514a7b46983846e33f95a561128e0660602a211cc1e61cddb9bd8b8660e00151604051610ac0929190918252602082015260400190565b60405180910390a45050610ad360018055565b505050505050565b610ae3611d46565b610aed6000611da0565b565b610af7611ab9565b6000610b0960a0850160808601612aa2565b6001600160a01b031603610b49576040517f72b41cdf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836040013514610b86576040517f48bc100500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610bc86040518060400160405280600681526020017f62726964676500000000000000000000000000000000000000000000000000008152506000610609565b90506000816001600160a01b0316635817b0c3866040518263ffffffff1660e01b8152600401610bf89190612ff6565b602060405180830381865afa158015610c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c399190612f47565b600081815260cc6020526040902080546001909101549192506001600160a01b03169081610c93576040517f7c6addb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fce70f39b0000000000000000000000000000000000000000000000000000000081526001600160a01b0385169063ce70f39b90610ce290869060608c0135908b908b90600401613114565b602060405180830381865afa158015610cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d239190613134565b610d59576040517f45d24f2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820182526000808252602080830182815287835260cc909152929020905181547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0390911617815590516001909101558015610e9d576001600160a01b038216600090815260c9602052604090205460ff1615610e79576001600160a01b0382166342e91bb3610dfc60a08a0160808b01612aa2565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260248101849052604401600060405180830381600087803b158015610e5c57600080fd5b505af1158015610e70573d6000803e3d6000fd5b50505050610e9d565b610e9d610e8c60a0890160808a01612aa2565b6001600160a01b0384169083611b12565b610ead60a0880160808901612aa2565b6001600160a01b0316837fc5d9f7cd7998e24ecf12ad69eca9339764e2cb13788d5d9616f502601b219af68484604051610efc9291906001600160a01b03929092168252602082015260400190565b60405180910390a350505050610f1160018055565b505050565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b038316937401000000000000000000000000000000000000000090930460ff1692909190610f6790613151565b80601f0160208091040260200160405190810160405280929190818152602001828054610f9390613151565b8015610fe05780601f10610fb557610100808354040283529160200191610fe0565b820191906000526020600020905b815481529060010190602001808311610fc357829003601f168201915b505050505090806003018054610ff590613151565b80601f016020809104026020016040519081016040528092919081815260200182805461102190613151565b801561106e5780601f106110435761010080835404028352916020019161106e565b820191906000526020600020905b81548152906001019060200180831161105157829003601f168201915b5050505050905085565b611080611ab9565b6001600160a01b03871615806110e757506110d2886040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250600061079e565b6001600160a01b0316876001600160a01b0316145b1561111e576040517f4694641b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661115e576040517f7c6addb700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84600003611198576040517f015f093200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160a08101825260008082526020820181905291810191909152606080820181905260808201526001600160a01b038716600090815260c9602052604081205460ff1615611432576040517f77be18a8000000000000000000000000000000000000000000000000000000008152336004820152602481018890526001600160a01b038916906377be18a890604401600060405180830381600087803b15801561124457600080fd5b505af1158015611258573d6000803e3d6000fd5b505050506001600160a01b03888116600090815260ca6020908152604091829020825160a081018452815481526001820154948516928101929092527401000000000000000000000000000000000000000090930460ff16918101919091526002820180549192916060840191906112cf90613151565b80601f01602080910402602001604051908101604052809291908181526020018280546112fb90613151565b80156113485780601f1061131d57610100808354040283529160200191611348565b820191906000526020600020905b81548152906001019060200180831161132b57829003601f168201915b5050505050815260200160038201805461136190613151565b80601f016020809104026020016040519081016040528092919081815260200182805461138d90613151565b80156113da5780601f106113af576101008083540402835291602001916113da565b820191906000526020600020905b8154815290600101906020018083116113bd57829003601f168201915b5050509190925250505060208101519092506001600160a01b031661142b576040517ff91680d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50856116c4565b60008890506040518060a001604052804681526020018a6001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611495573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b991906131b3565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156114ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261152791908101906131d0565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801561156a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261159291908101906131d0565b90526040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529093506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156115f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161b9190612f47565b90506116326001600160a01b03831633308c611e0a565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015611691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b59190612f47565b6116bf9190612e13565b925050505b611753604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018b905233608082015260408051808201909152600b81527f746f6b656e5f7661756c7400000000000000000000000000000000000000000060208201526117a1908c90600061079e565b6001600160a01b031660a082015260808101516040517f0c6fab8200000000000000000000000000000000000000000000000000000000916117ec918691908e908790602401613247565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526101608201526101408101879052610120810186905261186b8634612e13565b60e08201526001600160a01b03851660c0820152610180810184905260408051808201909152600681527f627269646765000000000000000000000000000000000000000000000000000060208201526000906118c89082610609565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b81526004016118f49190612e4d565b60206040518083038185885af1158015611912573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906119379190612f47565b905060405180604001604052808b6001600160a01b031681526020018481525060cc600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550602082015181600101559050508a6001600160a01b031682608001516001600160a01b0316827f325cab7553038374e17f39bb45e2a2c90f66c6a52798cb5f95c20d94c11c95e28f8e88604051611a0a939291909283526001600160a01b03919091166020830152604082015260600190565b60405180910390a450505050611a1f60018055565b5050505050505050565b611a31611d46565b6001600160a01b038116611aad5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106c7565b611ab681611da0565b50565b600260015403611b0b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016106c7565b6002600155565b6040516001600160a01b038316602482015260448101829052610f119084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611e5b565b8035600090815260cb60209081526040808320839290918391611be2918701908701612aa2565b6001600160a01b0390811682526020820192909252604001600020541690508061061957611c0f83611f40565b6107ae565b60018055565b600080611c26856121f7565b84604051602001611c389291906132fe565b60408051601f19818403018152908290526097547fbf40fac10000000000000000000000000000000000000000000000000000000083529092506001600160a01b03169063bf40fac190611c90908490600401613356565b602060405180830381865afa158015611cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd19190613369565b915082611d25576040516001600160a01b038316151590611cf6908390602001613386565b60405160208183030381529060405290611d235760405162461bcd60e51b81526004016106c79190613356565b505b509392505050565b611d356122b5565b611d3d61233a565b611ab6816123bf565b6065546001600160a01b03163314610aed5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106c7565b606580546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526106039085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611b57565b6000611eb0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166124399092919063ffffffff16565b805190915015610f115780806020019051810190611ece9190613134565b610f115760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016106c7565b6000611fd5818335611f586040860160208701612aa2565b604051602001611f9792919091825260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602082015260340190565b6040516020818303038152906040528051906020012060405180602001611fbd906128c3565b601f1982820381018352601f90910116604052612448565b6097549091506001600160a01b0380831691636c0db62b9116611ffe6040860160208701612aa2565b853561201060608801604089016133cb565b61201d60608901896133e8565b61202a60808b018b6133e8565b60405161203e9291908d359060200161344d565b6040516020818303038152906040526040518863ffffffff1660e01b815260040161206f97969594939291906134d0565b600060405180830381600087803b15801561208957600080fd5b505af115801561209d573d6000803e3d6000fd5b5050506001600160a01b038216600090815260c96020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560ca90915290208391506120f8828261366f565b50508135600090815260cb6020908152604080832084939092909161212291908701908701612aa2565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b03168260200160208101906121839190612aa2565b6001600160a01b031683357f9e465b29e576a3e01584e31d607353f21b80c055e813af907c0a495f6cf4f7bc6121bc60608701876133e8565b6121c960808901896133e8565b6121d960608b0160408c016133cb565b6040516121ea95949392919061371d565b60405180910390a4919050565b606060006122048361254c565b600101905060008167ffffffffffffffff81111561222457612224612964565b6040519080825280601f01601f19166020018201604052801561224e576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461225857509392505050565b600054610100900460ff166123325760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106c7565b610aed61262e565b600054610100900460ff166123b75760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106c7565b610aed6126ab565b6001600160a01b0381166123ff576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60606107ab8484600085612731565b60008347101561249a5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064016106c7565b81516000036124eb5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016106c7565b8282516020840186f590506001600160a01b0381166107ae5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016106c7565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612595577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106125c1576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106125df57662386f26fc10000830492506010015b6305f5e10083106125f7576305f5e100830492506008015b612710831061260b57612710830492506004015b6064831061261d576064830492506002015b600a83106106195760010192915050565b600054610100900460ff16611c145760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106c7565b600054610100900460ff166127285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016106c7565b610aed33611da0565b6060824710156127a95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016106c7565b600080866001600160a01b031685876040516127c5919061375a565b60006040518083038185875af1925050503d8060008114612802576040519150601f19603f3d011682016040523d82523d6000602084013e612807565b606091505b509150915061281887838387612825565b925050505b949350505050565b6060831561289457825160000361288d576001600160a01b0385163b61288d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106c7565b508161281d565b61281d83838151156128a95781518083602001fd5b8060405162461bcd60e51b81526004016106c79190613356565b6121518061377783390190565b6001600160a01b0381168114611ab657600080fd5b80356128f0816128d0565b919050565b6000806000806080858703121561290b57600080fd5b843567ffffffffffffffff81111561292257600080fd5b850160a0818803121561293457600080fd5b93506020850135612944816128d0565b92506040850135612954816128d0565b9396929550929360600135925050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156129bc576129bc612964565b604052919050565b600067ffffffffffffffff8211156129de576129de612964565b50601f01601f191660200190565b600082601f8301126129fd57600080fd5b8135612a10612a0b826129c4565b612993565b818152846020838601011115612a2557600080fd5b816020850160208301376000918101602001919091529392505050565b8015158114611ab657600080fd5b60008060408385031215612a6357600080fd5b823567ffffffffffffffff811115612a7a57600080fd5b612a86858286016129ec565b9250506020830135612a9781612a42565b809150509250929050565b600060208284031215612ab457600080fd5b81356107ae816128d0565b600080600060608486031215612ad457600080fd5b83359250602084013567ffffffffffffffff811115612af257600080fd5b612afe868287016129ec565b9250506040840135612b0f81612a42565b809150509250925092565b60008060008060008060c08789031215612b3357600080fd5b863595506020870135612b45816128d0565b945060408701359350606087013592506080870135612b63816128d0565b915060a087013567ffffffffffffffff811115612b7f57600080fd5b612b8b89828a016129ec565b9150509295509295509295565b60008060408385031215612bab57600080fd5b823591506020830135612a97816128d0565b600060208284031215612bcf57600080fd5b5035919050565b600080600060408486031215612beb57600080fd5b833567ffffffffffffffff80821115612c0357600080fd5b908501906101a08288031215612c1857600080fd5b90935060208501359080821115612c2e57600080fd5b818601915086601f830112612c4257600080fd5b813581811115612c5157600080fd5b876020828501011115612c6357600080fd5b6020830194508093505050509250925092565b60005b83811015612c91578181015183820152602001612c79565b50506000910152565b60008151808452612cb2816020860160208601612c76565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260ff8416604082015260a060608201526000612cf760a0830185612c9a565b8281036080840152612d098185612c9a565b98975050505050505050565b600080600080600080600080610100898b031215612d3257600080fd5b883597506020890135612d44816128d0565b96506040890135612d54816128d0565b9550606089013594506080890135935060a0890135925060c0890135612d79816128d0565b915060e089013567ffffffffffffffff811115612d9557600080fd5b612da18b828c016129ec565b9150509295985092959890939650565b600060608284031215612dc357600080fd5b6040516060810181811067ffffffffffffffff82111715612de657612de6612964565b604052825181526020830151612dfb816128d0565b60208201526040928301519281019290925250919050565b81810381811115610619577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b602081528151602082015260006020830151612e7460408401826001600160a01b03169052565b5060408301516060830152606083015160808301526080830151612ea360a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a0610180808501829052612f216101c0860184612c9a565b90860151858203601f190183870152909250612f3d8382612c9a565b9695505050505050565b600060208284031215612f5957600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612f9557600080fd5b830160208101925035905067ffffffffffffffff811115612fb557600080fd5b803603821315612fc457600080fd5b9250929050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6020815281356020820152600061300f602084016128e5565b6001600160a01b038116604084015250604083013560608301526060830135608083015261303f608084016128e5565b6001600160a01b03811660a08401525061305b60a084016128e5565b6001600160a01b03811660c08401525061307760c084016128e5565b6001600160a01b03811660e08401525061010060e0840135818401526101208185013581850152610140915080850135828501525061016081850135818501526130c381860186612f60565b925090506101a061018081818701526130e16101c087018585612fcb565b93506130ef81880188612f60565b93509050601f198685030182870152613109848483612fcb565b979650505050505050565b848152836020820152606060408201526000612f3d606083018486612fcb565b60006020828403121561314657600080fd5b81516107ae81612a42565b600181811c9082168061316557607f821691505b60208210810361319e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60ff81168114611ab657600080fd5b6000602082840312156131c557600080fd5b81516107ae816131a4565b6000602082840312156131e257600080fd5b815167ffffffffffffffff8111156131f957600080fd5b8201601f8101841361320a57600080fd5b8051613218612a0b826129c4565b81815285602083850101111561322d57600080fd5b61323e826020830160208601612c76565b95945050505050565b6080815284516080820152600060208601516001600160a01b0380821660a085015260ff60408901511660c08501526060880151915060a060e0850152613292610120850183612c9a565b915060808801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80858403016101008601526132ce8382612c9a565b9188166020860152506001600160a01b038616604085015291506132ef9050565b82606083015295945050505050565b60008351613310818460208801612c76565b7f2e00000000000000000000000000000000000000000000000000000000000000908301908152835161334a816001840160208801612c76565b01600101949350505050565b6020815260006106166020830184612c9a565b60006020828403121561337b57600080fd5b81516107ae816128d0565b7f41523a7a65726f416464723a00000000000000000000000000000000000000008152600082516133be81600c850160208701612c76565b91909101600c0192915050565b6000602082840312156133dd57600080fd5b81356107ae816131a4565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261341d57600080fd5b83018035915067ffffffffffffffff82111561343857600080fd5b602001915036819003821315612fc457600080fd5b828482377f286272696467656400000000000000000000000000000000000000000000000092019182527ff09f8c88000000000000000000000000000000000000000000000000000000006008830152600c8201527f2900000000000000000000000000000000000000000000000000000000000000602c820152602d01919050565b60006001600160a01b03808a16835280891660208401525086604083015260ff8616606083015260c0608083015261350c60c083018587612fcb565b82810360a084015261351e8185612c9a565b9a9950505050505050505050565b601f821115610f1157600081815260208120601f850160051c810160208610156135535750805b601f850160051c820191505b81811015610ad35782815560010161355f565b67ffffffffffffffff83111561358a5761358a612964565b61359e836135988354613151565b8361352c565b6000601f8411600181146135f057600085156135ba5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355613668565b600083815260209020601f19861690835b828110156136215786850135825560209485019460019092019101613601565b508682101561365c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b81358155600181016020830135613685816128d0565b81546040850135613695816131a4565b74ff00000000000000000000000000000000000000008160a01b166001600160a01b0384167fffffffffffffffffffffff000000000000000000000000000000000000000000841617178455505050506136f260608301836133e8565b613700818360028601613572565b505061370f60808301836133e8565b610603818360038601613572565b606081526000613731606083018789612fcb565b8281036020840152613744818688612fcb565b91505060ff831660408301529695505050505050565b6000825161376c818460208701612c76565b919091019291505056fe608060405234801561001057600080fd5b50612131806100206000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806367e828bf116100e35780638da5cb5b1161008c578063a9059cbb11610066578063a9059cbb146103b4578063dd62ed3e146103c7578063f2fde38b1461040d57600080fd5b80638da5cb5b1461037b57806395d89b4114610399578063a457c2d7146103a157600080fd5b8063715018a6116100bd578063715018a61461034057806377be18a8146103485780637cf8ed0d1461035b57600080fd5b806367e828bf146102a75780636c0db62b146102f757806370a082311461030a57600080fd5b806323b872dd116101455780633ab76e9f1161011f5780633ab76e9f1461026b57806342e91bb31461028957806349d126051461029e57600080fd5b806323b872dd14610230578063313ce56714610243578063395093511461025857600080fd5b80630ca4dffd116101765780630ca4dffd146101d357806318160ddd1461020b5780631be2bfa71461021d57600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a610420565b6040516101a79190611abd565b60405180910390f35b6101c36101be366004611b30565b6104b2565b60405190151581526020016101a7565b6101e66101e1366004611c4b565b6104cc565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b60cb545b6040519081526020016101a7565b6101e661022b366004611c99565b6104e0565b6101c361023e366004611cf0565b6104f5565b60ce5460405160ff90911681526020016101a7565b6101c3610266366004611b30565b610551565b60975473ffffffffffffffffffffffffffffffffffffffff166101e6565b61029c610297366004611b30565b61059d565b005b61020f60fc5481565b6102cb60fb5460fc5473ffffffffffffffffffffffffffffffffffffffff90911691565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101a7565b61029c610305366004611d31565b6106a1565b61020f610318366004611ddb565b73ffffffffffffffffffffffffffffffffffffffff16600090815260c9602052604090205490565b61029c6108eb565b61029c610356366004611b30565b6108ff565b60fb546101e69073ffffffffffffffffffffffffffffffffffffffff1681565b60655473ffffffffffffffffffffffffffffffffffffffff166101e6565b61019a6109f6565b6101c36103af366004611b30565b610a05565b6101c36103c2366004611b30565b610ac7565b61020f6103d5366004611df8565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260ca6020908152604080832093909416825291909152205490565b61029c61041b366004611ddb565b610b22565b606060cc805461042f90611e31565b80601f016020809104026020016040519081016040528092919081815260200182805461045b90611e31565b80156104a85780601f1061047d576101008083540402835291602001916104a8565b820191906000526020600020905b81548152906001019060200180831161048b57829003601f168201915b5050505050905090565b6000336104c0818585610bbf565b60019150505b92915050565b60006104d9468484610d3e565b9392505050565b60006104ed848484610d3e565b949350505050565b60003073ffffffffffffffffffffffffffffffffffffffff841603610546576040517f669bcddc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104ed848484610e89565b33600081815260ca6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104c09082908690610598908790611eb3565b610bbf565b6040518060400160405280600b81526020017f746f6b656e5f7661756c740000000000000000000000000000000000000000008152506105de8160006104cc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610642576040517f1b0b999e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61064c8383610ea2565b8273ffffffffffffffffffffffffffffffffffffffff167f397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa68360405161069491815260200190565b60405180910390a2505050565b600054610100900460ff16158080156106c15750600054600160ff909116105b806106db5750303b1580156106db575060005460ff166001145b6107525760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156107b057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff861615806107d1575084155b806107db57504685145b806107e557508251155b806107ef57508151155b15610826576040517ff12d598000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082f87610f60565b61083a828486610f79565b60fb80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff881617905560fc85905580156108e257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6108f3611006565b6108fd600061106d565b565b6040518060400160405280600b81526020017f746f6b656e5f7661756c740000000000000000000000000000000000000000008152506109408160006104cc565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109a4576040517f1b0b999e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109ae83836110e4565b8273ffffffffffffffffffffffffffffffffffffffff167f9b5b9a05e4726d8bb959f1440e05c6b8109443f2083bc4e386237d76545265538360405161069491815260200190565b606060cd805461042f90611e31565b33600081815260ca6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610aaf5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610749565b610abc8286868403610bbf565b506001949350505050565b60003073ffffffffffffffffffffffffffffffffffffffff841603610b18576040517f669bcddc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104d98383611255565b610b2a611006565b73ffffffffffffffffffffffffffffffffffffffff8116610bb35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610749565b610bbc8161106d565b50565b73ffffffffffffffffffffffffffffffffffffffff8316610c475760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff8216610cd05760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600080610d4a85611263565b84604051602001610d5c929190611ec6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac190610ddf908490600401611abd565b602060405180830381865afa158015610dfc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e209190611f1e565b915082610e815760405173ffffffffffffffffffffffffffffffffffffffff8316151590610e52908390602001611f3b565b60405160208183030381529060405290610e7f5760405162461bcd60e51b81526004016107499190611abd565b505b509392505050565b600033610e97858285611321565b610abc8585856113de565b73ffffffffffffffffffffffffffffffffffffffff8216610f055760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610749565b8060cb6000828254610f179190611eb3565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260c9602052604081208054839290610f51908490611eb3565b90915550610f5c9050565b5050565b610f68611643565b610f706116c8565b610bbc8161174d565b600054610100900460ff16610ff65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b6110018383836117e1565b505050565b60655473ffffffffffffffffffffffffffffffffffffffff1633146108fd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610749565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b73ffffffffffffffffffffffffffffffffffffffff821661116d5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260c96020526040902054818110156112095760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260c960205260408120838303905560cb8054849290611245908490611f80565b9091555061100190508360008483565b6000336104c08185856113de565b60606000611270836118ae565b600101905060008167ffffffffffffffff81111561129057611290611b5c565b6040519080825280601f01601f1916602001820160405280156112ba576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85049450846112c457509392505050565b73ffffffffffffffffffffffffffffffffffffffff838116600090815260ca60209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146113d857818110156113cb5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610749565b6113d88484848403610bbf565b50505050565b73ffffffffffffffffffffffffffffffffffffffff83166114675760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff82166114f05760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260c960205260409020548181101561158c5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610749565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260c960205260408082208585039055918516815290812080548492906115d0908490611eb3565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161163691815260200190565b60405180910390a36113d8565b600054610100900460ff166116c05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b6108fd611990565b600054610100900460ff166117455760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b6108fd611a13565b73ffffffffffffffffffffffffffffffffffffffff811661179a576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600054610100900460ff1661185e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b60cc61186a8482611fe1565b5060cd6118778382611fe1565b5060ce80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff929092169190911790555050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106118f7577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310611923576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061194157662386f26fc10000830492506010015b6305f5e1008310611959576305f5e100830492506008015b612710831061196d57612710830492506004015b6064831061197f576064830492506002015b600a83106104c65760010192915050565b600054610100900460ff16611a0d5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b60018055565b600054610100900460ff16611a905760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610749565b6108fd3361106d565b60005b83811015611ab4578181015183820152602001611a9c565b50506000910152565b6020815260008251806020840152611adc816040850160208701611a99565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff81168114610bbc57600080fd5b60008060408385031215611b4357600080fd5b8235611b4e81611b0e565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112611b9c57600080fd5b813567ffffffffffffffff80821115611bb757611bb7611b5c565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611bfd57611bfd611b5c565b81604052838152866020858801011115611c1657600080fd5b836020870160208301376000602085830101528094505050505092915050565b80358015158114611c4657600080fd5b919050565b60008060408385031215611c5e57600080fd5b823567ffffffffffffffff811115611c7557600080fd5b611c8185828601611b8b565b925050611c9060208401611c36565b90509250929050565b600080600060608486031215611cae57600080fd5b83359250602084013567ffffffffffffffff811115611ccc57600080fd5b611cd886828701611b8b565b925050611ce760408501611c36565b90509250925092565b600080600060608486031215611d0557600080fd5b8335611d1081611b0e565b92506020840135611d2081611b0e565b929592945050506040919091013590565b60008060008060008060c08789031215611d4a57600080fd5b8635611d5581611b0e565b95506020870135611d6581611b0e565b945060408701359350606087013560ff81168114611d8257600080fd5b9250608087013567ffffffffffffffff80821115611d9f57600080fd5b611dab8a838b01611b8b565b935060a0890135915080821115611dc157600080fd5b50611dce89828a01611b8b565b9150509295509295509295565b600060208284031215611ded57600080fd5b81356104d981611b0e565b60008060408385031215611e0b57600080fd5b8235611e1681611b0e565b91506020830135611e2681611b0e565b809150509250929050565b600181811c90821680611e4557607f821691505b602082108103611e7e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104c6576104c6611e84565b60008351611ed8818460208801611a99565b7f2e000000000000000000000000000000000000000000000000000000000000009083019081528351611f12816001840160208801611a99565b01600101949350505050565b600060208284031215611f3057600080fd5b81516104d981611b0e565b7f41523a7a65726f416464723a0000000000000000000000000000000000000000815260008251611f7381600c850160208701611a99565b91909101600c0192915050565b818103818111156104c6576104c6611e84565b601f82111561100157600081815260208120601f850160051c81016020861015611fba5750805b601f850160051c820191505b81811015611fd957828155600101611fc6565b505050505050565b815167ffffffffffffffff811115611ffb57611ffb611b5c565b61200f816120098454611e31565b84611f93565b602080601f831160018114612062576000841561202c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611fd9565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156120af57888601518255948401946001909101908401612090565b50858210156120eb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122097aea87c926aeac94c95489d7f3674e61115440bca078ca4ef2af4eae4f9fea364736f6c63430008120033a264697066735822122089e27a345c7c6ec2e044b333ee9138d2f0743901e70542a655eb5279da9b965b64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006", + "0x029ae2e2f1d6964720a0fa7e6ffa902f995c156242f4f5a930aa9d9765d167d0": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "code": "0x6080604052600436106100c05760003560e01c8063715018a611610074578063d73bb3d01161004e578063d73bb3d014610257578063f2fde38b14610277578063fe9fbb801461029757600080fd5b8063715018a6146101f75780638da5cb5b1461020c578063ba0bbd951461023757600080fd5b80631be2bfa7116100a55780631be2bfa71461018c5780632d1fb389146101ac5780633ab76e9f146101cc57600080fd5b80630ca4dffd1461012257806319ab453c1461016c57600080fd5b3661011d5747158015906100e4575033600090815260c9602052604090205460ff16155b1561011b576040517f4fa3f24500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b34801561012e57600080fd5b5061014261013d36600461119e565b6102ed565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561017857600080fd5b5061011b61018736600461120e565b610301565b34801561019857600080fd5b506101426101a736600461122b565b61049a565b3480156101b857600080fd5b5061011b6101c7366004611282565b6104af565b3480156101d857600080fd5b5060975473ffffffffffffffffffffffffffffffffffffffff16610142565b34801561020357600080fd5b5061011b6105c6565b34801561021857600080fd5b5060655473ffffffffffffffffffffffffffffffffffffffff16610142565b34801561024357600080fd5b5061011b6102523660046112ae565b6105da565b34801561026357600080fd5b5061011b6102723660046112da565b6106f1565b34801561028357600080fd5b5061011b61029236600461120e565b61078d565b3480156102a357600080fd5b506102dd6102b236600461120e565b73ffffffffffffffffffffffffffffffffffffffff16600090815260c9602052604090205460ff1690565b6040519015158152602001610163565b60006102fa468484610841565b9392505050565b600054610100900460ff16158080156103215750600054600160ff909116105b8061033b5750303b15801561033b575060005460ff166001145b6103cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561042a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610433826109a6565b801561049657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006104a7848484610841565b949350505050565b6104b76109bf565b73ffffffffffffffffffffffffffffffffffffffff82161580610505575073ffffffffffffffffffffffffffffffffffffffff8216600090815260c9602052604090205460ff161515811515145b1561053c576040517f6faf7e9c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815260c9602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b6105ce6109bf565b6105d86000610a40565b565b33600090815260c9602052604090205460ff16610623576040517f4fa3f24500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61062b610ab7565b73ffffffffffffffffffffffffffffffffffffffff8216610678576040517f687563df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61069873ffffffffffffffffffffffffffffffffffffffff831682610b2a565b8173ffffffffffffffffffffffffffffffffffffffff167f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e826040516106e091815260200190565b60405180910390a261049660018055565b33600090815260c9602052604090205460ff1661073a576040517f4fa3f24500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610742610ab7565b61074c3382610b2a565b60405181815233907f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e9060200160405180910390a261078a60018055565b50565b6107956109bf565b73ffffffffffffffffffffffffffffffffffffffff8116610838576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103c3565b61078a81610a40565b60008061084d85610c05565b8460405160200161085f929190611317565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac1906108e290849060040161136f565b602060405180830381865afa1580156108ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061092391906113c0565b91508261099e5760405173ffffffffffffffffffffffffffffffffffffffff83161515906109559083906020016113dd565b6040516020818303038152906040529061099c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103c3919061136f565b505b509392505050565b6109ae610cc3565b6109b6610d62565b61078a81610e01565b60655473ffffffffffffffffffffffffffffffffffffffff1633146105d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c3565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600260015403610b23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103c3565b6002600155565b80156104965760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610b8a576040519150601f19603f3d011682016040523d82523d6000602084013e610b8f565b606091505b5050905080610bfa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016103c3565b505050565b60018055565b60606000610c1283610e95565b600101905060008167ffffffffffffffff811115610c3257610c326110af565b6040519080825280601f01601f191660200182016040528015610c5c576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084610c6657509392505050565b600054610100900460ff16610d5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016103c3565b6105d8610f78565b600054610100900460ff16610df9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016103c3565b6105d861100f565b73ffffffffffffffffffffffffffffffffffffffff8116610e4e576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310610ede577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310610f0a576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610f2857662386f26fc10000830492506010015b6305f5e1008310610f40576305f5e100830492506008015b6127108310610f5457612710830492506004015b60648310610f66576064830492506002015b600a8310610f72576001015b92915050565b600054610100900460ff16610bff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016103c3565b600054610100900460ff166110a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016103c3565b6105d833610a40565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126110ef57600080fd5b813567ffffffffffffffff8082111561110a5761110a6110af565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611150576111506110af565b8160405283815286602085880101111561116957600080fd5b836020870160208301376000602085830101528094505050505092915050565b8035801515811461119957600080fd5b919050565b600080604083850312156111b157600080fd5b823567ffffffffffffffff8111156111c857600080fd5b6111d4858286016110de565b9250506111e360208401611189565b90509250929050565b73ffffffffffffffffffffffffffffffffffffffff8116811461078a57600080fd5b60006020828403121561122057600080fd5b81356102fa816111ec565b60008060006060848603121561124057600080fd5b83359250602084013567ffffffffffffffff81111561125e57600080fd5b61126a868287016110de565b92505061127960408501611189565b90509250925092565b6000806040838503121561129557600080fd5b82356112a0816111ec565b91506111e360208401611189565b600080604083850312156112c157600080fd5b82356112cc816111ec565b946020939093013593505050565b6000602082840312156112ec57600080fd5b5035919050565b60005b8381101561130e5781810151838201526020016112f6565b50506000910152565b600083516113298184602088016112f3565b7f2e0000000000000000000000000000000000000000000000000000000000000090830190815283516113638160018401602088016112f3565b01600101949350505050565b602081526000825180602084015261138e8160408501602087016112f3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000602082840312156113d257600080fd5b81516102fa816111ec565b7f41523a7a65726f416464723a000000000000000000000000000000000000000081526000825161141581600c8501602087016112f3565b91909101600c019291505056fea26469706673582212205ba76b4da10c920143efe8a59a5126aa1d82a4e0405a1710388f185b06f3d9e964736f6c63430008120033", + "balance": "0xffffffffffffff59776f94274fffffff" + }, + "0x0000777700000000000000000000000000000007": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80635221f613116100815780638da5cb5b1161005b5780638da5cb5b146101b0578063f2fde38b146101ce578063f8f3f844146101e157600080fd5b80635221f6131461017457806366ca2bc014610187578063715018a6146101a857600080fd5b80631be2bfa7116100b25780631be2bfa71461012057806332676bc6146101335780633ab76e9f1461015657600080fd5b80630ca4dffd146100ce57806319ab453c1461010b575b600080fd5b6100e16100dc366004611c53565b61020b565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61011e610119366004611cd7565b610221565b005b6100e161012e366004611cf4565b6103ba565b610146610141366004611d4f565b6103cf565b6040519015158152602001610102565b60975473ffffffffffffffffffffffffffffffffffffffff166100e1565b610146610182366004611d7b565b61047a565b61019a610195366004611e11565b610767565b604051908152602001610102565b61011e6107c3565b60655473ffffffffffffffffffffffffffffffffffffffff166100e1565b61011e6101dc366004611cd7565b6107d7565b61019a6101ef366004611d4f565b6040805192835260208301919091528082206060909201905290565b600061021846848461088e565b90505b92915050565b600054610100900460ff16158080156102415750600054600160ff909116105b8061025b5750303b15801561025b575060005460ff166001145b6102ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561034a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610353826109f3565b80156103b657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006103c784848461088e565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff831661041e576040517fa99bf91a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000829003610459576040517f053c769c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080519283526020830191909152808220606090920190525460011490565b60004686036104b5576040517fe822b48d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8516610502576040517fa99bf91a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084900361053d576040517f053c769c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061054b83850185611ed0565b9050600061058f6040518060400160405280600581526020017f7461696b6f000000000000000000000000000000000000000000000000000000815250600061020b565b825161010001516040517f25bf86f20000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff91909116906325bf86f290602401602060405180830381865afa158015610615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106399190612075565b905080158015906106535750815161065090610a0c565b81145b801561075b575073B51f0f2bdCbf6cfabB35239921A5c672519F74ba63960304398360000151606001516106be8b6040518060400160405280600e81526020017f7369676e616c5f7365727669636500000000000000000000000000000000000081525060006103ba565b604080518c8152602081018c9052818120606090910190915260208701516040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815261071a949392916001916004016120fc565b602060405180830381865af4158015610737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075b9190612148565b98975050505050505050565b60008181036107a2576040517f053c769c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080513381526020810192909252808220606090920190526001815590565b6107cb610a31565b6107d56000610ab2565b565b6107df610a31565b73ffffffffffffffffffffffffffffffffffffffff8116610882576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102e3565b61088b81610ab2565b50565b60008061089a85610b29565b846040516020016108ac929190612165565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac19061092f9084906004016121bd565b602060405180830381865afa15801561094c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097091906121d0565b9150826109eb5760405173ffffffffffffffffffffffffffffffffffffffff83161515906109a29083906020016121ed565b604051602081830303815290604052906109e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102e391906121bd565b505b509392505050565b6109fb610be7565b610a03610c86565b61088b81610d25565b600080610a22610a1d846000610db9565b6111fd565b80516020909101209392505050565b60655473ffffffffffffffffffffffffffffffffffffffff1633146107d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102e3565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60606000610b3683611241565b600101905060008167ffffffffffffffff811115610b5657610b56611b1e565b6040519080825280601f01601f191660200182016040528015610b80576020820181803683370190505b5090508181016020015b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084610b8a57509392505050565b600054610100900460ff16610c7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102e3565b6107d5611323565b600054610100900460ff16610d1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102e3565b6107d56113c0565b73ffffffffffffffffffffffffffffffffffffffff8116610d72576040517f9a109b0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61020082015160609015610e2557610dd2826011612290565b67ffffffffffffffff811115610dea57610dea611b1e565b604051908082528060200260200182016040528015610e1d57816020015b6060815260200190600190039081610e085790505b509050610e95565b6101e083015115610e3b57610dd2826010612290565b610e4682600f612290565b67ffffffffffffffff811115610e5e57610e5e611b1e565b604051908082528060200260200182016040528015610e9157816020015b6060815260200190600190039081610e7c5790505b5090505b8251610ea090611460565b81600081518110610eb357610eb36122a3565b6020026020010181905250610ecb8360200151611460565b81600181518110610ede57610ede6122a3565b6020026020010181905250610ef68360400151611473565b81600281518110610f0957610f096122a3565b6020026020010181905250610f218360600151611460565b81600381518110610f3457610f346122a3565b6020026020010181905250610f4c8360800151611460565b81600481518110610f5f57610f5f6122a3565b6020026020010181905250610f778360a00151611460565b81600581518110610f8a57610f8a6122a3565b6020026020010181905250610fc18360c00151604051602001610fad91906122d2565b6040516020818303038152906040526114af565b81600681518110610fd457610fd46122a3565b6020026020010181905250610fec8360e0015161151e565b81600781518110610fff57610fff6122a3565b602002602001018190525061102a8361010001516fffffffffffffffffffffffffffffffff1661151e565b8160088151811061103d5761103d6122a3565b602002602001018190525061105683610120015161152c565b81600981518110611069576110696122a3565b602002602001018190525061108283610140015161152c565b81600a81518110611095576110956122a3565b60200260200101819052506110ae83610160015161152c565b81600b815181106110c1576110c16122a3565b60200260200101819052506110da8361018001516114af565b81600c815181106110ed576110ed6122a3565b6020026020010181905250611106836101a00151611460565b81600d81518110611119576111196122a3565b6020026020010181905250611168836101c00151604051602001610fad919060c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016815260080190565b81600e8151811061117b5761117b6122a3565b6020026020010181905250826101e001516000146111c0576111a1836101e0015161151e565b81600f815181106111b4576111b46122a3565b60200260200101819052505b6102008301511561021b576111d9836102000151611460565b816010815181106111ec576111ec6122a3565b602002602001018190525092915050565b6060600061120a83611544565b9050611218815160c0611678565b8160405160200161122a929190612307565b604051602081830303815290604052915050919050565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061128a577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106112b6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106112d457662386f26fc10000830492506010015b6305f5e10083106112ec576305f5e100830492506008015b612710831061130057612710830492506004015b60648310611312576064830492506002015b600a831061021b5760010192915050565b600054610100900460ff166113ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102e3565b60018055565b600054610100900460ff16611457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102e3565b6107d533610ab2565b606061021b61146e83611860565b6114af565b604051606082811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208301529061021b90603401610fad565b606080825160011480156114dd57506080836000815181106114d3576114d36122a3565b016020015160f81c105b156114e957508161021b565b6114f583516080611678565b83604051602001611507929190612307565b604051602081830303815290604052905092915050565b606061021b61146e83611948565b606061021b61146e8367ffffffffffffffff16611948565b6060815160000361156357505060408051600081526020810190915290565b6000805b83518110156115a857838181518110611582576115826122a3565b602002602001015151826115969190612290565b91506115a181612336565b9050611567565b60008267ffffffffffffffff8111156115c3576115c3611b1e565b6040519080825280601f01601f1916602001820160405280156115ed576020820181803683370190505b50600092509050602081015b855183101561166f576000868481518110611616576116166122a3565b60200260200101519050600060208201905061163483828451611aa3565b878581518110611646576116466122a3565b6020026020010151518361165a9190612290565b925050508261166890612336565b92506115f9565b50949350505050565b60608060388410156116f757604080516001808252818301909252906020820181803683370190505090506116ad838561236e565b60f81b816000815181106116c3576116c36122a3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610218565b600060015b6117068187612387565b156117295761171482612336565b91506117226101008261239b565b90506116fc565b611734826001612290565b67ffffffffffffffff81111561174c5761174c611b1e565b6040519080825280601f01601f191660200182016040528015611776576020820181803683370190505b509250611783858361236e565b61178e90603761236e565b60f81b836000815181106117a4576117a46122a3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b8181116109e9576101006117ec82846123b2565b6117f8906101006124e5565b6118029088612387565b61180c91906124f1565b60f81b838281518110611821576118216122a3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061185981612336565b90506117d8565b606060008260405160200161187791815260200190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260208084528383019092529250600091829160208201818036833701905050905060005b815181101561166f5783836118da81612336565b9450815181106118ec576118ec6122a3565b602001015160f81c60f81b828281518110611909576119096122a3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061194181612336565b90506118c6565b606060008260405160200161195f91815260200190565b604051602081830303815290604052905060005b60208110156119cc5781818151811061198e5761198e6122a3565b01602001517fff00000000000000000000000000000000000000000000000000000000000000166000036119cc576119c581612336565b9050611973565b60006119d98260206123b2565b67ffffffffffffffff8111156119f1576119f1611b1e565b6040519080825280601f01601f191660200182016040528015611a1b576020820181803683370190505b50905060005b815181101561166f578383611a3581612336565b945081518110611a4757611a476122a3565b602001015160f81c60f81b828281518110611a6457611a646122a3565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611a9c81612336565b9050611a21565b8282825b60208110611adf5781518352611abe602084612290565b9250611acb602083612290565b9150611ad86020826123b2565b9050611aa7565b905182516020929092036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199091169116179052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611b7057611b70611b1e565b60405290565b604051610220810167ffffffffffffffff81118282101715611b7057611b70611b1e565b600082601f830112611bab57600080fd5b813567ffffffffffffffff80821115611bc657611bc6611b1e565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611c0c57611c0c611b1e565b81604052838152866020858801011115611c2557600080fd5b836020870160208301376000602085830101528094505050505092915050565b801515811461088b57600080fd5b60008060408385031215611c6657600080fd5b823567ffffffffffffffff811115611c7d57600080fd5b611c8985828601611b9a565b9250506020830135611c9a81611c45565b809150509250929050565b73ffffffffffffffffffffffffffffffffffffffff8116811461088b57600080fd5b8035611cd281611ca5565b919050565b600060208284031215611ce957600080fd5b813561021881611ca5565b600080600060608486031215611d0957600080fd5b83359250602084013567ffffffffffffffff811115611d2757600080fd5b611d3386828701611b9a565b9250506040840135611d4481611c45565b809150509250925092565b60008060408385031215611d6257600080fd5b8235611d6d81611ca5565b946020939093013593505050565b600080600080600060808688031215611d9357600080fd5b853594506020860135611da581611ca5565b935060408601359250606086013567ffffffffffffffff80821115611dc957600080fd5b818801915088601f830112611ddd57600080fd5b813581811115611dec57600080fd5b896020828501011115611dfe57600080fd5b9699959850939650602001949392505050565b600060208284031215611e2357600080fd5b5035919050565b600082601f830112611e3b57600080fd5b60405161010080820182811067ffffffffffffffff82111715611e6057611e60611b1e565b60405283018185821115611e7357600080fd5b845b82811015611e8d578035825260209182019101611e75565b509195945050505050565b80356fffffffffffffffffffffffffffffffff81168114611cd257600080fd5b803567ffffffffffffffff81168114611cd257600080fd5b600060208284031215611ee257600080fd5b813567ffffffffffffffff80821115611efa57600080fd5b9083019060408286031215611f0e57600080fd5b611f16611b4d565b823582811115611f2557600080fd5b83016103008188031215611f3857600080fd5b611f40611b76565b8135815260208201356020820152611f5a60408301611cc7565b6040820152606082013560608201526080820135608082015260a082013560a0820152611f8a8860c08401611e2a565b60c08201526101c08083013560e08301526101e0611fa9818501611e98565b610100840152610200611fbd818601611eb8565b610120850152611fd06102208601611eb8565b610140850152611fe36102408601611eb8565b61016085015261026085013587811115611ffc57600080fd5b6120088c828801611b9a565b610180860152506102808501356101a08501526120286102a08601611eb8565b838501526102c0850135828501526102e085013581850152505050808352505060208301358281111561205a57600080fd5b61206687828601611b9a565b60208301525095945050505050565b60006020828403121561208757600080fd5b5051919050565b60005b838110156120a9578181015183820152602001612091565b50506000910152565b600081518084526120ca81602086016020860161208e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015283604082015282606082015260a06080820152600061213d60a08301846120b2565b979650505050505050565b60006020828403121561215a57600080fd5b815161021881611c45565b6000835161217781846020880161208e565b7f2e0000000000000000000000000000000000000000000000000000000000000090830190815283516121b181600184016020880161208e565b01600101949350505050565b60208152600061021860208301846120b2565b6000602082840312156121e257600080fd5b815161021881611ca5565b7f41523a7a65726f416464723a000000000000000000000000000000000000000081526000825161222581600c85016020870161208e565b91909101600c0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561021b5761021b612261565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008183825b60088110156122f75781518352602092830192909101906001016122d8565b5050506101008201905092915050565b6000835161231981846020880161208e565b83519083019061232d81836020880161208e565b01949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361236757612367612261565b5060010190565b60ff818116838216019081111561021b5761021b612261565b60008261239657612396612232565b500490565b808202811582820484141761021b5761021b612261565b8181038181111561021b5761021b612261565b600181815b8085111561241e57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561240457612404612261565b8085161561241157918102915b93841c93908002906123ca565b509250929050565b6000826124355750600161021b565b816124425750600061021b565b816001811461245857600281146124625761247e565b600191505061021b565b60ff84111561247357612473612261565b50506001821b61021b565b5060208310610133831016604e8410600b84101617156124a1575081810a61021b565b6124ab83836123c5565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156124dd576124dd612261565b029392505050565b60006102188383612426565b60008261250057612500612232565b50069056fea26469706673582212209e7235233ea73cd822dc3fc71cb88aeed9bb6967b10cbcf6820dcc506b275d0164736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x5072656465706c6f79455243323000000000000000000000000000000000001c", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x5052450000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000002ee000", + "0x0fbcff3234c0e4fa090508601e67e2155e18580b7c6ab4cb716e8ef2dca88184": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x55385a0c2ad17c21b4fe396be9b1f10f500e7eebad11fcd1afe36c68ee5fa4cd": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x478db7f3c43c550c1670aa0517a6d515b9e15f22ea28e4f99e8c5f8bcf58e406": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80633950935111610081578063a457c2d71161005b578063a457c2d714610194578063a9059cbb146101a7578063dd62ed3e146101ba57600080fd5b8063395093511461014357806370a082311461015657806395d89b411461018c57600080fd5b806318160ddd116100b257806318160ddd1461010f57806323b872dd14610121578063313ce5671461013457600080fd5b806306fdde03146100ce578063095ea7b3146100ec575b600080fd5b6100d6610200565b6040516100e39190610908565b60405180910390f35b6100ff6100fa36600461099d565b610292565b60405190151581526020016100e3565b6002545b6040519081526020016100e3565b6100ff61012f3660046109c7565b6102ac565b604051601281526020016100e3565b6100ff61015136600461099d565b6102d0565b610113610164366004610a03565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6100d661031c565b6100ff6101a236600461099d565b61032b565b6100ff6101b536600461099d565b610401565b6101136101c8366004610a25565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260016020908152604080832093909416825291909152205490565b60606003805461020f90610a58565b80601f016020809104026020016040519081016040528092919081815260200182805461023b90610a58565b80156102885780601f1061025d57610100808354040283529160200191610288565b820191906000526020600020905b81548152906001019060200180831161026b57829003601f168201915b5050505050905090565b6000336102a081858561040f565b60019150505b92915050565b6000336102ba8582856105c2565b6102c5858585610699565b506001949350505050565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906102a09082908690610317908790610aab565b61040f565b60606004805461020f90610a58565b33600081815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190838110156103f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6102c5828686840361040f565b6000336102a0818585610699565b73ffffffffffffffffffffffffffffffffffffffff83166104b1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016103eb565b73ffffffffffffffffffffffffffffffffffffffff8216610554576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016103eb565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146106935781811015610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016103eb565b610693848484840361040f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff831661073c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016103eb565b73ffffffffffffffffffffffffffffffffffffffff82166107df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016103eb565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015610895576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016103eb565b73ffffffffffffffffffffffffffffffffffffffff848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610693565b600060208083528351808285015260005b8181101561093557858101830151858201604001528201610919565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461099857600080fd5b919050565b600080604083850312156109b057600080fd5b6109b983610974565b946020939093013593505050565b6000806000606084860312156109dc57600080fd5b6109e584610974565b92506109f360208501610974565b9150604084013590509250925092565b600060208284031215610a1557600080fd5b610a1e82610974565b9392505050565b60008060408385031215610a3857600080fd5b610a4183610974565b9150610a4f60208401610974565b90509250929050565b600181811c90821680610a6c57607f821691505b602082108103610aa5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b808201808211156102a6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea264697066735822122066fafca01d431074160bbb4b6fc540b95eb31fa8c4479f896ac206b98463328464736f6c63430008120033", + "balance": "0x0" + } + } +} diff --git a/crates/primitives/res/genesis/taiko/eldfell.json b/crates/primitives/res/genesis/taiko/eldfell.json new file mode 100644 index 000000000000..22e0a52213ab --- /dev/null +++ b/crates/primitives/res/genesis/taiko/eldfell.json @@ -0,0 +1,148 @@ +{ + "0x19B4F9C381C7927FE33D853e48b560141A380C44": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x88f66d67C0e643A541822cc326708530a827EC8E": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x2E610A0D8E30D6df2877B9c3EC3daDb885364800": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0xd56fbBb9C88938a61e9CA71339Abd5f84dF131Cf": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063a54274621461003a575b600080fd5b61004d61004836600461173e565b610061565b604051901515815260200160405180910390f35b600080806100718486018661188e565b6040516bffffffffffffffffffffffff1960608c901b166020820152919350915060009081906100b490603401604051602081830303815290604052858d610184565b915091508161010a5760405162461bcd60e51b815260206004820152601960248201527f4c54503a696e76616c6964206163636f756e742070726f6f660000000000000060448201526064015b60405180910390fd5b6000610115826101ad565b9050600061013c8260028151811061012f5761012f6118f2565b60200260200101516101e6565b90506101738b60405160200161015491815260200190565b60405160208183030381529060405261016c8c6102e9565b87846102fc565b9d9c50505050505050505050505050565b60006060600061019386610316565b90506101a0818686610348565b9250925050935093915050565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906101e090610423565b92915050565b600060218260000151111561023d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b600080600061024b8561060f565b91945092509050600081600181111561026657610266611908565b146102b35760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b60008386602001516102c59190611934565b805190915060208410156102df5760208490036101000a90045b9695505050505050565b60606101e06102f783610959565b610a8d565b60008061030886610316565b90506102df81868686610afc565b6060818051906020012060405160200161033291815260200190565b6040516020818303038152906040529050919050565b60006060600061035785610b39565b90506000806000610369848a89610c32565b8151929550909350915015808061037d5750815b6103c95760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610101565b6000816103e55760405180602001604052806000815250610411565b610411866103f4600188611947565b81518110610404576104046118f2565b6020026020010151611052565b919b919a509098505050505050505050565b60606000806104318461060f565b9193509091506001905081600181111561044d5761044d611908565b1461049a5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610101565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816104b35790505090506000835b8651811015610604576020821061054c5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b6064820152608401610101565b6000806105896040518060400160405280858c6000015161056d9190611947565b8152602001858c602001516105829190611934565b905261060f565b5091509150604051806040016040528083836105a59190611934565b8152602001848b602001516105ba9190611934565b8152508585815181106105cf576105cf6118f2565b60209081029190910101526105e5600185611934565b93506105f18183611934565b6105fb9084611934565b925050506104e0565b508152949350505050565b6000806000808460000151116106675760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610101565b6020840151805160001a607f811161068c576000600160009450945094505050610952565b60b781116107085760006106a1608083611947565b9050808760000151116106f65760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610101565b60019550935060009250610952915050565b60bf81116107f757600061071d60b783611947565b9050808760000151116107725760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610101565b600183015160208290036101000a900461078c8183611934565b8851116107db5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610101565b6107e6826001611934565b965094506000935061095292505050565b60f7811161087257600061080c60c083611947565b9050808760000151116108615760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610101565b600195509350849250610952915050565b600061087f60f783611947565b9050808760000151116108d45760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610101565b600183015160208290036101000a90046108ee8183611934565b8851116109365760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b6044820152606401610101565b610941826001611934565b965094506001935061095292505050565b9193909250565b606060008260405160200161097091815260200190565b604051602081830303815290604052905060005b60208110156109c55781818151811061099f5761099f6118f2565b01602001516001600160f81b0319166000036109c5576109be8161195a565b9050610984565b60006109d2826020611947565b67ffffffffffffffff8111156109ea576109ea6117eb565b6040519080825280601f01601f191660200182016040528015610a14576020820181803683370190505b50905060005b8151811015610a84578383610a2e8161195a565b945081518110610a4057610a406118f2565b602001015160f81c60f81b828281518110610a5d57610a5d6118f2565b60200101906001600160f81b031916908160001a905350610a7d8161195a565b9050610a1a565b50949350505050565b60608082516001148015610abb5750608083600081518110610ab157610ab16118f2565b016020015160f81c105b15610ac75750816101e0565b610ad383516080611079565b83604051602001610ae59291906119a3565b604051602081830303815290604052905092915050565b6000806000610b0c878686610348565b91509150818015610b2e57508051602080830191909120875191880191909120145b979650505050505050565b60606000610b46836101ad565b90506000815167ffffffffffffffff811115610b6457610b646117eb565b604051908082528060200260200182016040528015610ba957816020015b6040805180820190915260608082526020820152815260200190600190039081610b825790505b50905060005b8251811015610c2a576000610bdc848381518110610bcf57610bcf6118f2565b6020026020010151611223565b90506040518060400160405280610bf2836101ad565b815260200182815250838381518110610c0d57610c0d6118f2565b60200260200101819052505080610c239061195a565b9050610baf565b509392505050565b600060606000806000610c44876112b3565b90506000869050600080610c6b604051806040016040528060608152602001606081525090565b60005b8c5181101561102a578c8181518110610c8957610c896118f2565b602002602001015191508284610c9f9190611934565b9350610cac600188611934565b965083600003610d09578482602001518051906020012014610d045760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b6044820152606401610101565b610dcb565b602082602001515110610d70578482602001518051906020012014610d045760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610101565b84610d7e83602001516113ec565b14610dcb5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610101565b610dd7601060016119c0565b60ff1682600001515103610e45578551841461102a576000868581518110610e0157610e016118f2565b01602001518351805160f89290921c925060009183908110610e2557610e256118f2565b60200260200101519050610e3881611414565b965060019450505061101a565b81515160011901610fd2576000610e5b8361144a565b9050600081600081518110610e7257610e726118f2565b016020015160f81c90506000610e896002836119ef565b610e94906002611a11565b90506000610ea5848360ff1661146e565b90506000610eb38b8a61146e565b90506000610ec183836114a4565b905060ff851660021480610ed8575060ff85166003145b15610f1257808351148015610eed5750808251145b15610eff57610efc818b611934565b99505b50600160ff1b995061102a945050505050565b60ff85161580610f25575060ff85166001145b15610f7b5782518114610f455750600160ff1b995061102a945050505050565b610f6c8860000151600181518110610f5f57610f5f6118f2565b6020026020010151611414565b9a50975061101a945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b6064820152608401610101565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610101565b6110238161195a565b9050610c6e565b50600160ff1b84148661103d878661146e565b909e909d50909b509950505050505050505050565b805180516060916101e09161106990600190611947565b81518110610bcf57610bcf6118f2565b60608060388410156110e057604080516001808252818301909252906020820181803683370190505090506110ae83856119c0565b60f81b816000815181106110c4576110c46118f2565b60200101906001600160f81b031916908160001a90535061121c565b600060015b6110ef8187611a2a565b15611112576110fd8261195a565b915061110b61010082611a3e565b90506110e5565b61111d826001611934565b67ffffffffffffffff811115611135576111356117eb565b6040519080825280601f01601f19166020018201604052801561115f576020820181803683370190505b50925061116c85836119c0565b6111779060376119c0565b60f81b8360008151811061118d5761118d6118f2565b60200101906001600160f81b031916908160001a905350600190505b818111611219576101006111bd8284611947565b6111c990610100611b39565b6111d39088611a2a565b6111dd9190611b45565b60f81b8382815181106111f2576111f26118f2565b60200101906001600160f81b031916908160001a9053506112128161195a565b90506111a9565b50505b9392505050565b606060008060006112338561060f565b91945092509050600081600181111561124e5761124e611908565b1461129b5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610101565b6112aa8560200151848461151e565b95945050505050565b60606000825160026112c59190611a3e565b67ffffffffffffffff8111156112dd576112dd6117eb565b6040519080825280601f01601f191660200182016040528015611307576020820181803683370190505b50905060005b83518110156113e557600484828151811061132a5761132a6118f2565b01602001516001600160f81b031916901c82611347836002611a3e565b81518110611357576113576118f2565b60200101906001600160f81b031916908160001a9053506010848281518110611382576113826118f2565b0160200151611394919060f81c6119ef565b60f81b826113a3836002611a3e565b6113ae906001611934565b815181106113be576113be6118f2565b60200101906001600160f81b031916908160001a9053506113de8161195a565b905061130d565b5092915050565b600060208251101561140057506020015190565b818060200190518101906101e09190611b59565b600060606020836000015110156114355761142e836115c7565b9050611441565b61143e83611223565b90505b61121c816113ec565b60606101e06114698360000151600081518110610bcf57610bcf6118f2565b6112b3565b60608251821061148d57506040805160208101909152600081526101e0565b61121c838384865161149f9190611947565b6115d2565b6000805b8084511180156114b85750808351115b801561150957508281815181106114d1576114d16118f2565b602001015160f81c60f81b6001600160f81b0319168482815181106114f8576114f86118f2565b01602001516001600160f81b031916145b1561121c576115178161195a565b90506114a8565b606060008267ffffffffffffffff81111561153b5761153b6117eb565b6040519080825280601f01601f191660200182016040528015611565576020820181803683370190505b509050805160000361157857905061121c565b8484016020820160005b8581101561159a578281015182820152602001611582565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606101e082611728565b6060816115e081601f611934565b101561161f5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610101565b8261162a8382611934565b10156116695760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610101565b6116738284611934565b845110156116b75760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610101565b6060821580156116d65760405191506000825260208201604052610a84565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561170f5780518352602092830192016116f7565b5050858452601f01601f19166040525050949350505050565b60606101e082602001516000846000015161151e565b60008060008060008060a0878903121561175757600080fd5b8635955060208701356001600160a01b038116811461177557600080fd5b94506040870135935060608701359250608087013567ffffffffffffffff808211156117a057600080fd5b818901915089601f8301126117b457600080fd5b8135818111156117c357600080fd5b8a60208285010111156117d557600080fd5b6020830194508093505050509295509295509295565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261181257600080fd5b813567ffffffffffffffff8082111561182d5761182d6117eb565b604051601f8301601f19908116603f01168101908282118183101715611855576118556117eb565b8160405283815286602085880101111561186e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156118a157600080fd5b823567ffffffffffffffff808211156118b957600080fd5b6118c586838701611801565b935060208501359150808211156118db57600080fd5b506118e885828601611801565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156101e0576101e061191e565b818103818111156101e0576101e061191e565b60006001820161196c5761196c61191e565b5060010190565b6000815160005b81811015611994576020818501810151868301520161197a565b50600093019283525090919050565b60006119b86119b28386611973565b84611973565b949350505050565b60ff81811683821601908111156101e0576101e061191e565b634e487b7160e01b600052601260045260246000fd5b600060ff831680611a0257611a026119d9565b8060ff84160691505092915050565b60ff82811682821603908111156101e0576101e061191e565b600082611a3957611a396119d9565b500490565b80820281158282048414176101e0576101e061191e565b600181815b80851115611a90578160001904821115611a7657611a7661191e565b80851615611a8357918102915b93841c9390800290611a5a565b509250929050565b600082611aa7575060016101e0565b81611ab4575060006101e0565b8160018114611aca5760028114611ad457611af0565b60019150506101e0565b60ff841115611ae557611ae561191e565b50506001821b6101e0565b5060208310610133831016604e8410600b8410161715611b13575081810a6101e0565b611b1d8383611a55565b8060001904821115611b3157611b3161191e565b029392505050565b600061121c8383611a98565b600082611b5457611b546119d9565b500690565b600060208284031215611b6b57600080fd5b505191905056fea26469706673582212200ce0b855958491d449296239ab0a499d51105fc25c306cacdd66eed473ebcf4164736f6c63430008140033", + "balance": "0x0" + }, + "0x3D242344128D1db694d798CF0Ad3dC778Aa77347": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209ad4b2c866dbe1263f15c72a9d9c6857d19b471dc0ffa8cba69fdd5d4cb102b864736f6c63430008140033", + "balance": "0x0" + }, + "0x9c7145F3B1EaB768364a9ff72318B9D7AeafB156": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220580d1b027125bdf07c98c62cba13a64e78c2192e8c0f84c6cef28804c6341ae864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000006": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063656b06a414610067578063715018a6146100b75780638da5cb5b146100c1578063decd8e39146100d2578063e1c7392a146100e5578063f2fde38b146100ed575b600080fd5b61009b610075366004610466565b60009182526065602090815260408084209284529190529020546001600160a01b031690565b6040516001600160a01b03909116815260200160405180910390f35b6100bf610100565b005b6033546001600160a01b031661009b565b6100bf6100e03660046104a4565b610114565b6100bf6101d4565b6100bf6100fb3660046104d9565b6102ea565b610108610360565b61011260006103ba565b565b61011c610360565b6001600160a01b0381163b15801561013c57506001600160a01b03811633145b1561015a57604051633baa901360e21b815260040160405180910390fd5b600083815260656020908152604080832085845282529182902080546001600160a01b038581166001600160a01b0319831681179093558451928352169181018290529091849186917fe41a6e8584d6e19a0dfc5f9331be4ebe61b5f025d45da164c9ca6ee9b837cea9910160405180910390a350505050565b600054610100900460ff16158080156101f45750600054600160ff909116105b8061020e5750303b15801561020e575060005460ff166001145b6102765760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610299576000805461ff0019166101001790555b6102a161040c565b80156102e7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6102f2610360565b6001600160a01b0381166103575760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161026d565b6102e7816103ba565b6033546001600160a01b031633146101125760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161026d565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166104335760405162461bcd60e51b815260040161026d906104fb565b610112600054610100900460ff1661045d5760405162461bcd60e51b815260040161026d906104fb565b610112336103ba565b6000806040838503121561047957600080fd5b50508035926020909101359150565b80356001600160a01b038116811461049f57600080fd5b919050565b6000806000606084860312156104b957600080fd5b83359250602084013591506104d060408501610488565b90509250925092565b6000602082840312156104eb57600080fd5b6104f482610488565b9392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d1b8f83f17d2971223f345076e2c8b1982272c271a0ce36e6b3541cd15bd267964736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0xa2985d6ec808cf8e4351b74656a3169ef9f5ae53c52585f208ff047513b6b22f": "0x0000000000000000000000001000777700000000000000000000000000000001", + "0xab0df58d0c513f542551f7cf89c05da0610fe5e3092a4b838d7d8529d492ecf0": "0x0000000000000000000000001000777700000000000000000000000000000004", + "0x56e7eae2fe6d26fea53c92b4b72c70c097b4c6cb841f2560628bc18c65113ede": "0x0000000000000000000000001000777700000000000000000000000000000002", + "0x7b5ab0263db4edc4cd0bef661062356260cf371a7955689e8739ce5188c0e9fe": "0x0000000000000000000000001000777700000000000000000000000000000003", + "0x62856d7e6e6c45fe7cca6dc9dc0aff508e9e029ca538a20a7d2086827adddfda": "0x0000000000000000000000001000777700000000000000000000000000000007", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000006" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000001": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106101375760003560e01c80639ee512f2116100b8578063c7b969081161007c578063c7b96908146102f3578063da69d3db1461030d578063dac5df7814610320578063ee82ac5e14610329578063f2fde38b1461033c578063f535bd561461034f57600080fd5b80639ee512f21461028e578063a86f9d9e146102a7578063b8914ce4146102ba578063bacb386d146102cd578063c20ebea5146102e057600080fd5b8063591aad8a116100ff578063591aad8a1461021d5780635c82e9c21461024f5780636c6563f614610262578063715018a6146102755780638da5cb5b1461027d57600080fd5b80630652b57a1461013c57806310da3738146101515780633ab76e9f1461018b5780634e755573146101b0578063539b8ade146101f2575b600080fd5b61014f61014a3660046116de565b610369565b005b6101787f92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce3881565b6040519081526020015b60405180910390f35b6097546001600160a01b03165b6040516001600160a01b039091168152602001610182565b6101b86103ec565b6040805182516001600160801b031681526020808401516001600160401b0316908201529181015163ffffffff1690820152606001610182565b60cd54610205906001600160401b031681565b6040516001600160401b039091168152602001610182565b61023061022b3660046116fb565b61044f565b6040805160ff9094168452602084019290925290820152606001610182565b61014f61025d366004611731565b61068a565b610198610270366004611782565b610a46565b61014f610a5d565b6065546001600160a01b0316610198565b61019871777735367b36bc9b61c50022d9d0700db4ec81565b6101986102b53660046117b7565b610a71565b6101786102c83660046117e3565b610a87565b6101786102db3660046117e3565b610ac3565b6101786102ee366004611810565b610afc565b60cd5461020590600160401b90046001600160401b031681565b61014f61031b366004611861565b610b20565b61017860cb5481565b6101786103373660046117e3565b610d8b565b61014f61034a3660046116de565b610dd8565b60cd5461020590600160801b90046001600160401b031681565b610371610e51565b6001600160a01b03811661039857604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b6040805160608101825260008082526020820181905291810191909152506040805160608101825260cc546001600160801b0381168252600160801b81046001600160401b03166020830152600160c01b900463ffffffff169181019190915290565b60008060008360ff1660011415801561046c57508360ff16600214155b1561048a5760405163bcd2d90d60e01b815260040160405180910390fd5b8360ff166001146104bb577fc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee56104dd565b7f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817985b915060008460ff16600114610512577fad77eceea844778cb4376153fc8f06f12f1695df4585bf75bfb17ec19ce90818610534565b7fb4a95509ce05fe8d45987859a067780d16a367c0e2cacf79cd301b93fb7179405b905060008560ff16600114610569577f71620584f61c57e688bbd3fd7a39a036e588d962c4c830f3dacbc15c917e02f261058b565b7f45b59254b0320fd853f3f38ac574999e91bd75fd5e6cab9c22c5e71fc6d276e45b82880192831001905060ff86166001036105c5576105be8282600170014551231950b75fc4402da1732fc9bebe19610eab565b9250610634565b61060d7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16106088484600170014551231950b75fc4402da1732fc9bebe19610eab565b610efa565b90925090506106318282600170014551231950b75fc4402da1732fc9bebe19610eab565b92505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610681576106788370014551231950b75fc4402da1732fc9bebe196118bd565b92506001851894505b50509250925092565b600054610100900460ff16158080156106aa5750600054600160ff909116105b806106c45750303b1580156106c4575060005460ff166001145b61072c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561074f576000805461ff0019166101001790555b600146111580610763575063ffffffff4610155b15610781576040516306cffa2760e01b815260040160405180910390fd5b60014311156107a357604051635a0f9e4160e11b815260040160405180910390fd5b6107b360408301602084016118d0565b63ffffffff16156109a2576107cb60208301836118eb565b6001600160401b031615806107f657506107eb60608301604084016118eb565b6001600160401b0316155b80610817575061080c60808301606084016118eb565b6001600160401b0316155b80610838575061082d60a08301608084016118eb565b6001600160401b0316155b1561085657604051639cc448b560e01b815260040160405180910390fd5b60008061089e61086c60608601604087016118eb565b61087960208701876118eb565b61088960808801606089016118eb565b61089960a0890160808a016118eb565b610f19565b91509150816001600160801b0316600014806108ca57506001600160401b036001600160801b03831610155b806108dc57506001600160801b038116155b156108fa57604051639cc448b560e01b815260040160405180910390fd5b60cc80546001600160401b038416600160801b026001600160c01b03199091166001600160801b0384161717905561093860408501602086016118d0565b60cc805463ffffffff92909216600160c01b0263ffffffff60c01b19909216919091179055600261096f60608601604087016118eb565b610979919061191c565b60cd60106101000a8154816001600160401b0302191690836001600160401b0316021790555050505b60cd805467ffffffffffffffff1916426001600160401b03161790556109c783611018565b6109d043611031565b5060cb5543156109fb5760006109e76001436118bd565b600081815260c96020526040902090409055505b8015610a41576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610a538484846110c4565b90505b9392505050565b610a65610e51565b610a6f6000611178565b565b6000610a7e4684846110c4565b90505b92915050565b6000808215610a965782610aaa565b60cd54600160401b90046001600160401b03165b600090815260ca60205260409020600101549392505050565b6000808215610ad25782610ae6565b60cd54600160401b90046001600160401b03165b600090815260ca60205260409020549392505050565b6000610b17610b096103ec565b8563ffffffff1685856111ca565b50949350505050565b3371777735367b36bc9b61c50022d9d0700db4ec14610b5257604051636494e9f760e01b815260040160405180910390fd5b6000610b5f6001436118bd565b90508040600080610b6f84611031565b915091508160cb5414610ba35760cb54604051636340d9fb60e11b8152600481019190915260248101839052604401610723565b60cb819055600084815260c96020908152604080832086905560cd80546fffffffffffffffff00000000000000001916600160401b6001600160401b038c1690810291909117909155815180830183528c81528084018c815282865260ca8552948390209051815593516001949094019390935580518b81529182018a90527f7528bbd1cef0e5d13408706892a51ee8ef82bbf33d4ec0c37216f8beba71205b910160405180910390a2600080610c586103ec565b9050806040015163ffffffff16600014610cbd5760cd54610c8f908290610c88906001600160401b0316426118bd565b458a6111ca565b60cd80546001600160401b03909216600160801b0267ffffffffffffffff60801b1990921691909117905591505b814814610cf057604051634083acad60e01b81526001600160401b03808416600483015248166024820152604401610723565b60cd80546001600160401b0342811667ffffffffffffffff19909216821790925560408051438416815292851660208401524563ffffffff908116848301526060840192909252608083018890524460a08401524160c08401524690911660e0830152517ff5e89a4a67ffebdbc23df567479d3096c1dba4169c6bbf20ffc6b24d7f6e6e70918190036101000190a150505050505050505050565b6000438210610d9c57506000919050565b4382108015610db65750610db2610100436118bd565b8210155b15610dc057504090565b50600090815260c9602052604090205490565b919050565b610de0610e51565b6001600160a01b038116610e455760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610723565b610e4e81611178565b50565b6065546001600160a01b03163314610a6f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610723565b600060405160408152602080820152602060408201528460608201528560808201528360a08201528260c082015260208160e08360056107d05a03fa610ef057600080fd5b5195945050505050565b6000806000198385098385029250828110838203039150509250929050565b600080856001600160401b0316600003610f3557610f35611942565b6000610f4260028861191c565b9050610f606001600160401b038816680755bf798b4a1bf1e4611958565b9250610f7f610f7a84886001600160401b03168489611276565b611335565b91506000610f8f84848489611276565b90506000610fa9858585610fa48b6002611972565b611276565b9050600082610fba8361271061199d565b610fc491906119b4565b9050806001600160401b0316876001600160401b03161461100b57604051631530943760e11b81526001600160401b03808916600483015282166024820152604401610723565b5050505094509492505050565b6110206113a2565b6110286113d1565b610e4e81611400565b60008061103c6116a9565b60005b60ff811080156110525750806001018510155b15611084576000198186030180408360ff83066101008110611076576110766119c8565b60200201525060010161103f565b5046611fe0820152612000812092508340816110a160ff876119de565b61010081106110b2576110b26119c8565b60200201526120009020919391925050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015611115573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113991906119f2565b90508115801561115057506001600160a01b038116155b15610a5657604051631467050360e21b81526004810185905260248101849052604401610723565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080806202bf2063ffffffff8516116111e55760006111ec565b6202bf2084035b60cd5460408901519192506001600160401b03600160801b909104811663ffffffff8085169190910192811689029161123691839061122f908690839061144916565b039061145f565b935050505061125e86602001516001600160401b03168760000151838763ffffffff16611276565b91508160000361126d57600191505b94509492505050565b60006001600160801b0385161580159061129857506001600160801b03841615155b6112a4576112a4611942565b60006001600160401b038316156112bb57826112be565b60015b905060006112d5856001600160401b031688611474565b905060006112f56112e68488611a0f565b6001600160401b031689611474565b90506001600160801b0387166001600160401b03841661131584846118bd565b61131f91906119b4565b61132991906119b4565b98975050505050505050565b60006001600160801b0382111561139e5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610723565b5090565b600054610100900460ff166113c95760405162461bcd60e51b815260040161072390611a36565b610a6f6114c6565b600054610100900460ff166113f85760405162461bcd60e51b815260040161072390611a36565b610a6f6114f3565b6001600160a01b03811661142757604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60008183116114585781610a7e565b5090919050565b600081831161146e5782610a7e565b50919050565b60008061148a6001600160801b0384168561199d565b9050680755bf798b4a1bf1e481106114b55760405163576ff4f160e01b815260040160405180910390fd5b6114be81611523565b949350505050565b600054610100900460ff166114ed5760405162461bcd60e51b815260040161072390611a36565b60018055565b600054610100900460ff1661151a5760405162461bcd60e51b815260040161072390611a36565b610a6f33611178565b6000680248ce36a70cb26b3e19821361153e57506000919050565b680755bf798b4a1bf1e5821261156757604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b6d2c06887d92262d378b9593af35346c09791803c2923d5d9721c3da80929091056001605f1b0190921d6bb17217f7d1cf79abc9e3b39881029095039081018102606090811d6d019dd9374d4315c8464a395fc09881016c1bff318b126baa436ea9aeaffd19840102821d93840193016d29c9ad45cc0beb0a2ff097a7bab40192909202821d6dcf3c27b2e487711b467e90f19320016c22fcd1cffa6fa000f6e27eeca082018202831d6d022f98fbc368092c79210d196fa0018202831d6d13aaae3ba38de06adc25ebfacc0901820290921d6d624dcbeb5e25df590e409325888a01026d360d7aeea093263ec6495851bd9760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b604051806120000160405280610100906020820280368337509192915050565b6001600160a01b0381168114610e4e57600080fd5b6000602082840312156116f057600080fd5b8135610a56816116c9565b6000806040838503121561170e57600080fd5b82359150602083013560ff8116811461172657600080fd5b809150509250929050565b60008082840360c081121561174557600080fd5b8335611750816116c9565b925060a0601f198201121561176457600080fd5b506020830190509250929050565b80358015158114610dd357600080fd5b60008060006060848603121561179757600080fd5b83359250602084013591506117ae60408501611772565b90509250925092565b600080604083850312156117ca57600080fd5b823591506117da60208401611772565b90509250929050565b6000602082840312156117f557600080fd5b5035919050565b803563ffffffff81168114610dd357600080fd5b60008060006060848603121561182557600080fd5b61182e846117fc565b925061183c602085016117fc565b91506117ae604085016117fc565b80356001600160401b0381168114610dd357600080fd5b6000806000806080858703121561187757600080fd5b843593506020850135925061188e6040860161184a565b915061189c606086016117fc565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a8157610a816118a7565b6000602082840312156118e257600080fd5b610a7e826117fc565b6000602082840312156118fd57600080fd5b610a7e8261184a565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038084168061193657611936611906565b92169190910492915050565b634e487b7160e01b600052600160045260246000fd5b60006001600160801b038084168061193657611936611906565b6001600160401b03818116838216028082169190828114611995576119956118a7565b505092915050565b8082028115828204841417610a8157610a816118a7565b6000826119c3576119c3611906565b500490565b634e487b7160e01b600052603260045260246000fd5b6000826119ed576119ed611906565b500690565b600060208284031215611a0457600080fd5b8151610a56816116c9565b6001600160401b03818116838216019080821115611a2f57611a2f6118a7565b5092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220bd7f7091e6a697697091252fac98ba75d8b5eb2366b8463a9d05f995c921619164736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000001": { + "storage": { + "0x00000000000000000000000000000000000000000000000000000000000000cb": "0xd02f27dfd81ca98ddc593afdc449ac14b6f636ece56d0f41f5aa383eaa73d02b", + "0x00000000000000000000000000000000000000000000000000000000000000cc": "0x0000000000bebc200000000058b8ef1c0000000485b9d2e799564d28c46075dd", + "0x00000000000000000000000000000000000000000000000000000000000000cd": "0x00000000000000000000000a9507f68000000000000000000000000064b16457", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000001" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000004": { + "storage": {}, + "code": "0x60806040526004361061012e5760003560e01c8063715018a6116100ab578063bac443e21161006f578063bac443e21461041b578063ce70f39b1461043b578063d0496d6a1461045b578063f2fde38b146104ca578063f9803919146104ea578063fee99b221461050a57600080fd5b8063715018a6146103955780638da5cb5b146103aa57806396e17852146103c8578063a4444efd146103db578063a86f9d9e146103fb57600080fd5b8063540be6a3116100f2578063540be6a3146102e75780635817b0c3146103075780635d0bd98614610335578063606b5b74146103555780636c6563f61461037557600080fd5b80630652b57a1461020357806319ab453c14610223578063343b643c146102435780633ab76e9f146102885780635075a9d4146102ba57600080fd5b366101fe5761014c6a1d1bdad95b97dd985d5b1d60aa1b600161052a565b6001600160a01b0316336001600160a01b03161415801561019757506101816a195d1a195c97dd985d5b1d60aa1b600161052a565b6001600160a01b0316336001600160a01b031614155b80156101c757506101b1647461696b6f60d81b600161052a565b6001600160a01b0316336001600160a01b031614155b80156101de57506065546001600160a01b03163314155b156101fc576040516345dd044560e11b815260040160405180910390fd5b005b600080fd5b34801561020f57600080fd5b506101fc61021e366004612b75565b610540565b34801561022f57600080fd5b506101fc61023e366004612b75565b6105c3565b34801561024f57600080fd5b5061027361025e366004612b92565b600090815260cd602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561029457600080fd5b506097546001600160a01b03165b6040516001600160a01b03909116815260200161027f565b3480156102c657600080fd5b506102da6102d5366004612b92565b6106db565b60405161027f9190612be3565b3480156102f357600080fd5b50610273610302366004612b92565b6106e6565b34801561031357600080fd5b50610327610322366004612c0a565b6106f2565b60405190815260200161027f565b34801561034157600080fd5b50610273610350366004612b92565b610705565b34801561036157600080fd5b50610327610370366004612b92565b610718565b34801561038157600080fd5b506102a2610390366004612c4c565b610723565b3480156103a157600080fd5b506101fc61073a565b3480156103b657600080fd5b506065546001600160a01b03166102a2565b6103276103d6366004612c0a565b61074e565b3480156103e757600080fd5b506102736103f6366004612ccd565b61077c565b34801561040757600080fd5b506102a2610416366004612d1f565b61052a565b34801561042757600080fd5b506101fc610436366004612d4f565b610794565b34801561044757600080fd5b50610273610456366004612ccd565b6107b8565b34801561046757600080fd5b50604080516060808201835260008083526020808401829052928401528251808201845260ca5480825260cb546001600160a01b0390811683860190815260cc54938701938452865192835251169381019390935251928201929092520161027f565b3480156104d657600080fd5b506101fc6104e5366004612b75565b6107c7565b3480156104f657600080fd5b506101fc610505366004612db7565b610840565b34801561051657600080fd5b506101fc610525366004612d4f565b61085e565b6000610537468484610874565b90505b92915050565b610548610928565b6001600160a01b03811661056f57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff16158080156105e35750600054600160ff909116105b806105fd5750303b1580156105fd575060005460ff166001145b6106655760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610688576000805461ff0019166101001790555b61069182610982565b80156106d7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061053a8261099b565b600061053a30836109c6565b600061053a61070083612f0d565b610aa7565b60006107113083610ad7565b5092915050565b600061053a82610b60565b6000610730848484610874565b90505b9392505050565b610742610928565b61074c6000610b9b565b565b6000610758610bed565b61076c60c93061076785612f0d565b610c46565b905061077760018055565b919050565b600061078b3086868686610f27565b95945050505050565b61079c610bed565b6107aa60c93085858561108a565b6107b360018055565b505050565b600061078b308686868661137b565b6107cf610928565b6001600160a01b0381166108345760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161065c565b61083d81610b9b565b50565b610848610bed565b61085560c9308484611600565b6106d760018055565b610866610bed565b6107aa60c930858585611838565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156108c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e9919061300e565b90508115801561090057506001600160a01b038116155b1561073357604051631467050360e21b8152600481018590526024810184905260440161065c565b6065546001600160a01b0316331461074c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161065c565b61098a611d37565b610992611d66565b61083d81611d95565b6000806109a783610b60565b80549091508060038111156109be576109be612bab565b949350505050565b604051635437cecf60e11b81526000906001600160a01b0384169063a86f9d9e906109f590849060040161302b565b602060405180830381865afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a36919061300e565b604051631933b5e360e11b8152306004820152602481018490526001600160a01b0391909116906332676bc690604401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610537919061304d565b600081604051602001610aba91906130ba565b604051602081830303815290604052805190602001209050919050565b600080836001600160a01b0316636c6563f68460016040518363ffffffff1660e01b8152600401610b099291906131b4565b602060405180830381865afa158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a919061300e565b6001600160a01b03811615159590945092505050565b60006040518060400160405280600e81526020016d4d4553534147455f53544154555360901b81525082604051602001610aba9291906131d3565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600260015403610c3f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161065c565b6002600155565b60808101516000906001600160a01b0316610c74576040516301b1868360e71b815260040160405180910390fd5b600080610c85858560600151610ad7565b91509150811580610c995750468460600151145b15610cb75760405163e822b48d60e01b815260040160405180910390fd5b60a08401516001600160a01b03161580610ce65750806001600160a01b03168460a001516001600160a01b0316145b15610d045760405163b9ad6a0f60e01b815260040160405180910390fd5b60008461012001518561010001518660e00151610d21919061320b565b610d2b919061320b565b9050348114610d4d57604051632609a19760e21b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0388169063a86f9d9e90610d7d9060019060040161321e565b602060405180830381865afa158015610d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbe919061300e565b9050610dd36001600160a01b03821683611dde565b8754886000610de18361323d565b909155508652336020870152466040870152610dfc86610aa7565b604051635437cecf60e11b81529095506001600160a01b0388169063a86f9d9e90610e2c9060009060040161302b565b602060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d919061300e565b6001600160a01b03166366ca2bc0866040518263ffffffff1660e01b8152600401610e9a91815260200190565b6020604051808303816000875af1158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd9190613256565b50847f47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f387604051610f0e91906130ba565b60405180910390a2505050509392505050565b60018055565b600080866001600160a01b0316636c6563f68660006040518363ffffffff1660e01b8152600401610f599291906131b4565b602060405180830381865afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a919061300e565b604051635437cecf60e11b81529091506001600160a01b0388169063a86f9d9e90610fca9060009060040161302b565b602060405180830381865afa158015610fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100b919061300e565b6001600160a01b0316635221f61386838988886040518663ffffffff1660e01b815260040161103e95949392919061326f565b602060405180830381865afa15801561105b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107f919061304d565b979650505050505050565b600061109c60a0850160808601612b75565b6001600160a01b0316036110c3576040516301b1868360e71b815260040160405180910390fd5b468360400135146110e75760405163e822b48d60e01b815260040160405180910390fd5b60006110f561070085612f0d565b600081815260048801602052604090205490915060ff16151560010361112e5760405163afde133560e01b815260040160405180910390fd5b61113f85828660600135868661137b565b61115c5760405163498b0b1d60e01b815260040160405180910390fd5b60008181526004870160205260408120805460ff1916600117905561118a61010086013560e087013561320b565b9050801561131f57604051635437cecf60e11b81526000906001600160a01b0388169063a86f9d9e906111c29060019060040161321e565b602060405180830381865afa1580156111df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611203919061300e565b90506001600160a01b03811615611298576001600160a01b03811663ba0bbd9561123360a0890160808a01612b75565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401600060405180830381600087803b15801561127b57600080fd5b505af115801561128f573d6000803e3d6000fd5b5050505061131d565b60006112aa60a0880160808901612b75565b6001600160a01b03168360405160006040518083038185875af1925050503d80600081146112f4576040519150601f19603f3d011682016040523d82523d6000602084013e6112f9565b606091505b505090508061131b5760405163f6664cf160e01b815260040160405180910390fd5b505b505b817fea00c741e39d1d9ab1c6703152d71f9da09a782ed4ae128414730dadbb9bd84761135160a0880160808901612b75565b604080516001600160a01b039092168252602082018590520160405180910390a250505050505050565b600046840361139d5760405163e822b48d60e01b815260040160405180910390fd5b60008590036113bf5760405163a6407c9360e01b815260040160405180910390fd5b60006113cd83850185613359565b604051635437cecf60e11b8152647461696b6f60d81b60048201526000602482018190529192506001600160a01b0389169063a86f9d9e90604401602060405180830381865afa158015611425573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611449919061300e565b8251610100015160405163bacb386d60e01b81526001600160801b0390911660048201526001600160a01b03919091169063bacb386d90602401602060405180830381865afa1580156114a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c49190613256565b90508015806114dd575081516114d990611e94565b8114155b156114ed5760009250505061078b565b815160600151604051633632b1fb60e11b815273d56fbBb9C88938a61e9CA71339Abd5f84dF131Cf9163a5427462916001600160a01b038c1690636c6563f69061153e908c906000906004016131b4565b602060405180830381865afa15801561155b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157f919061300e565b6115888b610b60565b602087015160405160e086901b6001600160e01b03191681526115b3949392916003916004016134fd565b602060405180830381865af41580156115d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f4919061304d565b98975050505050505050565b610140820135158061160f5750805b156116555761162460a0830160808401612b75565b6001600160a01b0316336001600160a01b0316146116555760405163d7f4fc9f60e01b815260040160405180910390fd5b600061166361070084612f0d565b905060016116708261099b565b600381111561168157611681612bab565b1461169f57604051631f6646b560e01b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0386169063a86f9d9e906116cf9060019060040161321e565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611710919061300e565b90506001600160a01b0381161561178057604051630d73bb3d60e41b815261010085013560048201526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b15801561176757600080fd5b505af115801561177b573d6000803e3d6000fd5b505050505b61178c8685845a611eb9565b156117a15761179c826002612011565b611830565b8215611818576117b2826003612011565b6000806117c560e0870160c08801612b75565b6001600160a01b0316146117e8576117e360e0860160c08701612b75565b6117f8565b6117f860a0860160808701612b75565b90506118126001600160a01b038216610100870135611dde565b50611830565b6118306001600160a01b038216610100860135611dde565b505050505050565b61014083013515801561186c575061185660a0840160808501612b75565b6001600160a01b0316336001600160a01b031614155b1561188a5760405163398b635960e21b815260040160405180910390fd5b468360600135146118ae5760405163e822b48d60e01b815260040160405180910390fd5b60006118bc61070085612f0d565b905060006118c98261099b565b60038111156118da576118da612bab565b146118f857604051630cfafbf960e01b815260040160405180910390fd5b6000856001600160a01b0316636c6563f6866040013560006040518363ffffffff1660e01b815260040161192d9291906131b4565b602060405180830381865afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e919061300e565b604051635437cecf60e11b81529091506001600160a01b0387169063a86f9d9e9061199e9060009060040161302b565b602060405180830381865afa1580156119bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119df919061300e565b6001600160a01b0316635221f6138660400135838588886040518663ffffffff1660e01b8152600401611a1695949392919061326f565b602060405180830381865afa158015611a33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a57919061304d565b611a74576040516314504c7360e31b815260040160405180910390fd5b6000610120860135611a8f61010088013560e089013561320b565b611a99919061320b565b90506000876001600160a01b031663a86f9d9e60016040518263ffffffff1660e01b8152600401611aca919061321e565b602060405180830381865afa158015611ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0b919061300e565b90506001600160a01b03811615801590611b255750600082115b15611b8557604051630d73bb3d60e41b8152600481018390526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b158015611b6c57600080fd5b505af1158015611b80573d6000803e3d6000fd5b505050505b611bac60e0880135611b9d60a08a0160808b01612b75565b6001600160a01b031690611dde565b60008030611bc060c08b0160a08c01612b75565b6001600160a01b03161480611bed57506000611be260c08b0160a08c01612b75565b6001600160a01b0316145b15611c02575060029050610100880135611c79565b6000611c1460a08b0160808c01612b75565b6001600160a01b0316336001600160a01b031614611c3757896101400135611c39565b5a5b90506000611c498d8c8a85611eb9565b90508015611c5a5760029350611c76565b60019350611c766001600160a01b0386166101008d0135611dde565b50505b611c838683612011565b600080611c9660e08c0160c08d01612b75565b6001600160a01b031614611cb957611cb460e08b0160c08c01612b75565b611cc9565b611cc960a08b0160808c01612b75565b90506001600160a01b0381163303611d07576000611cec836101208d013561320b565b9050611d016001600160a01b03831682611dde565b50611d29565b611d16336101208c0135611dde565b611d296001600160a01b03821683611dde565b505050505050505050505050565b600054610100900460ff16611d5e5760405162461bcd60e51b815260040161065c90613530565b61074c61208a565b600054610100900460ff16611d8d5760405162461bcd60e51b815260040161065c90613530565b61074c6120b1565b6001600160a01b038116611dbc57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b801580611df257506001600160a01b038216155b15611dfb575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611e48576040519150601f19603f3d011682016040523d82523d6000602084013e611e4d565b606091505b50509050806107b35760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015260640161065c565b600080611eaa611ea58460006120e1565b612502565b80516020909101209392505050565b600081600003611edc57604051637f0e960960e11b815260040160405180910390fd5b6040518060600160405280848152602001856020016020810190611f009190612b75565b6001600160a01b039081168252604087810135602093840152835160018a0155918301516002890180546001600160a01b0319169190921617905501516003860155611f5260c0850160a08601612b75565b6001600160a01b031682610100860135611f7061016088018861357b565b604051611f7e9291906135c1565b600060405180830381858888f193505050503d8060008114611fbc576040519150601f19603f3d011682016040523d82523d6000602084013e611fc1565b606091505b505060408051606081018252600180825260208201819052600019919092018190528782018290556002880180546001600160a01b03191690921790915560039096019590955550929392505050565b80600381111561202357612023612bab565b61202c8361099b565b600381111561203d5761203d612bab565b146106d75761204c8282612546565b817f0af4d5247f6a4028d6699afb62871a76b398da1d1a626c8a9b90e0bd5f54c73c823360405161207e9291906135d1565b60405180910390a25050565b600054610100900460ff16610f215760405162461bcd60e51b815260040161065c90613530565b600054610100900460ff166120d85760405162461bcd60e51b815260040161065c90613530565b61074c33610b9b565b6102008201516060901561214c576120fa82601161320b565b6001600160401b0381111561211157612111612dfd565b60405190808252806020026020018201604052801561214457816020015b606081526020019060019003908161212f5790505b5090506121bb565b6101e083015115612162576120fa82601061320b565b61216d82600f61320b565b6001600160401b0381111561218457612184612dfd565b6040519080825280602002602001820160405280156121b757816020015b60608152602001906001900390816121a25790505b5090505b82516121c69061256f565b816000815181106121d9576121d96135f7565b60200260200101819052506121f1836020015161256f565b81600181518110612204576122046135f7565b602002602001018190525061221c8360400151612582565b8160028151811061222f5761222f6135f7565b6020026020010181905250612247836060015161256f565b8160038151811061225a5761225a6135f7565b6020026020010181905250612272836080015161256f565b81600481518110612285576122856135f7565b602002602001018190525061229d8360a0015161256f565b816005815181106122b0576122b06135f7565b60200260200101819052506122e78360c001516040516020016122d3919061360d565b6040516020818303038152906040526125ab565b816006815181106122fa576122fa6135f7565b60200260200101819052506123128360e0015161261a565b81600781518110612325576123256135f7565b60200260200101819052506123478361010001516001600160801b031661261a565b8160088151811061235a5761235a6135f7565b6020026020010181905250612373836101200151612628565b81600981518110612386576123866135f7565b602002602001018190525061239f836101400151612628565b81600a815181106123b2576123b26135f7565b60200260200101819052506123cb836101600151612628565b81600b815181106123de576123de6135f7565b60200260200101819052506123f78361018001516125ab565b81600c8151811061240a5761240a6135f7565b6020026020010181905250612423836101a0015161256f565b81600d81518110612436576124366135f7565b602002602001018190525061246d836101c001516040516020016122d3919060c09190911b6001600160c01b031916815260080190565b81600e81518110612480576124806135f7565b6020026020010181905250826101e001516000146124c5576124a6836101e0015161261a565b81600f815181106124b9576124b96135f7565b60200260200101819052505b6102008301511561053a576124de83610200015161256f565b816010815181106124f1576124f16135f7565b602002602001018190525092915050565b6060600061250f8361263f565b905061251d815160c0612774565b8160405160200161252f929190613642565b604051602081830303815290604052915050919050565b600061255183610b60565b9050600082600381111561256757612567612bab565b909155505050565b606061053a61257d8361291c565b6125ab565b604051606082811b6bffffffffffffffffffffffff191660208301529061053a906034016122d3565b606080825160011480156125d957506080836000815181106125cf576125cf6135f7565b016020015160f81c105b156125e557508161053a565b6125f183516080612774565b83604051602001612603929190613642565b604051602081830303815290604052905092915050565b606061053a61257d836129ce565b606061053a61257d836001600160401b03166129ce565b60608151600003612660576040805160008082526020820190925290610711565b6000805b83518110156126a55783818151811061267f5761267f6135f7565b60200260200101515182612693919061320b565b915061269e8161323d565b9050612664565b6000826001600160401b038111156126bf576126bf612dfd565b6040519080825280601f01601f1916602001820160405280156126e9576020820181803683370190505b50600092509050602081015b855183101561276b576000868481518110612712576127126135f7565b60200260200101519050600060208201905061273083828451612af8565b878581518110612742576127426135f7565b60200260200101515183612756919061320b565b92505050826127649061323d565b92506126f5565b50949350505050565b60608060388410156127db57604080516001808252818301909252906020820181803683370190505090506127a98385613671565b60f81b816000815181106127bf576127bf6135f7565b60200101906001600160f81b031916908160001a905350610537565b600060015b6127ea81876136a0565b1561280d576127f88261323d565b9150612806610100826136b4565b90506127e0565b61281882600161320b565b6001600160401b0381111561282f5761282f612dfd565b6040519080825280601f01601f191660200182016040528015612859576020820181803683370190505b5092506128668583613671565b612871906037613671565b60f81b83600081518110612887576128876135f7565b60200101906001600160f81b031916908160001a905350600190505b818111612913576101006128b782846136cb565b6128c3906101006137c2565b6128cd90886136a0565b6128d791906137ce565b60f81b8382815181106128ec576128ec6135f7565b60200101906001600160f81b031916908160001a90535061290c8161323d565b90506128a3565b50509392505050565b606060008260405160200161293391815260200190565b60408051808303601f1901815260208084528383019092529250600091829160208201818036833701905050905060005b815181101561276b5783836129788161323d565b94508151811061298a5761298a6135f7565b602001015160f81c60f81b8282815181106129a7576129a76135f7565b60200101906001600160f81b031916908160001a9053506129c78161323d565b9050612964565b60606000826040516020016129e591815260200190565b604051602081830303815290604052905060005b6020811015612a3a57818181518110612a1457612a146135f7565b01602001516001600160f81b031916600003612a3a57612a338161323d565b90506129f9565b6000612a478260206136cb565b6001600160401b03811115612a5e57612a5e612dfd565b6040519080825280601f01601f191660200182016040528015612a88576020820181803683370190505b50905060005b815181101561276b578383612aa28161323d565b945081518110612ab457612ab46135f7565b602001015160f81c60f81b828281518110612ad157612ad16135f7565b60200101906001600160f81b031916908160001a905350612af18161323d565b9050612a8e565b8282825b60208110612b345781518352612b1360208461320b565b9250612b2060208361320b565b9150612b2d6020826136cb565b9050612afc565b905182516020929092036101000a6000190180199091169116179052505050565b6001600160a01b038116811461083d57600080fd5b803561077781612b55565b600060208284031215612b8757600080fd5b813561053781612b55565b600060208284031215612ba457600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60048110612bdf57634e487b7160e01b600052602160045260246000fd5b9052565b6020810161053a8284612bc1565b60006101a08284031215612c0457600080fd5b50919050565b600060208284031215612c1c57600080fd5b81356001600160401b03811115612c3257600080fd5b6109be84828501612bf1565b801515811461083d57600080fd5b600080600060608486031215612c6157600080fd5b83359250602084013591506040840135612c7a81612c3e565b809150509250925092565b60008083601f840112612c9757600080fd5b5081356001600160401b03811115612cae57600080fd5b602083019150836020828501011115612cc657600080fd5b9250929050565b60008060008060608587031215612ce357600080fd5b843593506020850135925060408501356001600160401b03811115612d0757600080fd5b612d1387828801612c85565b95989497509550505050565b60008060408385031215612d3257600080fd5b823591506020830135612d4481612c3e565b809150509250929050565b600080600060408486031215612d6457600080fd5b83356001600160401b0380821115612d7b57600080fd5b612d8787838801612bf1565b94506020860135915080821115612d9d57600080fd5b50612daa86828701612c85565b9497909650939450505050565b60008060408385031215612dca57600080fd5b82356001600160401b03811115612de057600080fd5b612dec85828601612bf1565b9250506020830135612d4481612c3e565b634e487b7160e01b600052604160045260246000fd5b6040516101a081016001600160401b0381118282101715612e3657612e36612dfd565b60405290565b604080519081016001600160401b0381118282101715612e3657612e36612dfd565b60405161022081016001600160401b0381118282101715612e3657612e36612dfd565b600082601f830112612e9257600080fd5b81356001600160401b0380821115612eac57612eac612dfd565b604051601f8301601f19908116603f01168101908282118183101715612ed457612ed4612dfd565b81604052838152866020858801011115612eed57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101a08236031215612f2057600080fd5b612f28612e13565b82358152612f3860208401612b6a565b60208201526040830135604082015260608301356060820152612f5d60808401612b6a565b6080820152612f6e60a08401612b6a565b60a0820152612f7f60c08401612b6a565b60c082015260e08381013590820152610100808401359082015261012080840135908201526101408084013590820152610160808401356001600160401b0380821115612fcb57600080fd5b612fd736838801612e81565b83850152610180925082860135915080821115612ff357600080fd5b5061300036828701612e81565b918301919091525092915050565b60006020828403121561302057600080fd5b815161053781612b55565b6d7369676e616c5f7365727669636560901b8152901515602082015260400190565b60006020828403121561305f57600080fd5b815161053781612c3e565b60005b8381101561308557818101518382015260200161306d565b50506000910152565b600081518084526130a681602086016020860161306a565b601f01601f19169290920160200192915050565b6020815281516020820152600060208301516130e160408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015161311060a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a061018080850182905261318e6101c086018461308e565b90860151858203601f1901838701529092506131aa838261308e565b9695505050505050565b9182526562726964676560d01b60208301521515604082015260600190565b600083516131e581846020880161306a565b9190910191825250602001919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561053a5761053a6131f5565b6a195d1a195c97dd985d5b1d60aa1b8152901515602082015260400190565b60006001820161324f5761324f6131f5565b5060010190565b60006020828403121561326857600080fd5b5051919050565b8581526001600160a01b0385166020820152604081018490526080606082018190528101829052818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b600082601f8301126132cf57600080fd5b6040516101008082018281106001600160401b03821117156132f3576132f3612dfd565b6040528301818582111561330657600080fd5b845b82811015613320578035825260209182019101613308565b509195945050505050565b80356001600160801b038116811461077757600080fd5b80356001600160401b038116811461077757600080fd5b60006020828403121561336b57600080fd5b81356001600160401b038082111561338257600080fd5b908301906040828603121561339657600080fd5b61339e612e3c565b8235828111156133ad57600080fd5b830161030081880312156133c057600080fd5b6133c8612e5e565b81358152602082013560208201526133e260408301612b6a565b6040820152606082013560608201526080820135608082015260a082013560a08201526134128860c084016132be565b60c08201526101c08083013560e08301526101e061343181850161332b565b610100840152610200613445818601613342565b6101208501526134586102208601613342565b61014085015261346b6102408601613342565b6101608501526102608501358781111561348457600080fd5b6134908c828801612e81565b610180860152506102808501356101a08501526134b06102a08601613342565b838501526102c0850135828501526102e08501358185015250505080835250506020830135828111156134e257600080fd5b6134ee87828601612e81565b60208301525095945050505050565b85815260018060a01b038516602082015283604082015282606082015260a06080820152600061107f60a083018461308e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000808335601e1984360301811261359257600080fd5b8301803591506001600160401b038211156135ac57600080fd5b602001915036819003821315612cc657600080fd5b8183823760009101908152919050565b604081016135df8285612bc1565b6001600160a01b039290921660209190910152919050565b634e487b7160e01b600052603260045260246000fd5b60008183825b6008811015613632578151835260209283019290910190600101613613565b5050506101008201905092915050565b6000835161365481846020880161306a565b83519083019061366881836020880161306a565b01949350505050565b60ff818116838216019081111561053a5761053a6131f5565b634e487b7160e01b600052601260045260246000fd5b6000826136af576136af61368a565b500490565b808202811582820484141761053a5761053a6131f5565b8181038181111561053a5761053a6131f5565b600181815b808511156137195781600019048211156136ff576136ff6131f5565b8085161561370c57918102915b93841c93908002906136e3565b509250929050565b6000826137305750600161053a565b8161373d5750600061053a565b8160018114613753576002811461375d57613779565b600191505061053a565b60ff84111561376e5761376e6131f5565b50506001821b61053a565b5060208310610133831016604e8410600b841016171561379c575081810a61053a565b6137a683836136de565b80600019048211156137ba576137ba6131f5565b029392505050565b60006105378383613721565b6000826137dd576137dd61368a565b50069056fea2646970667358221220375c4de0362d3ed6e76edb571acb958d89d208d7216e0c416a7cdb4ee2dfeba764736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000004" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000002": { + "storage": {}, + "code": "0x6080604052600436106100e85760003560e01c8063780b64f01161008a578063a86f9d9e11610059578063a86f9d9e146102ca578063c287e578146102ea578063ee1490b21461032a578063f2fde38b1461033d57600080fd5b8063780b64f0146101fc5780638da5cb5b1461025b5780639754149b146102795780639aa8605c1461029957600080fd5b80633ab76e9f116100c65780633ab76e9f1461014f57806367090ccf146101865780636c6563f6146101c7578063715018a6146101e757600080fd5b80630652b57a146100ed5780630c6fab821461010f57806319ab453c1461012f575b600080fd5b3480156100f957600080fd5b5061010d610108366004611fa4565b61035d565b005b34801561011b57600080fd5b5061010d61012a366004611fc1565b6103e0565b34801561013b57600080fd5b5061010d61014a366004611fa4565b61068f565b34801561015b57600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019257600080fd5b506101696101a1366004612030565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156101d357600080fd5b506101696101e236600461206e565b6107a7565b3480156101f357600080fd5b5061010d6107be565b34801561020857600080fd5b5061023c6102173660046120a7565b60cc60205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161017d565b34801561026757600080fd5b506065546001600160a01b0316610169565b34801561028557600080fd5b5061010d6102943660046120c0565b6107d2565b3480156102a557600080fd5b506102b96102b4366004611fa4565b610b54565b60405161017d9594939291906121b0565b3480156102d657600080fd5b506101696102e5366004612201565b610ca5565b3480156102f657600080fd5b5061031a610305366004611fa4565b60c96020526000908152604090205460ff1681565b604051901515815260200161017d565b61010d610338366004612295565b610cbb565b34801561034957600080fd5b5061010d610358366004611fa4565b611574565b6103656115ed565b6001600160a01b03811661038c57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b6103e8611647565b6562726964676560d01b6103fd816001610ca5565b6001600160a01b0316336001600160a01b03161461042e57604051630d85cccf60e11b815260040160405180910390fd5b6000336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561046e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104929190612374565b90506104b281604001516a1d1bdad95b97dd985d5b1d60aa1b60006107a7565b6001600160a01b031681602001516001600160a01b0316146104e7576040516320258b8760e21b815260040160405180910390fd5b6000468735036105b4576105016040880160208901611fa4565b905061051c6a3a30b4b5b7afba37b5b2b760a91b6001610ca5565b6001600160a01b0316816001600160a01b03160361059b576040516340c10f1960e01b81526001600160a01b038681166004830152602482018690528216906340c10f1990604401600060405180830381600087803b15801561057e57600080fd5b505af1158015610592573d6000803e3d6000fd5b50505050610624565b6105af6001600160a01b03821686866116a0565b610624565b6105bd87611703565b6040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052919250908216906340c10f1990604401600060405180830381600087803b15801561060b57600080fd5b505af115801561061f573d6000803e3d6000fd5b505050505b815160408084015181519081526001600160a01b0384811660208301529181018790528188169291891691907fe5da926519fc972010fe65b35c1e3339e6dc72b35ffaec203999c2a2a2593eac9060600160405180910390a450505061068960018055565b50505050565b600054610100900460ff16158080156106af5750600054600160ff909116105b806106c95750303b1580156106c9575060005460ff166001145b6107315760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610754576000805461ff0019166101001790555b61075d82611762565b80156107a3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006107b484848461177b565b90505b9392505050565b6107c66115ed565b6107d0600061182f565b565b6107da611647565b60006107ec60a0850160808601611fa4565b6001600160a01b031603610813576040516372b41cdf60e01b815260040160405180910390fd5b46836040013514610837576040516348bc100560e01b815260040160405180910390fd5b600061084d6562726964676560d01b6000610ca5565b90506000816001600160a01b0316635817b0c3866040518263ffffffff1660e01b815260040161087d919061244c565b602060405180830381865afa15801561089a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108be919061256a565b600081815260cc6020526040902080546001909101549192506001600160a01b031690816108ff57604051637c6addb760e01b815260040160405180910390fd5b60405163ce70f39b60e01b81526001600160a01b0385169063ce70f39b9061093590869060608c0135908b908b90600401612583565b602060405180830381865afa158015610952573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097691906125ad565b610993576040516308ba49e560e31b815260040160405180910390fd5b6040805180820182526000808252602080830182815287835260cc909152929020905181546001600160a01b0319166001600160a01b0390911617815590516001909101558015610adb576001600160a01b038216600090815260c9602052604090205460ff1680610a2e5750610a196a3a30b4b5b7afba37b5b2b760a91b6001610ca5565b6001600160a01b0316826001600160a01b0316145b15610ab7576001600160a01b0382166340c10f19610a5260a08a0160808b01611fa4565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401600060405180830381600087803b158015610a9a57600080fd5b505af1158015610aae573d6000803e3d6000fd5b50505050610adb565b610adb610aca60a0890160808a01611fa4565b6001600160a01b03841690836116a0565b610aeb60a0880160808901611fa4565b6001600160a01b0316837fc5d9f7cd7998e24ecf12ad69eca9339764e2cb13788d5d9616f502601b219af68484604051610b3a9291906001600160a01b03929092168252602082015260400190565b60405180910390a350505050610b4f60018055565b505050565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b03831693600160a01b90930460ff1692909190610b94906125ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610bc0906125ca565b8015610c0d5780601f10610be257610100808354040283529160200191610c0d565b820191906000526020600020905b815481529060010190602001808311610bf057829003601f168201915b505050505090806003018054610c22906125ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610c4e906125ca565b8015610c9b5780601f10610c7057610100808354040283529160200191610c9b565b820191906000526020600020905b815481529060010190602001808311610c7e57829003601f168201915b5050505050905085565b6000610cb246848461177b565b90505b92915050565b610cc3611647565b6001600160a01b0387161580610d035750610cee886a1d1bdad95b97dd985d5b1d60aa1b60006107a7565b6001600160a01b0316876001600160a01b0316145b15610d2157604051634694641b60e01b815260040160405180910390fd5b6001600160a01b038616610d4857604051637c6addb760e01b815260040160405180910390fd5b84600003610d685760405162af849960e11b815260040160405180910390fd5b6040805160a08101825260008082526020820181905291810191909152606080820181905260808201526001600160a01b038716600090815260c9602052604081205460ff1615610faf576001600160a01b03888116600090815260ca6020908152604091829020825160a08101845281548152600182015494851692810192909252600160a01b90930460ff1691810191909152600282018054919291606084019190610e15906125ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610e41906125ca565b8015610e8e5780601f10610e6357610100808354040283529160200191610e8e565b820191906000526020600020905b815481529060010190602001808311610e7157829003601f168201915b50505050508152602001600382018054610ea7906125ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed3906125ca565b8015610f205780601f10610ef557610100808354040283529160200191610f20565b820191906000526020600020905b815481529060010190602001808311610f0357829003601f168201915b5050509190925250505060208101519092506001600160a01b0316610f4757610f47612604565b604051632770a7eb60e21b8152336004820152602481018890526001600160a01b03891690639dc29fac90604401600060405180830381600087803b158015610f8f57600080fd5b505af1158015610fa3573d6000803e3d6000fd5b505050508690506112a8565b60008890506040518060a001604052804681526020018a6001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611012573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110369190612629565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561107c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110a49190810190612646565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156110e7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261110f9190810190612646565b9052925061112c6a3a30b4b5b7afba37b5b2b760a91b6001610ca5565b6001600160a01b0316896001600160a01b0316036111ac57604051632770a7eb60e21b8152336004820152602481018990526001600160a01b038a1690639dc29fac90604401600060405180830381600087803b15801561118c57600080fd5b505af11580156111a0573d6000803e3d6000fd5b505050508791506112a6565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156111f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611217919061256a565b905061122e6001600160a01b03831633308c611881565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015611274573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611298919061256a565b6112a291906126bd565b9250505b505b611337604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018b905233608082015261135e8b6a1d1bdad95b97dd985d5b1d60aa1b60006107a7565b6001600160a01b031660a08201526080810151604051630637d5c160e11b91611390918691908e9087906024016126de565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610160820152610140810187905261012081018690526113e286346126bd565b60e08201526001600160a01b03851660c0820152610180810184905260006114136562726964676560d01b82610ca5565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b815260040161143f9190612776565b60206040518083038185885af115801561145d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611482919061256a565b905060405180604001604052808b6001600160a01b031681526020018481525060cc600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550602082015181600101559050508a6001600160a01b031682608001516001600160a01b0316827f325cab7553038374e17f39bb45e2a2c90f66c6a52798cb5f95c20d94c11c95e28f8e88604051611555939291909283526001600160a01b03919091166020830152604082015260600190565b60405180910390a45050505061156a60018055565b5050505050505050565b61157c6115ed565b6001600160a01b0381166115e15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610728565b6115ea8161182f565b50565b6065546001600160a01b031633146107d05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610728565b6002600154036116995760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610728565b6002600155565b6040516001600160a01b038316602482015260448101829052610b4f90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526118b9565b8035600090815260cb6020908152604080832083929091839161172a918701908701611fa4565b6001600160a01b03908116825260208201929092526040016000205416905080610cb5576117578361198b565b6107b7565b60018055565b61176a611be6565b611772611c15565b6115ea81611c44565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156117cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f09190612866565b90508115801561180757506001600160a01b038116155b156107b757604051631467050360e21b81526004810185905260248101849052604401610728565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526106899085906323b872dd60e01b906084016116cc565b600061190e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611c8d9092919063ffffffff16565b805190915015610b4f578080602001905181019061192c91906125ad565b610b4f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610728565b6000611a048183356119a36040860160208701611fa4565b6040516119c692916001600160a01b031690602001918252602082015260400190565b60405160208183030381529060405280519060200120604051806020016119ec90611f72565b601f1982820381018352601f90910116604052611c9c565b6097549091506001600160a01b0380831691636c0db62b9116611a2d6040860160208701611fa4565b8535611a3f6060880160408901612883565b611a4c60608901896128a0565b611a5960808b018b6128a0565b6040518963ffffffff1660e01b8152600401611a7c9897969594939291906128e7565b600060405180830381600087803b158015611a9657600080fd5b505af1158015611aaa573d6000803e3d6000fd5b5050506001600160a01b038216600090815260c960209081526040808320805460ff1916600117905560ca9091529020839150611ae78282612a55565b50508135600090815260cb60209081526040808320849390929091611b1191908701908701611fa4565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b0316826020016020810190611b729190611fa4565b6001600160a01b031683357f9e465b29e576a3e01584e31d607353f21b80c055e813af907c0a495f6cf4f7bc611bab60608701876128a0565b611bb860808901896128a0565b611bc860608b0160408c01612883565b604051611bd9959493929190612adc565b60405180910390a4919050565b600054610100900460ff16611c0d5760405162461bcd60e51b815260040161072890612b19565b6107d0611da0565b600054610100900460ff16611c3c5760405162461bcd60e51b815260040161072890612b19565b6107d0611dc7565b6001600160a01b038116611c6b57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60606107b48484600085611df7565b600083471015611cee5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610728565b8151600003611d3f5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610728565b8282516020840186f590506001600160a01b0381166107b75760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610728565b600054610100900460ff1661175c5760405162461bcd60e51b815260040161072890612b19565b600054610100900460ff16611dee5760405162461bcd60e51b815260040161072890612b19565b6107d03361182f565b606082471015611e585760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610728565b600080866001600160a01b03168587604051611e749190612b64565b60006040518083038185875af1925050503d8060008114611eb1576040519150601f19603f3d011682016040523d82523d6000602084013e611eb6565b606091505b5091509150611ec787838387611ed4565b925050505b949350505050565b60608315611f43578251600003611f3c576001600160a01b0385163b611f3c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610728565b5081611ecc565b611ecc8383815115611f585781518083602001fd5b8060405162461bcd60e51b81526004016107289190612b80565b61199080612b9483390190565b6001600160a01b03811681146115ea57600080fd5b8035611f9f81611f7f565b919050565b600060208284031215611fb657600080fd5b81356107b781611f7f565b60008060008060808587031215611fd757600080fd5b843567ffffffffffffffff811115611fee57600080fd5b850160a0818803121561200057600080fd5b9350602085013561201081611f7f565b9250604085013561202081611f7f565b9396929550929360600135925050565b6000806040838503121561204357600080fd5b82359150602083013561205581611f7f565b809150509250929050565b80151581146115ea57600080fd5b60008060006060848603121561208357600080fd5b8335925060208401359150604084013561209c81612060565b809150509250925092565b6000602082840312156120b957600080fd5b5035919050565b6000806000604084860312156120d557600080fd5b833567ffffffffffffffff808211156120ed57600080fd5b908501906101a0828803121561210257600080fd5b9093506020850135908082111561211857600080fd5b818601915086601f83011261212c57600080fd5b81358181111561213b57600080fd5b87602082850101111561214d57600080fd5b6020830194508093505050509250925092565b60005b8381101561217b578181015183820152602001612163565b50506000910152565b6000815180845261219c816020860160208601612160565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260ff8416604082015260a0606082018190526000906121e390830185612184565b82810360808401526121f58185612184565b98975050505050505050565b6000806040838503121561221457600080fd5b82359150602083013561205581612060565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561226557612265612226565b604052919050565b600067ffffffffffffffff82111561228757612287612226565b50601f01601f191660200190565b600080600080600080600080610100898b0312156122b257600080fd5b8835975060208901356122c481611f7f565b965060408901356122d481611f7f565b9550606089013594506080890135935060a0890135925060c08901356122f981611f7f565b915060e089013567ffffffffffffffff81111561231557600080fd5b8901601f81018b1361232657600080fd5b80356123396123348261226d565b61223c565b8181528c602083850101111561234e57600080fd5b816020840160208301376000602083830101528093505050509295985092959890939650565b60006060828403121561238657600080fd5b6040516060810181811067ffffffffffffffff821117156123a9576123a9612226565b6040528251815260208301516123be81611f7f565b60208201526040928301519281019290925250919050565b6000808335601e198436030181126123ed57600080fd5b830160208101925035905067ffffffffffffffff81111561240d57600080fd5b80360382131561241c57600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815281356020820152600061246560208401611f94565b6001600160a01b038116604084015250604083013560608301526060830135608083015261249560808401611f94565b6001600160a01b03811660a0840152506124b160a08401611f94565b6001600160a01b03811660c0840152506124cd60c08401611f94565b6001600160a01b03811660e08401525061010060e084013581840152610120818501358185015261014091508085013582850152506101608185013581850152612519818601866123d6565b925090506101a061018081818701526125376101c087018585612423565b9350612545818801886123d6565b878603601f1901848901529350905061255f848483612423565b979650505050505050565b60006020828403121561257c57600080fd5b5051919050565b8481528360208201526060604082015260006125a3606083018486612423565b9695505050505050565b6000602082840312156125bf57600080fd5b81516107b781612060565b600181811c908216806125de57607f821691505b6020821081036125fe57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052600160045260246000fd5b60ff811681146115ea57600080fd5b60006020828403121561263b57600080fd5b81516107b78161261a565b60006020828403121561265857600080fd5b815167ffffffffffffffff81111561266f57600080fd5b8201601f8101841361268057600080fd5b805161268e6123348261226d565b8181528560208385010111156126a357600080fd5b6126b4826020830160208601612160565b95945050505050565b81810381811115610cb557634e487b7160e01b600052601160045260246000fd5b60808152845160808201526000602086015160018060a01b0380821660a085015260ff60408901511660c08501526060880151915060a060e0850152612728610120850183612184565b91506080880151607f19858403016101008601526127468382612184565b9188166020860152506001600160a01b038616604085015291506127679050565b82606083015295945050505050565b60208152815160208201526000602083015161279d60408401826001600160a01b03169052565b50604083015160608301526060830151608083015260808301516127cc60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a061018080850182905261284a6101c0860184612184565b90860151858203601f1901838701529092506125a38382612184565b60006020828403121561287857600080fd5b81516107b781611f7f565b60006020828403121561289557600080fd5b81356107b78161261a565b6000808335601e198436030181126128b757600080fd5b83018035915067ffffffffffffffff8211156128d257600080fd5b60200191503681900382131561241c57600080fd5b6001600160a01b038981168252881660208201526040810187905260ff8616606082015260c0608082018190526000906129249083018688612423565b82810360a0840152612937818587612423565b9b9a5050505050505050505050565b601f821115610b4f57600081815260208120601f850160051c8101602086101561296d5750805b601f850160051c820191505b8181101561298c57828155600101612979565b505050505050565b67ffffffffffffffff8311156129ac576129ac612226565b6129c0836129ba83546125ca565b83612946565b6000601f8411600181146129f457600085156129dc5750838201355b600019600387901b1c1916600186901b178355612a4e565b600083815260209020601f19861690835b82811015612a255786850135825560209485019460019092019101612a05565b5086821015612a425760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b81358155600181016020830135612a6b81611f7f565b81546040850135612a7b8161261a565b60ff60a01b60a09190911b166001600160a01b03929092166001600160a81b03199190911617179055612ab160608301836128a0565b612abf818360028601612994565b5050612ace60808301836128a0565b610689818360038601612994565b606081526000612af0606083018789612423565b8281036020840152612b03818688612423565b91505060ff831660408301529695505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251612b76818460208701612160565b9190910192915050565b602081526000610cb2602083018461218456fe608060405234801561001057600080fd5b50611970806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80636c6563f6116100c35780639dc29fac1161007c5780639dc29fac146102fa578063a457c2d71461030d578063a86f9d9e14610320578063a9059cbb14610333578063dd62ed3e14610346578063f2fde38b1461035957600080fd5b80636c6563f61461028a57806370a082311461029d578063715018a6146102c65780637cf8ed0d146102ce5780638da5cb5b146102e157806395d89b41146102f257600080fd5b8063313ce56711610115578063313ce5671461020e57806339509351146102235780633ab76e9f1461023657806340c10f191461025b57806349d126051461026e5780636c0db62b1461027757600080fd5b80630652b57a1461015d57806306fdde0314610172578063095ea7b31461019057806318160ddd146101b357806323b872dd146101c557806326afaadd146101d8575b600080fd5b61017061016b36600461144e565b61036c565b005b61017a6103ef565b604051610187919061148f565b60405180910390f35b6101a361019e3660046114c2565b610429565b6040519015158152602001610187565b60cb545b604051908152602001610187565b6101a36101d33660046114ee565b610443565b6101ef60fb5460fc546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610187565b60fd5460405160ff9091168152602001610187565b6101a36102313660046114c2565b610483565b6097546001600160a01b03165b6040516001600160a01b039091168152602001610187565b6101706102693660046114c2565b6104a5565b6101b760fc5481565b6101706102853660046115d2565b6105ae565b610243610298366004611691565b610754565b6101b76102ab36600461144e565b6001600160a01b0316600090815260c9602052604090205490565b610170610761565b60fb54610243906001600160a01b031681565b6065546001600160a01b0316610243565b61017a610775565b6101706103083660046114c2565b610807565b6101a361031b3660046114c2565b610901565b61024361032e3660046116c6565b610987565b6101a36103413660046114c2565b610994565b6101b76103543660046116f2565b6109c9565b61017061036736600461144e565b6109f4565b610374610a6d565b6001600160a01b03811661039b57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b60606103f9610ac7565b61040460fc54610ad6565b60405160200161041592919061172b565b604051602081830303815290604052905090565b600033610437818585610b69565b60019150505b92915050565b6000306001600160a01b0384160361046e576040516319a6f37760e21b815260040160405180910390fd5b610479848484610c8e565b90505b9392505050565b60003361043781858561049683836109c9565b6104a09190611769565b610b69565b647461696b6f60d81b6a1c1c9bdd995c97dc1bdbdb60aa1b6a1d1bdad95b97dd985d5b1d60aa1b6104d7836001610987565b6001600160a01b0316336001600160a01b03161415801561051457506104fe826001610987565b6001600160a01b0316336001600160a01b031614155b801561053c5750610526816001610987565b6001600160a01b0316336001600160a01b031614155b1561055a57604051630d85cccf60e11b815260040160405180910390fd5b6105648585610ca7565b846001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858560405161059f91815260200190565b60405180910390a25050505050565b600054610100900460ff16158080156105ce5750600054600160ff909116105b806105e85750303b1580156105e8575060005460ff166001145b6106505760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610673576000805461ff0019166101001790555b6001600160a01b0386161580610687575084155b8061069157504685145b8061069b57508251155b806106a557508151155b156106c3576040516301e25ab360e71b815260040160405180910390fd5b6106cc87610d69565b6106d68284610d82565b60fb80546001600160a01b0319166001600160a01b03881617905560fc85905560fd805460ff191660ff8616179055801561074b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6000610479848484610db3565b610769610a6d565b6107736000610e67565b565b606060cd80546107849061178a565b80601f01602080910402602001604051908101604052809291908181526020018280546107b09061178a565b80156107fd5780601f106107d2576101008083540402835291602001916107fd565b820191906000526020600020905b8154815290600101906020018083116107e057829003601f168201915b5050505050905090565b647461696b6f60d81b6a1c1c9bdd995c97dc1bdbdb60aa1b6a1d1bdad95b97dd985d5b1d60aa1b610839836001610987565b6001600160a01b0316336001600160a01b0316141580156108765750610860826001610987565b6001600160a01b0316336001600160a01b031614155b801561089e5750610888816001610987565b6001600160a01b0316336001600160a01b031614155b156108bc57604051630d85cccf60e11b815260040160405180910390fd5b6108c68585610eb9565b846001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58560405161059f91815260200190565b6000338161090f82866109c9565b90508381101561096f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610647565b61097c8286868403610b69565b506001949350505050565b600061047c468484610db3565b6000306001600160a01b038416036109bf576040516319a6f37760e21b815260040160405180910390fd5b61047c8383610fea565b6001600160a01b03918216600090815260ca6020908152604080832093909416825291909152205490565b6109fc610a6d565b6001600160a01b038116610a615760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610647565b610a6a81610e67565b50565b6065546001600160a01b031633146107735760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610647565b606060cc80546107849061178a565b60606000610ae383610ff8565b600101905060008167ffffffffffffffff811115610b0357610b0361152f565b6040519080825280601f01601f191660200182016040528015610b2d576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610b3757509392505050565b6001600160a01b038316610bcb5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610647565b6001600160a01b038216610c2c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610647565b6001600160a01b03838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600033610c9c8582856110d0565b61097c85858561114a565b6001600160a01b038216610cfd5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610647565b8060cb6000828254610d0f9190611769565b90915550506001600160a01b038216600081815260c960209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b5050565b610d716112f5565b610d79611324565b610a6a81611353565b600054610100900460ff16610da95760405162461bcd60e51b8152600401610647906117c4565b610d65828261139c565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610e04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e28919061180f565b905081158015610e3f57506001600160a01b038116155b1561047c57604051631467050360e21b81526004810185905260248101849052604401610647565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216610f195760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610647565b6001600160a01b038216600090815260c9602052604090205481811015610f8d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610647565b6001600160a01b038316600081815260c960209081526040808320868603905560cb80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610c81565b505050565b60003361043781858561114a565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106110375772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611063576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061108157662386f26fc10000830492506010015b6305f5e1008310611099576305f5e100830492506008015b61271083106110ad57612710830492506004015b606483106110bf576064830492506002015b600a831061043d5760010192915050565b60006110dc84846109c9565b9050600019811461114457818110156111375760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610647565b6111448484848403610b69565b50505050565b6001600160a01b0383166111ae5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610647565b6001600160a01b0382166112105760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610647565b6001600160a01b038316600090815260c96020526040902054818110156112885760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610647565b6001600160a01b03808516600081815260c9602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906112e89086815260200190565b60405180910390a3611144565b600054610100900460ff1661131c5760405162461bcd60e51b8152600401610647906117c4565b6107736113dc565b600054610100900460ff1661134b5760405162461bcd60e51b8152600401610647906117c4565b610773611409565b6001600160a01b03811661137a57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166113c35760405162461bcd60e51b8152600401610647906117c4565b60cc6113cf838261187a565b5060cd610fe5828261187a565b600054610100900460ff166114035760405162461bcd60e51b8152600401610647906117c4565b60018055565b600054610100900460ff166114305760405162461bcd60e51b8152600401610647906117c4565b61077333610e67565b6001600160a01b0381168114610a6a57600080fd5b60006020828403121561146057600080fd5b813561047c81611439565b60005b8381101561148657818101518382015260200161146e565b50506000910152565b60208152600082518060208401526114ae81604085016020870161146b565b601f01601f19169190910160400192915050565b600080604083850312156114d557600080fd5b82356114e081611439565b946020939093013593505050565b60008060006060848603121561150357600080fd5b833561150e81611439565b9250602084013561151e81611439565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261155657600080fd5b813567ffffffffffffffff808211156115715761157161152f565b604051601f8301601f19908116603f011681019082821181831017156115995761159961152f565b816040528381528660208588010111156115b257600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c087890312156115eb57600080fd5b86356115f681611439565b9550602087013561160681611439565b945060408701359350606087013560ff8116811461162357600080fd5b9250608087013567ffffffffffffffff8082111561164057600080fd5b61164c8a838b01611545565b935060a089013591508082111561166257600080fd5b5061166f89828a01611545565b9150509295509295509295565b8035801515811461168c57600080fd5b919050565b6000806000606084860312156116a657600080fd5b83359250602084013591506116bd6040850161167c565b90509250925092565b600080604083850312156116d957600080fd5b823591506116e96020840161167c565b90509250929050565b6000806040838503121561170557600080fd5b823561171081611439565b9150602083013561172081611439565b809150509250929050565b6000835161173d81846020880161146b565b6241c55b60e71b908301908152835161175d81600484016020880161146b565b01600401949350505050565b8082018082111561043d57634e487b7160e01b600052601160045260246000fd5b600181811c9082168061179e57607f821691505b6020821081036117be57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561182157600080fd5b815161047c81611439565b601f821115610fe557600081815260208120601f850160051c810160208610156118535750805b601f850160051c820191505b818110156118725782815560010161185f565b505050505050565b815167ffffffffffffffff8111156118945761189461152f565b6118a8816118a2845461178a565b8461182c565b602080601f8311600181146118dd57600084156118c55750858301515b600019600386901b1c1916600185901b178555611872565b600085815260208120601f198616915b8281101561190c578886015182559484019460019091019084016118ed565b508582101561192a5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220b40c6ab2d2ac6f02bd81640104801f3a38058209c3426b02583ae83cd4f9626164736f6c63430008140033a264697066735822122051da8881de7c8127cafb93733e67495f9cf4eb99b2d5f043b163acb59a7c9c5c64736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000002" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000003": { + "storage": {}, + "code": "0x6080604052600436106100ab5760003560e01c80638da5cb5b116100645780638da5cb5b146101c0578063a86f9d9e146101de578063ba0bbd95146101fe578063d73bb3d01461021e578063f2fde38b1461023e578063fe9fbb801461025e57600080fd5b80630652b57a146100f457806319ab453c146101145780632d1fb389146101345780633ab76e9f146101545780636c6563f61461018b578063715018a6146101ab57600080fd5b366100ef5747158015906100cf575033600090815260c9602052604090205460ff16155b156100ed57604051634fa3f24560e01b815260040160405180910390fd5b005b600080fd5b34801561010057600080fd5b506100ed61010f366004610a90565b6102a7565b34801561012057600080fd5b506100ed61012f366004610a90565b61032a565b34801561014057600080fd5b506100ed61014f366004610ac2565b610442565b34801561016057600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019757600080fd5b5061016e6101a6366004610af7565b6104fb565b3480156101b757600080fd5b506100ed610512565b3480156101cc57600080fd5b506065546001600160a01b031661016e565b3480156101ea57600080fd5b5061016e6101f9366004610b2c565b610526565b34801561020a57600080fd5b506100ed610219366004610b4f565b610533565b34801561022a57600080fd5b506100ed610239366004610b7b565b6105f1565b34801561024a57600080fd5b506100ed610259366004610a90565b610674565b34801561026a57600080fd5b50610297610279366004610a90565b6001600160a01b0316600090815260c9602052604090205460ff1690565b6040519015158152602001610182565b6102af6106ea565b6001600160a01b0381166102d657604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff161580801561034a5750600054600160ff909116105b806103645750303b158015610364575060005460ff166001145b6103cc5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156103ef576000805461ff0019166101001790555b6103f882610744565b801561043e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b61044a6106ea565b6001600160a01b038216158061047e57506001600160a01b038216600090815260c9602052604090205460ff161515811515145b1561049c57604051631bebdfa760e21b815260040160405180910390fd5b6001600160a01b038216600081815260c96020908152604091829020805460ff191685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b600061050884848461075d565b90505b9392505050565b61051a6106ea565b6105246000610811565b565b600061050b46848461075d565b33600090815260c9602052604090205460ff1661056357604051634fa3f24560e01b815260040160405180910390fd5b61056b610863565b6001600160a01b0382166105925760405163687563df60e01b815260040160405180910390fd5b6105a56001600160a01b038316826108bc565b816001600160a01b03167f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e826040516105e091815260200190565b60405180910390a261043e60018055565b33600090815260c9602052604090205460ff1661062157604051634fa3f24560e01b815260040160405180910390fd5b610629610863565b61063333826108bc565b60405181815233907f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e9060200160405180910390a261067160018055565b50565b61067c6106ea565b6001600160a01b0381166106e15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103c3565b61067181610811565b6065546001600160a01b031633146105245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c3565b61074c61097d565b6107546109ac565b610671816109db565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156107ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d29190610b94565b9050811580156107e957506001600160a01b038116155b1561050b57604051631467050360e21b815260048101859052602481018490526044016103c3565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6002600154036108b55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103c3565b6002600155565b8015806108d057506001600160a01b038216155b156108d9575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610926576040519150601f19603f3d011682016040523d82523d6000602084013e61092b565b606091505b50509050806109725760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016103c3565b505050565b60018055565b600054610100900460ff166109a45760405162461bcd60e51b81526004016103c390610bb1565b610524610a24565b600054610100900460ff166109d35760405162461bcd60e51b81526004016103c390610bb1565b610524610a4b565b6001600160a01b038116610a0257604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166109775760405162461bcd60e51b81526004016103c390610bb1565b600054610100900460ff16610a725760405162461bcd60e51b81526004016103c390610bb1565b61052433610811565b6001600160a01b038116811461067157600080fd5b600060208284031215610aa257600080fd5b813561050b81610a7b565b80358015158114610abd57600080fd5b919050565b60008060408385031215610ad557600080fd5b8235610ae081610a7b565b9150610aee60208401610aad565b90509250929050565b600080600060608486031215610b0c57600080fd5b8335925060208401359150610b2360408501610aad565b90509250925092565b60008060408385031215610b3f57600080fd5b82359150610aee60208401610aad565b60008060408385031215610b6257600080fd5b8235610b6d81610a7b565b946020939093013593505050565b600060208284031215610b8d57600080fd5b5035919050565b600060208284031215610ba657600080fd5b815161050b81610a7b565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d1f620816e429aef5462d90b937779e4a09a43cf61a7434dba633ff2bfa8098364736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xa738d3397c1eb96f671d7e4bd29cabbfa1a9c9ebc0db4142aee17809c43ab720": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000003" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0xffffffffffffff21f494c589bfffffff" + }, + "0x0000777700000000000000000000000000000007": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80636c6563f6116100715780636c6563f614610162578063715018a6146101755780638da5cb5b1461017d578063a86f9d9e1461018e578063f2fde38b146101a1578063f8f3f844146101b457600080fd5b80630652b57a146100b957806319ab453c146100ce57806332676bc6146100e15780633ab76e9f146101095780635221f6131461012e57806366ca2bc014610141575b600080fd5b6100cc6100c7366004611a18565b6101e0565b005b6100cc6100dc366004611a18565b610263565b6100f46100ef366004611a35565b61037b565b60405190151581526020015b60405180910390f35b6097546001600160a01b03165b6040516001600160a01b039091168152602001610100565b6100f461013c366004611a61565b6103ed565b61015461014f366004611af7565b61055d565b604051908152602001610100565b610116610170366004611b25565b6105a2565b6100cc6105b9565b6065546001600160a01b0316610116565b61011661019c366004611b5a565b6105cd565b6100cc6101af366004611a18565b6105da565b6101546101c2366004611a35565b6040805192835260208301919091526034600c830120918101905290565b6101e8610653565b6001600160a01b03811661020f57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff16158080156102835750600054600160ff909116105b8061029d5750303b15801561029d575060005460ff166001145b6103055760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610328576000805461ff0019166101001790555b610331826106ad565b8015610377576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006001600160a01b0383166103a4576040516354cdfc8d60e11b815260040160405180910390fd5b60008290036103c65760405163014f1da760e21b815260040160405180910390fd5b5060408051838152602081018390526034600c820120908201909152546001145b92915050565b600046860361040f5760405163e822b48d60e01b815260040160405180910390fd5b6001600160a01b038516610436576040516354cdfc8d60e11b815260040160405180910390fd5b60008490036104585760405163014f1da760e21b815260040160405180910390fd5b600061046683850185611bf6565b9050600061047d647461696b6f60d81b60006105cd565b8251604051632e24533960e21b81526001600160a01b03929092169163b8914ce4916104af9160040190815260200190565b602060405180830381865afa1580156104cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f09190611cbd565b60408051898152602081018990526034600c820120818301909252606081019190915290915061055190608001604051602081830303815290604052604051806040016040528060018152602001600160f81b8152508460200151846106c6565b98975050505050505050565b600081810361057f5760405163014f1da760e21b815260040160405180910390fd5b506040805133815260208101929092526034600c83012091810190526001815590565b60006105af8484846106ea565b90505b9392505050565b6105c1610653565b6105cb600061079e565b565b60006105b24684846106ea565b6105e2610653565b6001600160a01b0381166106475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016102fc565b6106508161079e565b50565b6065546001600160a01b031633146105cb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102fc565b6106b56107f0565b6106bd61081f565b6106508161084e565b6000806106d286610897565b90506106e0818686866108c9565b9695505050505050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa15801561073b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075f9190611cd6565b90508115801561077657506001600160a01b038116155b156105b257604051631467050360e21b815260048101859052602481018490526044016102fc565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166108175760405162461bcd60e51b81526004016102fc90611cf3565b6105cb610906565b600054610100900460ff166108465760405162461bcd60e51b81526004016102fc90611cf3565b6105cb610933565b6001600160a01b03811661087557604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b606081805190602001206040516020016108b391815260200190565b6040516020818303038152906040529050919050565b60008060006108d9878686610963565b915091508180156108fb57508051602080830191909120875191880191909120145b979650505050505050565b600054610100900460ff1661092d5760405162461bcd60e51b81526004016102fc90611cf3565b60018055565b600054610100900460ff1661095a5760405162461bcd60e51b81526004016102fc90611cf3565b6105cb3361079e565b60006060600061097285610a3e565b90506000806000610984848a89610b37565b815192955090935091501580806109985750815b6109e45760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e00000000000060448201526064016102fc565b600081610a005760405180602001604052806000815250610a2c565b610a2c86610a0f600188611d54565b81518110610a1f57610a1f611d67565b6020026020010151610f57565b919b919a509098505050505050505050565b60606000610a4b83610f7e565b90506000815167ffffffffffffffff811115610a6957610a69611b86565b604051908082528060200260200182016040528015610aae57816020015b6040805180820190915260608082526020820152815260200190600190039081610a875790505b50905060005b8251811015610b2f576000610ae1848381518110610ad457610ad4611d67565b6020026020010151610fb1565b90506040518060400160405280610af783610f7e565b815260200182815250838381518110610b1257610b12611d67565b60200260200101819052505080610b2890611d7d565b9050610ab4565b509392505050565b600060606000806000610b4987611041565b90506000869050600080610b70604051806040016040528060608152602001606081525090565b60005b8c51811015610f2f578c8181518110610b8e57610b8e611d67565b602002602001015191508284610ba49190611d96565b9350610bb1600188611d96565b965083600003610c0e578482602001518051906020012014610c095760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b60448201526064016102fc565b610cd0565b602082602001515110610c75578482602001518051906020012014610c095760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c2068617368000000000060448201526064016102fc565b84610c83836020015161117a565b14610cd05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f6465206861736800000000000060448201526064016102fc565b610cdc60106001611da9565b60ff1682600001515103610d4a5785518414610f2f576000868581518110610d0657610d06611d67565b01602001518351805160f89290921c925060009183908110610d2a57610d2a611d67565b60200260200101519050610d3d816111a2565b9650600194505050610f1f565b81515160011901610ed7576000610d60836111d8565b9050600081600081518110610d7757610d77611d67565b016020015160f81c90506000610d8e600283611dc2565b610d99906002611df2565b90506000610daa848360ff166111fc565b90506000610db88b8a6111fc565b90506000610dc68383611232565b905060ff851660021480610ddd575060ff85166003145b15610e1757808351148015610df25750808251145b15610e0457610e01818b611d96565b99505b50600160ff1b9950610f2f945050505050565b60ff85161580610e2a575060ff85166001145b15610e805782518114610e4a5750600160ff1b9950610f2f945050505050565b610e718860000151600181518110610e6457610e64611d67565b60200260200101516111a2565b9a509750610f1f945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b60648201526084016102fc565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e00000060448201526064016102fc565b610f2881611d7d565b9050610b73565b50600160ff1b841486610f4287866111fc565b909e909d50909b509950505050505050505050565b805180516060916103e791610f6e90600190611d54565b81518110610ad457610ad4611d67565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906103e7906112ac565b60606000806000610fc185611498565b919450925090506000816001811115610fdc57610fdc611e0b565b146110295760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e000000000000000060448201526064016102fc565b611038856020015184846117e2565b95945050505050565b60606000825160026110539190611e21565b67ffffffffffffffff81111561106b5761106b611b86565b6040519080825280601f01601f191660200182016040528015611095576020820181803683370190505b50905060005b83518110156111735760048482815181106110b8576110b8611d67565b01602001516001600160f81b031916901c826110d5836002611e21565b815181106110e5576110e5611d67565b60200101906001600160f81b031916908160001a905350601084828151811061111057611110611d67565b0160200151611122919060f81c611dc2565b60f81b82611131836002611e21565b61113c906001611d96565b8151811061114c5761114c611d67565b60200101906001600160f81b031916908160001a90535061116c81611d7d565b905061109b565b5092915050565b600060208251101561118e57506020015190565b818060200190518101906103e79190611cbd565b600060606020836000015110156111c3576111bc8361188b565b90506111cf565b6111cc83610fb1565b90505b6105b28161117a565b60606103e76111f78360000151600081518110610ad457610ad4611d67565b611041565b60608251821061121b57506040805160208101909152600081526103e7565b6105b2838384865161122d9190611d54565b611896565b6000805b8084511180156112465750808351115b8015611297575082818151811061125f5761125f611d67565b602001015160f81c60f81b6001600160f81b03191684828151811061128657611286611d67565b01602001516001600160f81b031916145b156105b2576112a581611d7d565b9050611236565b60606000806112ba84611498565b919350909150600190508160018111156112d6576112d6611e0b565b146113235760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e00000000000000000060448201526064016102fc565b6040805160208082526104208201909252600091816020015b604080518082019091526000808252602082015281526020019060019003908161133c5790505090506000835b865181101561148d57602082106113d55760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b60648201526084016102fc565b6000806114126040518060400160405280858c600001516113f69190611d54565b8152602001858c6020015161140b9190611d96565b9052611498565b50915091506040518060400160405280838361142e9190611d96565b8152602001848b602001516114439190611d96565b81525085858151811061145857611458611d67565b602090810291909101015261146e600185611d96565b935061147a8183611d96565b6114849084611d96565b92505050611369565b508152949350505050565b6000806000808460000151116114f05760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e000000000000000060448201526064016102fc565b6020840151805160001a607f81116115155760006001600094509450945050506117db565b60b7811161159157600061152a608083611d54565b90508087600001511161157f5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e0000000000000060448201526064016102fc565b600195509350600092506117db915050565b60bf81116116805760006115a660b783611d54565b9050808760000151116115fb5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e0060448201526064016102fc565b600183015160208290036101000a90046116158183611d96565b8851116116645760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e000000000000000060448201526064016102fc565b61166f826001611d96565b96509450600093506117db92505050565b60f781116116fb57600061169560c083611d54565b9050808760000151116116ea5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e00000000000000000060448201526064016102fc565b6001955093508492506117db915050565b600061170860f783611d54565b90508087600001511161175d5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e00000060448201526064016102fc565b600183015160208290036101000a90046117778183611d96565b8851116117bf5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b60448201526064016102fc565b6117ca826001611d96565b96509450600193506117db92505050565b9193909250565b606060008267ffffffffffffffff8111156117ff576117ff611b86565b6040519080825280601f01601f191660200182016040528015611829576020820181803683370190505b509050805160000361183c5790506105b2565b8484016020820160005b8581101561185e578281015182820152602001611846565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606103e7826119ed565b6060816118a481601f611d96565b10156118e35760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102fc565b826118ee8382611d96565b101561192d5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102fc565b6119378284611d96565b8451101561197b5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016102fc565b60608215801561199a57604051915060008252602082016040526119e4565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119d35780518352602092830192016119bb565b5050858452601f01601f1916604052505b50949350505050565b60606103e78260200151600084600001516117e2565b6001600160a01b038116811461065057600080fd5b600060208284031215611a2a57600080fd5b81356105b281611a03565b60008060408385031215611a4857600080fd5b8235611a5381611a03565b946020939093013593505050565b600080600080600060808688031215611a7957600080fd5b853594506020860135611a8b81611a03565b935060408601359250606086013567ffffffffffffffff80821115611aaf57600080fd5b818801915088601f830112611ac357600080fd5b813581811115611ad257600080fd5b896020828501011115611ae457600080fd5b9699959850939650602001949392505050565b600060208284031215611b0957600080fd5b5035919050565b80358015158114611b2057600080fd5b919050565b600080600060608486031215611b3a57600080fd5b8335925060208401359150611b5160408501611b10565b90509250925092565b60008060408385031215611b6d57600080fd5b82359150611b7d60208401611b10565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bbf57611bbf611b86565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bee57611bee611b86565b604052919050565b60006020808385031215611c0957600080fd5b823567ffffffffffffffff80821115611c2157600080fd5b9084019060408287031215611c3557600080fd5b611c3d611b9c565b823581528383013582811115611c5257600080fd5b80840193505086601f840112611c6757600080fd5b823582811115611c7957611c79611b86565b611c8b601f8201601f19168601611bc5565b92508083528785828601011115611ca157600080fd5b8085850186850137600090830185015292830152509392505050565b600060208284031215611ccf57600080fd5b5051919050565b600060208284031215611ce857600080fd5b81516105b281611a03565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b818103818111156103e7576103e7611d3e565b634e487b7160e01b600052603260045260246000fd5b600060018201611d8f57611d8f611d3e565b5060010190565b808201808211156103e7576103e7611d3e565b60ff81811683821601908111156103e7576103e7611d3e565b600060ff831680611de357634e487b7160e01b600052601260045260246000fd5b8060ff84160691505092915050565b60ff82811682821603908111156103e7576103e7611d3e565b634e487b7160e01b600052602160045260246000fd5b80820281158282048414176103e7576103e7611d3e56fea2646970667358221220727b3b71bb6428f2b0ff827ceeabefd08ed4c1ffd6ad882c5d137fbe8f96be8064736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000007": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000007" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220caef1c2a647344b8936c2def885861b955c9b56ccb762c5243ac8ec49af2096f64736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000003e8000", + "0xc4fd933fc30203af5f8bd19ad30e064c96642a369b9fc4288ea95569541f4034": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x967c153683def525608ec6efe0cac3319a9c97a6d4164fb43765c79311abffdc": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x5de52a798624bd714aafa39067b28145e3708f46d26ac1d8a415c99cb44977ab": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x29f6d6ec0904737d43c119104bcf9427181549a0e10faeefa218e436001011fd": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069c565b60405180910390f35b6100df6100da366004610706565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610730565b61024c565b604051601281526020016100c3565b6100df610131366004610706565b610270565b6100f361014436600461076c565b6001600160a01b031660009081526020819052604090205490565b6100b6610292565b6100df610175366004610706565b6102a1565b6100df610188366004610706565b610321565b6100f361019b36600461078e565b61032f565b6060600380546101af906107c1565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c1565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b60003361024081858561035a565b60019150505b92915050565b60003361025a85828561047e565b6102658585856104f8565b506001949350505050565b600033610240818585610283838361032f565b61028d91906107fb565b61035a565b6060600480546101af906107c1565b600033816102af828661032f565b9050838110156103145760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b610265828686840361035a565b6000336102408185856104f8565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103bc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161030b565b6001600160a01b03821661041d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161030b565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061048a848461032f565b905060001981146104f257818110156104e55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161030b565b6104f2848484840361035a565b50505050565b6001600160a01b03831661055c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161030b565b6001600160a01b0382166105be5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161030b565b6001600160a01b038316600090815260208190526040902054818110156106365760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161030b565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f2565b600060208083528351808285015260005b818110156106c9578581018301518582016040015282016106ad565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461070157600080fd5b919050565b6000806040838503121561071957600080fd5b610722836106ea565b946020939093013593505050565b60008060006060848603121561074557600080fd5b61074e846106ea565b925061075c602085016106ea565b9150604084013590509250925092565b60006020828403121561077e57600080fd5b610787826106ea565b9392505050565b600080604083850312156107a157600080fd5b6107aa836106ea565b91506107b8602084016106ea565b90509250929050565b600181811c908216806107d557607f821691505b6020821081036107f557634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561024657634e487b7160e01b600052601160045260246000fdfea26469706673582212200c6a590d0220261e9ad2a153910ca40f21f69a425e5af92fee3a769ffc07753764736f6c63430008140033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/grimsvotn.json b/crates/primitives/res/genesis/taiko/grimsvotn.json new file mode 100644 index 000000000000..c1321a5ac33e --- /dev/null +++ b/crates/primitives/res/genesis/taiko/grimsvotn.json @@ -0,0 +1,148 @@ +{ + "0x19B4F9C381C7927FE33D853e48b560141A380C44": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x09d4121CD4123F039390c7f5e99b15BED5e07222": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x9E5da4B6D25Ee5A68aa8c29B6B87C82f7F463893": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x5075901Fdd1d57Ca754472cb94967f564bA7dc6E": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063a54274621461003a575b600080fd5b61004d61004836600461173e565b610061565b604051901515815260200160405180910390f35b600080806100718486018661188e565b6040516bffffffffffffffffffffffff1960608c901b166020820152919350915060009081906100b490603401604051602081830303815290604052858d610184565b915091508161010a5760405162461bcd60e51b815260206004820152601960248201527f4c54503a696e76616c6964206163636f756e742070726f6f660000000000000060448201526064015b60405180910390fd5b6000610115826101ad565b9050600061013c8260028151811061012f5761012f6118f2565b60200260200101516101e6565b90506101738b60405160200161015491815260200190565b60405160208183030381529060405261016c8c6102e9565b87846102fc565b9d9c50505050505050505050505050565b60006060600061019386610316565b90506101a0818686610348565b9250925050935093915050565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906101e090610423565b92915050565b600060218260000151111561023d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b600080600061024b8561060f565b91945092509050600081600181111561026657610266611908565b146102b35760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b60008386602001516102c59190611934565b805190915060208410156102df5760208490036101000a90045b9695505050505050565b60606101e06102f783610959565b610a8d565b60008061030886610316565b90506102df81868686610afc565b6060818051906020012060405160200161033291815260200190565b6040516020818303038152906040529050919050565b60006060600061035785610b39565b90506000806000610369848a89610c32565b8151929550909350915015808061037d5750815b6103c95760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610101565b6000816103e55760405180602001604052806000815250610411565b610411866103f4600188611947565b81518110610404576104046118f2565b6020026020010151611052565b919b919a509098505050505050505050565b60606000806104318461060f565b9193509091506001905081600181111561044d5761044d611908565b1461049a5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610101565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816104b35790505090506000835b8651811015610604576020821061054c5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b6064820152608401610101565b6000806105896040518060400160405280858c6000015161056d9190611947565b8152602001858c602001516105829190611934565b905261060f565b5091509150604051806040016040528083836105a59190611934565b8152602001848b602001516105ba9190611934565b8152508585815181106105cf576105cf6118f2565b60209081029190910101526105e5600185611934565b93506105f18183611934565b6105fb9084611934565b925050506104e0565b508152949350505050565b6000806000808460000151116106675760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610101565b6020840151805160001a607f811161068c576000600160009450945094505050610952565b60b781116107085760006106a1608083611947565b9050808760000151116106f65760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610101565b60019550935060009250610952915050565b60bf81116107f757600061071d60b783611947565b9050808760000151116107725760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610101565b600183015160208290036101000a900461078c8183611934565b8851116107db5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610101565b6107e6826001611934565b965094506000935061095292505050565b60f7811161087257600061080c60c083611947565b9050808760000151116108615760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610101565b600195509350849250610952915050565b600061087f60f783611947565b9050808760000151116108d45760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610101565b600183015160208290036101000a90046108ee8183611934565b8851116109365760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b6044820152606401610101565b610941826001611934565b965094506001935061095292505050565b9193909250565b606060008260405160200161097091815260200190565b604051602081830303815290604052905060005b60208110156109c55781818151811061099f5761099f6118f2565b01602001516001600160f81b0319166000036109c5576109be8161195a565b9050610984565b60006109d2826020611947565b67ffffffffffffffff8111156109ea576109ea6117eb565b6040519080825280601f01601f191660200182016040528015610a14576020820181803683370190505b50905060005b8151811015610a84578383610a2e8161195a565b945081518110610a4057610a406118f2565b602001015160f81c60f81b828281518110610a5d57610a5d6118f2565b60200101906001600160f81b031916908160001a905350610a7d8161195a565b9050610a1a565b50949350505050565b60608082516001148015610abb5750608083600081518110610ab157610ab16118f2565b016020015160f81c105b15610ac75750816101e0565b610ad383516080611079565b83604051602001610ae59291906119a3565b604051602081830303815290604052905092915050565b6000806000610b0c878686610348565b91509150818015610b2e57508051602080830191909120875191880191909120145b979650505050505050565b60606000610b46836101ad565b90506000815167ffffffffffffffff811115610b6457610b646117eb565b604051908082528060200260200182016040528015610ba957816020015b6040805180820190915260608082526020820152815260200190600190039081610b825790505b50905060005b8251811015610c2a576000610bdc848381518110610bcf57610bcf6118f2565b6020026020010151611223565b90506040518060400160405280610bf2836101ad565b815260200182815250838381518110610c0d57610c0d6118f2565b60200260200101819052505080610c239061195a565b9050610baf565b509392505050565b600060606000806000610c44876112b3565b90506000869050600080610c6b604051806040016040528060608152602001606081525090565b60005b8c5181101561102a578c8181518110610c8957610c896118f2565b602002602001015191508284610c9f9190611934565b9350610cac600188611934565b965083600003610d09578482602001518051906020012014610d045760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b6044820152606401610101565b610dcb565b602082602001515110610d70578482602001518051906020012014610d045760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610101565b84610d7e83602001516113ec565b14610dcb5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610101565b610dd7601060016119c0565b60ff1682600001515103610e45578551841461102a576000868581518110610e0157610e016118f2565b01602001518351805160f89290921c925060009183908110610e2557610e256118f2565b60200260200101519050610e3881611414565b965060019450505061101a565b81515160011901610fd2576000610e5b8361144a565b9050600081600081518110610e7257610e726118f2565b016020015160f81c90506000610e896002836119ef565b610e94906002611a11565b90506000610ea5848360ff1661146e565b90506000610eb38b8a61146e565b90506000610ec183836114a4565b905060ff851660021480610ed8575060ff85166003145b15610f1257808351148015610eed5750808251145b15610eff57610efc818b611934565b99505b50600160ff1b995061102a945050505050565b60ff85161580610f25575060ff85166001145b15610f7b5782518114610f455750600160ff1b995061102a945050505050565b610f6c8860000151600181518110610f5f57610f5f6118f2565b6020026020010151611414565b9a50975061101a945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b6064820152608401610101565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610101565b6110238161195a565b9050610c6e565b50600160ff1b84148661103d878661146e565b909e909d50909b509950505050505050505050565b805180516060916101e09161106990600190611947565b81518110610bcf57610bcf6118f2565b60608060388410156110e057604080516001808252818301909252906020820181803683370190505090506110ae83856119c0565b60f81b816000815181106110c4576110c46118f2565b60200101906001600160f81b031916908160001a90535061121c565b600060015b6110ef8187611a2a565b15611112576110fd8261195a565b915061110b61010082611a3e565b90506110e5565b61111d826001611934565b67ffffffffffffffff811115611135576111356117eb565b6040519080825280601f01601f19166020018201604052801561115f576020820181803683370190505b50925061116c85836119c0565b6111779060376119c0565b60f81b8360008151811061118d5761118d6118f2565b60200101906001600160f81b031916908160001a905350600190505b818111611219576101006111bd8284611947565b6111c990610100611b39565b6111d39088611a2a565b6111dd9190611b45565b60f81b8382815181106111f2576111f26118f2565b60200101906001600160f81b031916908160001a9053506112128161195a565b90506111a9565b50505b9392505050565b606060008060006112338561060f565b91945092509050600081600181111561124e5761124e611908565b1461129b5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610101565b6112aa8560200151848461151e565b95945050505050565b60606000825160026112c59190611a3e565b67ffffffffffffffff8111156112dd576112dd6117eb565b6040519080825280601f01601f191660200182016040528015611307576020820181803683370190505b50905060005b83518110156113e557600484828151811061132a5761132a6118f2565b01602001516001600160f81b031916901c82611347836002611a3e565b81518110611357576113576118f2565b60200101906001600160f81b031916908160001a9053506010848281518110611382576113826118f2565b0160200151611394919060f81c6119ef565b60f81b826113a3836002611a3e565b6113ae906001611934565b815181106113be576113be6118f2565b60200101906001600160f81b031916908160001a9053506113de8161195a565b905061130d565b5092915050565b600060208251101561140057506020015190565b818060200190518101906101e09190611b59565b600060606020836000015110156114355761142e836115c7565b9050611441565b61143e83611223565b90505b61121c816113ec565b60606101e06114698360000151600081518110610bcf57610bcf6118f2565b6112b3565b60608251821061148d57506040805160208101909152600081526101e0565b61121c838384865161149f9190611947565b6115d2565b6000805b8084511180156114b85750808351115b801561150957508281815181106114d1576114d16118f2565b602001015160f81c60f81b6001600160f81b0319168482815181106114f8576114f86118f2565b01602001516001600160f81b031916145b1561121c576115178161195a565b90506114a8565b606060008267ffffffffffffffff81111561153b5761153b6117eb565b6040519080825280601f01601f191660200182016040528015611565576020820181803683370190505b509050805160000361157857905061121c565b8484016020820160005b8581101561159a578281015182820152602001611582565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606101e082611728565b6060816115e081601f611934565b101561161f5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610101565b8261162a8382611934565b10156116695760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610101565b6116738284611934565b845110156116b75760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610101565b6060821580156116d65760405191506000825260208201604052610a84565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561170f5780518352602092830192016116f7565b5050858452601f01601f19166040525050949350505050565b60606101e082602001516000846000015161151e565b60008060008060008060a0878903121561175757600080fd5b8635955060208701356001600160a01b038116811461177557600080fd5b94506040870135935060608701359250608087013567ffffffffffffffff808211156117a057600080fd5b818901915089601f8301126117b457600080fd5b8135818111156117c357600080fd5b8a60208285010111156117d557600080fd5b6020830194508093505050509295509295509295565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261181257600080fd5b813567ffffffffffffffff8082111561182d5761182d6117eb565b604051601f8301601f19908116603f01168101908282118183101715611855576118556117eb565b8160405283815286602085880101111561186e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156118a157600080fd5b823567ffffffffffffffff808211156118b957600080fd5b6118c586838701611801565b935060208501359150808211156118db57600080fd5b506118e885828601611801565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156101e0576101e061191e565b818103818111156101e0576101e061191e565b60006001820161196c5761196c61191e565b5060010190565b6000815160005b81811015611994576020818501810151868301520161197a565b50600093019283525090919050565b60006119b86119b28386611973565b84611973565b949350505050565b60ff81811683821601908111156101e0576101e061191e565b634e487b7160e01b600052601260045260246000fd5b600060ff831680611a0257611a026119d9565b8060ff84160691505092915050565b60ff82811682821603908111156101e0576101e061191e565b600082611a3957611a396119d9565b500490565b80820281158282048414176101e0576101e061191e565b600181815b80851115611a90578160001904821115611a7657611a7661191e565b80851615611a8357918102915b93841c9390800290611a5a565b509250929050565b600082611aa7575060016101e0565b81611ab4575060006101e0565b8160018114611aca5760028114611ad457611af0565b60019150506101e0565b60ff841115611ae557611ae561191e565b50506001821b6101e0565b5060208310610133831016604e8410600b8410161715611b13575081810a6101e0565b611b1d8383611a55565b8060001904821115611b3157611b3161191e565b029392505050565b600061121c8383611a98565b600082611b5457611b546119d9565b500690565b600060208284031215611b6b57600080fd5b505191905056fea264697066735822122067ddb2e3690f84d93d1a412860f6a463049c890e3ec168676bae8e8dc7ae3f3764736f6c63430008120033", + "balance": "0x0" + }, + "0x032847A8Cdd4487f83705f8D702743b60029AFDD": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220beb5d00868487ae13b8103480d5057ef120c70dcf0a0b13d4d29fb292e8aad5764736f6c63430008120033", + "balance": "0x0" + }, + "0x3e55D64323AD7E3287aa283475903D3fb3cA5098": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d80093ff59f040f5928ff201a3c212fa752b2ff8e0aea20a97ac0325ba978abb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000006": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063656b06a414610067578063715018a6146100b75780638da5cb5b146100c1578063decd8e39146100d2578063e1c7392a146100e5578063f2fde38b146100ed575b600080fd5b61009b610075366004610466565b60009182526065602090815260408084209284529190529020546001600160a01b031690565b6040516001600160a01b03909116815260200160405180910390f35b6100bf610100565b005b6033546001600160a01b031661009b565b6100bf6100e03660046104a4565b610114565b6100bf6101d4565b6100bf6100fb3660046104d9565b6102ea565b610108610360565b61011260006103ba565b565b61011c610360565b6001600160a01b0381163b15801561013c57506001600160a01b03811633145b1561015a57604051633baa901360e21b815260040160405180910390fd5b600083815260656020908152604080832085845282529182902080546001600160a01b038581166001600160a01b0319831681179093558451928352169181018290529091849186917fe41a6e8584d6e19a0dfc5f9331be4ebe61b5f025d45da164c9ca6ee9b837cea9910160405180910390a350505050565b600054610100900460ff16158080156101f45750600054600160ff909116105b8061020e5750303b15801561020e575060005460ff166001145b6102765760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610299576000805461ff0019166101001790555b6102a161040c565b80156102e7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6102f2610360565b6001600160a01b0381166103575760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161026d565b6102e7816103ba565b6033546001600160a01b031633146101125760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161026d565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166104335760405162461bcd60e51b815260040161026d906104fb565b610112600054610100900460ff1661045d5760405162461bcd60e51b815260040161026d906104fb565b610112336103ba565b6000806040838503121561047957600080fd5b50508035926020909101359150565b80356001600160a01b038116811461049f57600080fd5b919050565b6000806000606084860312156104b957600080fd5b83359250602084013591506104d060408501610488565b90509250925092565b6000602082840312156104eb57600080fd5b6104f482610488565b9392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220c5f7d4557009ba7141b3cd005aecb51648d30e5868346d5747a6722064e5e73664736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0xfeaa72fcc59acba6371da88141d071c9993f23312f54395296e3d9e5d39f0056": "0x0000000000000000000000001000777700000000000000000000000000000001", + "0x92fbb82d3d87ec735ae0893053f892b13be008dae0d966d083fc63772a95a170": "0x0000000000000000000000001000777700000000000000000000000000000004", + "0x2d89f514e5eeed612cd92d7cbfb188ecb4896b21769ef98030d34bcdb4c94bd9": "0x0000000000000000000000001000777700000000000000000000000000000002", + "0xc783d6d711f5c3d107daed8026e2089323b4661d3f4f92208071f4addcb75352": "0x0000000000000000000000001000777700000000000000000000000000000003", + "0xe4e56c450eba5c80504ff288920951a9da92b61b66c227cf06a8edb6e2edb548": "0x0000000000000000000000001000777700000000000000000000000000000007", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000006" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000001": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106101375760003560e01c80638f3ca30d116100b8578063c7b969081161007c578063c7b96908146102f5578063dac5df781461030f578063e1848cb014610318578063ee82ac5e1461032b578063f2fde38b1461033e578063f535bd561461035157600080fd5b80638f3ca30d146102905780639ee512f2146102a3578063a86f9d9e146102bc578063b8914ce4146102cf578063bacb386d146102e257600080fd5b8063539b8ade116100ff578063539b8ade14610207578063591aad8a146102325780636c6563f614610264578063715018a6146102775780638da5cb5b1461027f57600080fd5b80630652b57a1461013c57806310da3738146101515780633ab76e9f1461018b5780633d384a4b146101b05780634e755573146101c3575b600080fd5b61014f61014a3660046116d2565b61036b565b005b6101787f92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce3881565b6040519081526020015b60405180910390f35b6097546001600160a01b03165b6040516001600160a01b039091168152602001610182565b61014f6101be366004611706565b6103ee565b6101cb61065e565b6040805182516001600160801b031681526020808401516001600160401b03908116918301919091529282015190921690820152606001610182565b60cd5461021a906001600160401b031681565b6040516001600160401b039091168152602001610182565b61024561024036600461174c565b6106be565b6040805160ff9094168452602084019290925290820152606001610182565b610198610272366004611792565b6108f9565b61014f610910565b6065546001600160a01b0316610198565b61014f61029e3660046117c7565b610924565b61019871777735367b36bc9b61c50022d9d0700db4ec81565b6101986102ca366004611808565b610ce0565b6101786102dd366004611834565b610cf6565b6101786102f0366004611834565b610d32565b60cd5461021a90600160401b90046001600160401b031681565b61017860cb5481565b61017861032636600461184d565b610d6b565b610178610339366004611834565b610d8f565b61014f61034c3660046116d2565b610ddc565b60cd5461021a90600160801b90046001600160401b031681565b610373610e55565b6001600160a01b03811661039a57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b3371777735367b36bc9b61c50022d9d0700db4ec1461042057604051636494e9f760e01b815260040160405180910390fd5b600061042d6001436118a8565b9050804060008061043d84610eaf565b915091508160cb54146104765760cb54604051636340d9fb60e11b81526004810191909152602481018390526044015b60405180910390fd5b60cb819055600084815260c96020908152604080832086905560cd80546fffffffffffffffff00000000000000001916600160401b6001600160401b038c1690810291909117909155815180830183528c81528084018c815282865260ca8552948390209051815593516001949094019390935580518b81529182018a90527f7528bbd1cef0e5d13408706892a51ee8ef82bbf33d4ec0c37216f8beba71205b910160405180910390a260008061052b61065e565b905080604001516001600160401b03166000146105935760cd5461056590829061055e906001600160401b0316426118a8565b458a610f42565b60cd80546001600160401b03909216600160801b0267ffffffffffffffff60801b1990921691909117905591505b8148146105c657604051634083acad60e01b81526001600160401b0380841660048301524816602482015260440161046d565b60cd805467ffffffffffffffff1916426001600160401b03908116918217909255604080514384168152858416602082015245909316908301526060820152608081018690524460a08201524160c082015263ffffffff461660e08201527f4dcb01f99c4a2c27a16ab38d00ec92434f8231be81fa62e058f260d3c7156029906101000160405180910390a150505050505050505050565b6040805160608101825260008082526020820181905291810191909152506040805160608101825260cc546001600160801b03811682526001600160401b03600160801b820481166020840152600160c01b909104169181019190915290565b60008060008360ff166001141580156106db57508360ff16600214155b156106f95760405163bcd2d90d60e01b815260040160405180910390fd5b8360ff1660011461072a577fc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee561074c565b7f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817985b915060008460ff16600114610781577fad77eceea844778cb4376153fc8f06f12f1695df4585bf75bfb17ec19ce908186107a3565b7fb4a95509ce05fe8d45987859a067780d16a367c0e2cacf79cd301b93fb7179405b905060008560ff166001146107d8577f71620584f61c57e688bbd3fd7a39a036e588d962c4c830f3dacbc15c917e02f26107fa565b7f45b59254b0320fd853f3f38ac574999e91bd75fd5e6cab9c22c5e71fc6d276e45b82880192831001905060ff86166001036108345761082d8282600170014551231950b75fc4402da1732fc9bebe19610fde565b92506108a3565b61087c7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16108778484600170014551231950b75fc4402da1732fc9bebe19610fde565b61102d565b90925090506108a08282600170014551231950b75fc4402da1732fc9bebe19610fde565b92505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156108f0576108e78370014551231950b75fc4402da1732fc9bebe196118a8565b92506001851894505b50509250925092565b600061090684848461104c565b90505b9392505050565b610918610e55565b6109226000611100565b565b600054610100900460ff16158080156109445750600054600160ff909116105b8061095e5750303b15801561095e575060005460ff166001145b6109c15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161046d565b6000805460ff1916600117905580156109e4576000805461ff0019166101001790555b6001461115806109f8575063ffffffff4610155b15610a16576040516306cffa2760e01b815260040160405180910390fd5b6001431115610a3857604051635a0f9e4160e11b815260040160405180910390fd5b610a4860408301602084016118bb565b6001600160401b031615610c3c57610a6360208301836118bb565b6001600160401b03161580610a8e5750610a8360608301604084016118bb565b6001600160401b0316155b80610aaf5750610aa460808301606084016118bb565b6001600160401b0316155b80610ad05750610ac560a08301608084016118bb565b6001600160401b0316155b15610aee57604051639cc448b560e01b815260040160405180910390fd5b600080610b36610b0460608601604087016118bb565b610b1160208701876118bb565b610b2160808801606089016118bb565b610b3160a0890160808a016118bb565b611152565b91509150816001600160801b031660001480610b6257506001600160401b036001600160801b03831610155b80610b7457506001600160801b038116155b15610b9257604051639cc448b560e01b815260040160405180910390fd5b60cc80546001600160401b038416600160801b026001600160c01b03199091166001600160801b03841617179055610bd060408501602086016118bb565b60cc80546001600160401b0392909216600160c01b026001600160c01b039092169190911790556002610c0960608601604087016118bb565b610c1391906118ec565b60cd60106101000a8154816001600160401b0302191690836001600160401b0316021790555050505b60cd805467ffffffffffffffff1916426001600160401b0316179055610c6183611251565b610c6a43610eaf565b5060cb554315610c95576000610c816001436118a8565b600081815260c96020526040902090409055505b8015610cdb576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610ced46848461104c565b90505b92915050565b6000808215610d055782610d19565b60cd54600160401b90046001600160401b03165b600090815260ca60205260409020600101549392505050565b6000808215610d415782610d55565b60cd54600160401b90046001600160401b03165b600090815260ca60205260409020549392505050565b6000610d86610d7861065e565b8563ffffffff168585610f42565b50949350505050565b6000438210610da057506000919050565b4382108015610dba5750610db6610100436118a8565b8210155b15610dc457504090565b50600090815260c9602052604090205490565b919050565b610de4610e55565b6001600160a01b038116610e495760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161046d565b610e5281611100565b50565b6065546001600160a01b031633146109225760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161046d565b600080610eba61169d565b60005b60ff81108015610ed05750806001018510155b15610f02576000198186030180408360ff83066101008110610ef457610ef4611912565b602002015250600101610ebd565b5046611fe082015261200081209250834081610f1f60ff87611928565b6101008110610f3057610f30611912565b60200201526120009020919391925050565b600080806202bf206001600160401b03851611610f60576000610f67565b6202bf2084035b60cd546040890151919250600160801b90046001600160401b0390811681841601918116880290610fa49082610f9d858261126a565b0390611280565b9350505050610fc686602001516001600160401b031687600001518387611295565b915081600003610fd557600191505b94509492505050565b600060405160408152602080820152602060408201528460608201528560808201528360a08201528260c082015260208160e08360056107d05a03fa61102357600080fd5b5195945050505050565b6000806000198385098385029250828110838203039150509250929050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa15801561109d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c1919061193c565b9050811580156110d857506001600160a01b038116155b1561090957604051631467050360e21b8152600481018590526024810184905260440161046d565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080856001600160401b031660000361116e5761116e611959565b600061117b6002886118ec565b90506111996001600160401b038816680755bf798b4a1bf1e461196f565b92506111b86111b384886001600160401b03168489611295565b611354565b915060006111c884848489611295565b905060006111e28585856111dd8b6002611989565b611295565b90506000826111f3836127106119b4565b6111fd91906119cb565b9050806001600160401b0316876001600160401b031614611244576040516331c2ec2360e21b81526001600160401b0380891660048301528216602482015260440161046d565b5050505094509492505050565b6112596113c1565b6112616113f0565b610e528161141f565b60008183116112795781610ced565b5090919050565b600081831161128f5782610ced565b50919050565b60006001600160801b038516158015906112b757506001600160801b03841615155b6112c3576112c3611959565b60006001600160401b038316156112da57826112dd565b60015b905060006112f4856001600160401b031688611468565b9050600061131461130584886119df565b6001600160401b031689611468565b90506001600160801b0387166001600160401b03841661133484846118a8565b61133e91906119cb565b61134891906119cb565b98975050505050505050565b60006001600160801b038211156113bd5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b606482015260840161046d565b5090565b600054610100900460ff166113e85760405162461bcd60e51b815260040161046d90611a06565b6109226114ba565b600054610100900460ff166114175760405162461bcd60e51b815260040161046d90611a06565b6109226114e7565b6001600160a01b03811661144657604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60008061147e6001600160801b038416856119b4565b9050680755bf798b4a1bf1e481106114a9576040516372de381d60e01b815260040160405180910390fd5b6114b281611517565b949350505050565b600054610100900460ff166114e15760405162461bcd60e51b815260040161046d90611a06565b60018055565b600054610100900460ff1661150e5760405162461bcd60e51b815260040161046d90611a06565b61092233611100565b6000680248ce36a70cb26b3e19821361153257506000919050565b680755bf798b4a1bf1e5821261155b57604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b6d2c06887d92262d378b9593af35346c09791803c2923d5d9721c3da80929091056001605f1b0190921d6bb17217f7d1cf79abc9e3b39881029095039081018102606090811d6d019dd9374d4315c8464a395fc09881016c1bff318b126baa436ea9aeaffd19840102821d93840193016d29c9ad45cc0beb0a2ff097a7bab40192909202821d6dcf3c27b2e487711b467e90f19320016c22fcd1cffa6fa000f6e27eeca082018202831d6d022f98fbc368092c79210d196fa0018202831d6d13aaae3ba38de06adc25ebfacc0901820290921d6d624dcbeb5e25df590e409325888a01026d360d7aeea093263ec6495851bd9760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b604051806120000160405280610100906020820280368337509192915050565b6001600160a01b0381168114610e5257600080fd5b6000602082840312156116e457600080fd5b8135610909816116bd565b80356001600160401b0381168114610dd757600080fd5b6000806000806080858703121561171c57600080fd5b8435935060208501359250611733604086016116ef565b9150611741606086016116ef565b905092959194509250565b6000806040838503121561175f57600080fd5b82359150602083013560ff8116811461177757600080fd5b809150509250929050565b80358015158114610dd757600080fd5b6000806000606084860312156117a757600080fd5b83359250602084013591506117be60408501611782565b90509250925092565b60008082840360c08112156117db57600080fd5b83356117e6816116bd565b925060a0601f19820112156117fa57600080fd5b506020830190509250929050565b6000806040838503121561181b57600080fd5b8235915061182b60208401611782565b90509250929050565b60006020828403121561184657600080fd5b5035919050565b60008060006060848603121561186257600080fd5b833563ffffffff8116811461187657600080fd5b9250611884602085016116ef565b91506117be604085016116ef565b634e487b7160e01b600052601160045260246000fd5b81810381811115610cf057610cf0611892565b6000602082840312156118cd57600080fd5b610ced826116ef565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b0380841680611906576119066118d6565b92169190910492915050565b634e487b7160e01b600052603260045260246000fd5b600082611937576119376118d6565b500690565b60006020828403121561194e57600080fd5b8151610909816116bd565b634e487b7160e01b600052600160045260246000fd5b60006001600160801b0380841680611906576119066118d6565b6001600160401b038181168382160280821691908281146119ac576119ac611892565b505092915050565b8082028115828204841417610cf057610cf0611892565b6000826119da576119da6118d6565b500490565b6001600160401b038181168382160190808211156119ff576119ff611892565b5092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212203890f26859c50d4bcb2990b86955150cc1db102725f3e4bc015ad2ec3f168ef764736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000001": { + "storage": { + "0x00000000000000000000000000000000000000000000000000000000000000cb": "0xdec49b32a269dacf8af649c78ad8106484a218de96500f2e3cae7afa7871599b", + "0x00000000000000000000000000000000000000000000000000000000000000cc": "0x00000000001e8480000000022a83d6720000001c43c970ab8e4d088428ca4b6f", + "0x00000000000000000000000000000000000000000000000000000000000000cd": "0x000000000000000000000001b171ea0000000000000000000000000064707075", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000001" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000004": { + "storage": {}, + "code": "0x60806040526004361061012e5760003560e01c8063715018a6116100ab578063bac443e21161006f578063bac443e21461041b578063ce70f39b1461043b578063d0496d6a1461045b578063f2fde38b146104ca578063f9803919146104ea578063fee99b221461050a57600080fd5b8063715018a6146103955780638da5cb5b146103aa57806396e17852146103c8578063a4444efd146103db578063a86f9d9e146103fb57600080fd5b8063540be6a3116100f2578063540be6a3146102e75780635817b0c3146103075780635d0bd98614610335578063606b5b74146103555780636c6563f61461037557600080fd5b80630652b57a1461020357806319ab453c14610223578063343b643c146102435780633ab76e9f146102885780635075a9d4146102ba57600080fd5b366101fe5761014c6a1d1bdad95b97dd985d5b1d60aa1b600161052a565b6001600160a01b0316336001600160a01b03161415801561019757506101816a195d1a195c97dd985d5b1d60aa1b600161052a565b6001600160a01b0316336001600160a01b031614155b80156101c757506101b1647461696b6f60d81b600161052a565b6001600160a01b0316336001600160a01b031614155b80156101de57506065546001600160a01b03163314155b156101fc576040516345dd044560e11b815260040160405180910390fd5b005b600080fd5b34801561020f57600080fd5b506101fc61021e366004612b75565b610540565b34801561022f57600080fd5b506101fc61023e366004612b75565b6105c3565b34801561024f57600080fd5b5061027361025e366004612b92565b600090815260cd602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561029457600080fd5b506097546001600160a01b03165b6040516001600160a01b03909116815260200161027f565b3480156102c657600080fd5b506102da6102d5366004612b92565b6106db565b60405161027f9190612be3565b3480156102f357600080fd5b50610273610302366004612b92565b6106e6565b34801561031357600080fd5b50610327610322366004612c0a565b6106f2565b60405190815260200161027f565b34801561034157600080fd5b50610273610350366004612b92565b610705565b34801561036157600080fd5b50610327610370366004612b92565b610718565b34801561038157600080fd5b506102a2610390366004612c4c565b610723565b3480156103a157600080fd5b506101fc61073a565b3480156103b657600080fd5b506065546001600160a01b03166102a2565b6103276103d6366004612c0a565b61074e565b3480156103e757600080fd5b506102736103f6366004612ccd565b61077c565b34801561040757600080fd5b506102a2610416366004612d1f565b61052a565b34801561042757600080fd5b506101fc610436366004612d4f565b610794565b34801561044757600080fd5b50610273610456366004612ccd565b6107b8565b34801561046757600080fd5b50604080516060808201835260008083526020808401829052928401528251808201845260ca5480825260cb546001600160a01b0390811683860190815260cc54938701938452865192835251169381019390935251928201929092520161027f565b3480156104d657600080fd5b506101fc6104e5366004612b75565b6107c7565b3480156104f657600080fd5b506101fc610505366004612db7565b610840565b34801561051657600080fd5b506101fc610525366004612d4f565b61085e565b6000610537468484610874565b90505b92915050565b610548610928565b6001600160a01b03811661056f57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff16158080156105e35750600054600160ff909116105b806105fd5750303b1580156105fd575060005460ff166001145b6106655760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610688576000805461ff0019166101001790555b61069182610982565b80156106d7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061053a8261099b565b600061053a30836109c6565b600061053a61070083612f0d565b610aa7565b60006107113083610ad7565b5092915050565b600061053a82610b60565b6000610730848484610874565b90505b9392505050565b610742610928565b61074c6000610b9b565b565b6000610758610bed565b61076c60c93061076785612f0d565b610c46565b905061077760018055565b919050565b600061078b3086868686610f27565b95945050505050565b61079c610bed565b6107aa60c93085858561108a565b6107b360018055565b505050565b600061078b308686868661137b565b6107cf610928565b6001600160a01b0381166108345760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161065c565b61083d81610b9b565b50565b610848610bed565b61085560c9308484611600565b6106d760018055565b610866610bed565b6107aa60c930858585611838565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156108c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e9919061300e565b90508115801561090057506001600160a01b038116155b1561073357604051631467050360e21b8152600481018590526024810184905260440161065c565b6065546001600160a01b0316331461074c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161065c565b61098a611d37565b610992611d66565b61083d81611d95565b6000806109a783610b60565b80549091508060038111156109be576109be612bab565b949350505050565b604051635437cecf60e11b81526000906001600160a01b0384169063a86f9d9e906109f590849060040161302b565b602060405180830381865afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a36919061300e565b604051631933b5e360e11b8152306004820152602481018490526001600160a01b0391909116906332676bc690604401602060405180830381865afa158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610537919061304d565b600081604051602001610aba91906130ba565b604051602081830303815290604052805190602001209050919050565b600080836001600160a01b0316636c6563f68460016040518363ffffffff1660e01b8152600401610b099291906131b4565b602060405180830381865afa158015610b26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4a919061300e565b6001600160a01b03811615159590945092505050565b60006040518060400160405280600e81526020016d4d4553534147455f53544154555360901b81525082604051602001610aba9291906131d3565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600260015403610c3f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161065c565b6002600155565b60808101516000906001600160a01b0316610c74576040516301b1868360e71b815260040160405180910390fd5b600080610c85858560600151610ad7565b91509150811580610c995750468460600151145b15610cb75760405163e822b48d60e01b815260040160405180910390fd5b60a08401516001600160a01b03161580610ce65750806001600160a01b03168460a001516001600160a01b0316145b15610d045760405163b9ad6a0f60e01b815260040160405180910390fd5b60008461012001518561010001518660e00151610d21919061320b565b610d2b919061320b565b9050348114610d4d57604051632609a19760e21b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0388169063a86f9d9e90610d7d9060019060040161321e565b602060405180830381865afa158015610d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbe919061300e565b9050610dd36001600160a01b03821683611dde565b8754886000610de18361323d565b909155508652336020870152466040870152610dfc86610aa7565b604051635437cecf60e11b81529095506001600160a01b0388169063a86f9d9e90610e2c9060009060040161302b565b602060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d919061300e565b6001600160a01b03166366ca2bc0866040518263ffffffff1660e01b8152600401610e9a91815260200190565b6020604051808303816000875af1158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd9190613256565b50847f47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f387604051610f0e91906130ba565b60405180910390a2505050509392505050565b60018055565b600080866001600160a01b0316636c6563f68660006040518363ffffffff1660e01b8152600401610f599291906131b4565b602060405180830381865afa158015610f76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9a919061300e565b604051635437cecf60e11b81529091506001600160a01b0388169063a86f9d9e90610fca9060009060040161302b565b602060405180830381865afa158015610fe7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100b919061300e565b6001600160a01b0316635221f61386838988886040518663ffffffff1660e01b815260040161103e95949392919061326f565b602060405180830381865afa15801561105b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107f919061304d565b979650505050505050565b600061109c60a0850160808601612b75565b6001600160a01b0316036110c3576040516301b1868360e71b815260040160405180910390fd5b468360400135146110e75760405163e822b48d60e01b815260040160405180910390fd5b60006110f561070085612f0d565b600081815260048801602052604090205490915060ff16151560010361112e5760405163afde133560e01b815260040160405180910390fd5b61113f85828660600135868661137b565b61115c5760405163498b0b1d60e01b815260040160405180910390fd5b60008181526004870160205260408120805460ff1916600117905561118a61010086013560e087013561320b565b9050801561131f57604051635437cecf60e11b81526000906001600160a01b0388169063a86f9d9e906111c29060019060040161321e565b602060405180830381865afa1580156111df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611203919061300e565b90506001600160a01b03811615611298576001600160a01b03811663ba0bbd9561123360a0890160808a01612b75565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401600060405180830381600087803b15801561127b57600080fd5b505af115801561128f573d6000803e3d6000fd5b5050505061131d565b60006112aa60a0880160808901612b75565b6001600160a01b03168360405160006040518083038185875af1925050503d80600081146112f4576040519150601f19603f3d011682016040523d82523d6000602084013e6112f9565b606091505b505090508061131b5760405163f6664cf160e01b815260040160405180910390fd5b505b505b817fea00c741e39d1d9ab1c6703152d71f9da09a782ed4ae128414730dadbb9bd84761135160a0880160808901612b75565b604080516001600160a01b039092168252602082018590520160405180910390a250505050505050565b600046840361139d5760405163e822b48d60e01b815260040160405180910390fd5b60008590036113bf5760405163a6407c9360e01b815260040160405180910390fd5b60006113cd83850185613359565b604051635437cecf60e11b8152647461696b6f60d81b60048201526000602482018190529192506001600160a01b0389169063a86f9d9e90604401602060405180830381865afa158015611425573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611449919061300e565b8251610100015160405163bacb386d60e01b81526001600160801b0390911660048201526001600160a01b03919091169063bacb386d90602401602060405180830381865afa1580156114a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c49190613256565b90508015806114dd575081516114d990611e94565b8114155b156114ed5760009250505061078b565b815160600151604051633632b1fb60e11b8152735075901Fdd1d57Ca754472cb94967f564bA7dc6E9163a5427462916001600160a01b038c1690636c6563f69061153e908c906000906004016131b4565b602060405180830381865afa15801561155b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061157f919061300e565b6115888b610b60565b602087015160405160e086901b6001600160e01b03191681526115b3949392916003916004016134fd565b602060405180830381865af41580156115d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f4919061304d565b98975050505050505050565b610140820135158061160f5750805b156116555761162460a0830160808401612b75565b6001600160a01b0316336001600160a01b0316146116555760405163d7f4fc9f60e01b815260040160405180910390fd5b600061166361070084612f0d565b905060016116708261099b565b600381111561168157611681612bab565b1461169f57604051631f6646b560e01b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0386169063a86f9d9e906116cf9060019060040161321e565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611710919061300e565b90506001600160a01b0381161561178057604051630d73bb3d60e41b815261010085013560048201526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b15801561176757600080fd5b505af115801561177b573d6000803e3d6000fd5b505050505b61178c8685845a611eb9565b156117a15761179c826002612011565b611830565b8215611818576117b2826003612011565b6000806117c560e0870160c08801612b75565b6001600160a01b0316146117e8576117e360e0860160c08701612b75565b6117f8565b6117f860a0860160808701612b75565b90506118126001600160a01b038216610100870135611dde565b50611830565b6118306001600160a01b038216610100860135611dde565b505050505050565b61014083013515801561186c575061185660a0840160808501612b75565b6001600160a01b0316336001600160a01b031614155b1561188a5760405163398b635960e21b815260040160405180910390fd5b468360600135146118ae5760405163e822b48d60e01b815260040160405180910390fd5b60006118bc61070085612f0d565b905060006118c98261099b565b60038111156118da576118da612bab565b146118f857604051630cfafbf960e01b815260040160405180910390fd5b6000856001600160a01b0316636c6563f6866040013560006040518363ffffffff1660e01b815260040161192d9291906131b4565b602060405180830381865afa15801561194a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196e919061300e565b604051635437cecf60e11b81529091506001600160a01b0387169063a86f9d9e9061199e9060009060040161302b565b602060405180830381865afa1580156119bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119df919061300e565b6001600160a01b0316635221f6138660400135838588886040518663ffffffff1660e01b8152600401611a1695949392919061326f565b602060405180830381865afa158015611a33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a57919061304d565b611a74576040516314504c7360e31b815260040160405180910390fd5b6000610120860135611a8f61010088013560e089013561320b565b611a99919061320b565b90506000876001600160a01b031663a86f9d9e60016040518263ffffffff1660e01b8152600401611aca919061321e565b602060405180830381865afa158015611ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0b919061300e565b90506001600160a01b03811615801590611b255750600082115b15611b8557604051630d73bb3d60e41b8152600481018390526001600160a01b0382169063d73bb3d090602401600060405180830381600087803b158015611b6c57600080fd5b505af1158015611b80573d6000803e3d6000fd5b505050505b611bac60e0880135611b9d60a08a0160808b01612b75565b6001600160a01b031690611dde565b60008030611bc060c08b0160a08c01612b75565b6001600160a01b03161480611bed57506000611be260c08b0160a08c01612b75565b6001600160a01b0316145b15611c02575060029050610100880135611c79565b6000611c1460a08b0160808c01612b75565b6001600160a01b0316336001600160a01b031614611c3757896101400135611c39565b5a5b90506000611c498d8c8a85611eb9565b90508015611c5a5760029350611c76565b60019350611c766001600160a01b0386166101008d0135611dde565b50505b611c838683612011565b600080611c9660e08c0160c08d01612b75565b6001600160a01b031614611cb957611cb460e08b0160c08c01612b75565b611cc9565b611cc960a08b0160808c01612b75565b90506001600160a01b0381163303611d07576000611cec836101208d013561320b565b9050611d016001600160a01b03831682611dde565b50611d29565b611d16336101208c0135611dde565b611d296001600160a01b03821683611dde565b505050505050505050505050565b600054610100900460ff16611d5e5760405162461bcd60e51b815260040161065c90613530565b61074c61208a565b600054610100900460ff16611d8d5760405162461bcd60e51b815260040161065c90613530565b61074c6120b1565b6001600160a01b038116611dbc57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b801580611df257506001600160a01b038216155b15611dfb575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611e48576040519150601f19603f3d011682016040523d82523d6000602084013e611e4d565b606091505b50509050806107b35760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015260640161065c565b600080611eaa611ea58460006120e1565b612502565b80516020909101209392505050565b600081600003611edc57604051637f0e960960e11b815260040160405180910390fd5b6040518060600160405280848152602001856020016020810190611f009190612b75565b6001600160a01b039081168252604087810135602093840152835160018a0155918301516002890180546001600160a01b0319169190921617905501516003860155611f5260c0850160a08601612b75565b6001600160a01b031682610100860135611f7061016088018861357b565b604051611f7e9291906135c1565b600060405180830381858888f193505050503d8060008114611fbc576040519150601f19603f3d011682016040523d82523d6000602084013e611fc1565b606091505b505060408051606081018252600180825260208201819052600019919092018190528782018290556002880180546001600160a01b03191690921790915560039096019590955550929392505050565b80600381111561202357612023612bab565b61202c8361099b565b600381111561203d5761203d612bab565b146106d75761204c8282612546565b817f0af4d5247f6a4028d6699afb62871a76b398da1d1a626c8a9b90e0bd5f54c73c823360405161207e9291906135d1565b60405180910390a25050565b600054610100900460ff16610f215760405162461bcd60e51b815260040161065c90613530565b600054610100900460ff166120d85760405162461bcd60e51b815260040161065c90613530565b61074c33610b9b565b6102008201516060901561214c576120fa82601161320b565b6001600160401b0381111561211157612111612dfd565b60405190808252806020026020018201604052801561214457816020015b606081526020019060019003908161212f5790505b5090506121bb565b6101e083015115612162576120fa82601061320b565b61216d82600f61320b565b6001600160401b0381111561218457612184612dfd565b6040519080825280602002602001820160405280156121b757816020015b60608152602001906001900390816121a25790505b5090505b82516121c69061256f565b816000815181106121d9576121d96135f7565b60200260200101819052506121f1836020015161256f565b81600181518110612204576122046135f7565b602002602001018190525061221c8360400151612582565b8160028151811061222f5761222f6135f7565b6020026020010181905250612247836060015161256f565b8160038151811061225a5761225a6135f7565b6020026020010181905250612272836080015161256f565b81600481518110612285576122856135f7565b602002602001018190525061229d8360a0015161256f565b816005815181106122b0576122b06135f7565b60200260200101819052506122e78360c001516040516020016122d3919061360d565b6040516020818303038152906040526125ab565b816006815181106122fa576122fa6135f7565b60200260200101819052506123128360e0015161261a565b81600781518110612325576123256135f7565b60200260200101819052506123478361010001516001600160801b031661261a565b8160088151811061235a5761235a6135f7565b6020026020010181905250612373836101200151612628565b81600981518110612386576123866135f7565b602002602001018190525061239f836101400151612628565b81600a815181106123b2576123b26135f7565b60200260200101819052506123cb836101600151612628565b81600b815181106123de576123de6135f7565b60200260200101819052506123f78361018001516125ab565b81600c8151811061240a5761240a6135f7565b6020026020010181905250612423836101a0015161256f565b81600d81518110612436576124366135f7565b602002602001018190525061246d836101c001516040516020016122d3919060c09190911b6001600160c01b031916815260080190565b81600e81518110612480576124806135f7565b6020026020010181905250826101e001516000146124c5576124a6836101e0015161261a565b81600f815181106124b9576124b96135f7565b60200260200101819052505b6102008301511561053a576124de83610200015161256f565b816010815181106124f1576124f16135f7565b602002602001018190525092915050565b6060600061250f8361263f565b905061251d815160c0612774565b8160405160200161252f929190613642565b604051602081830303815290604052915050919050565b600061255183610b60565b9050600082600381111561256757612567612bab565b909155505050565b606061053a61257d8361291c565b6125ab565b604051606082811b6bffffffffffffffffffffffff191660208301529061053a906034016122d3565b606080825160011480156125d957506080836000815181106125cf576125cf6135f7565b016020015160f81c105b156125e557508161053a565b6125f183516080612774565b83604051602001612603929190613642565b604051602081830303815290604052905092915050565b606061053a61257d836129ce565b606061053a61257d836001600160401b03166129ce565b60608151600003612660576040805160008082526020820190925290610711565b6000805b83518110156126a55783818151811061267f5761267f6135f7565b60200260200101515182612693919061320b565b915061269e8161323d565b9050612664565b6000826001600160401b038111156126bf576126bf612dfd565b6040519080825280601f01601f1916602001820160405280156126e9576020820181803683370190505b50600092509050602081015b855183101561276b576000868481518110612712576127126135f7565b60200260200101519050600060208201905061273083828451612af8565b878581518110612742576127426135f7565b60200260200101515183612756919061320b565b92505050826127649061323d565b92506126f5565b50949350505050565b60608060388410156127db57604080516001808252818301909252906020820181803683370190505090506127a98385613671565b60f81b816000815181106127bf576127bf6135f7565b60200101906001600160f81b031916908160001a905350610537565b600060015b6127ea81876136a0565b1561280d576127f88261323d565b9150612806610100826136b4565b90506127e0565b61281882600161320b565b6001600160401b0381111561282f5761282f612dfd565b6040519080825280601f01601f191660200182016040528015612859576020820181803683370190505b5092506128668583613671565b612871906037613671565b60f81b83600081518110612887576128876135f7565b60200101906001600160f81b031916908160001a905350600190505b818111612913576101006128b782846136cb565b6128c3906101006137c2565b6128cd90886136a0565b6128d791906137ce565b60f81b8382815181106128ec576128ec6135f7565b60200101906001600160f81b031916908160001a90535061290c8161323d565b90506128a3565b50509392505050565b606060008260405160200161293391815260200190565b60408051808303601f1901815260208084528383019092529250600091829160208201818036833701905050905060005b815181101561276b5783836129788161323d565b94508151811061298a5761298a6135f7565b602001015160f81c60f81b8282815181106129a7576129a76135f7565b60200101906001600160f81b031916908160001a9053506129c78161323d565b9050612964565b60606000826040516020016129e591815260200190565b604051602081830303815290604052905060005b6020811015612a3a57818181518110612a1457612a146135f7565b01602001516001600160f81b031916600003612a3a57612a338161323d565b90506129f9565b6000612a478260206136cb565b6001600160401b03811115612a5e57612a5e612dfd565b6040519080825280601f01601f191660200182016040528015612a88576020820181803683370190505b50905060005b815181101561276b578383612aa28161323d565b945081518110612ab457612ab46135f7565b602001015160f81c60f81b828281518110612ad157612ad16135f7565b60200101906001600160f81b031916908160001a905350612af18161323d565b9050612a8e565b8282825b60208110612b345781518352612b1360208461320b565b9250612b2060208361320b565b9150612b2d6020826136cb565b9050612afc565b905182516020929092036101000a6000190180199091169116179052505050565b6001600160a01b038116811461083d57600080fd5b803561077781612b55565b600060208284031215612b8757600080fd5b813561053781612b55565b600060208284031215612ba457600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60048110612bdf57634e487b7160e01b600052602160045260246000fd5b9052565b6020810161053a8284612bc1565b60006101a08284031215612c0457600080fd5b50919050565b600060208284031215612c1c57600080fd5b81356001600160401b03811115612c3257600080fd5b6109be84828501612bf1565b801515811461083d57600080fd5b600080600060608486031215612c6157600080fd5b83359250602084013591506040840135612c7a81612c3e565b809150509250925092565b60008083601f840112612c9757600080fd5b5081356001600160401b03811115612cae57600080fd5b602083019150836020828501011115612cc657600080fd5b9250929050565b60008060008060608587031215612ce357600080fd5b843593506020850135925060408501356001600160401b03811115612d0757600080fd5b612d1387828801612c85565b95989497509550505050565b60008060408385031215612d3257600080fd5b823591506020830135612d4481612c3e565b809150509250929050565b600080600060408486031215612d6457600080fd5b83356001600160401b0380821115612d7b57600080fd5b612d8787838801612bf1565b94506020860135915080821115612d9d57600080fd5b50612daa86828701612c85565b9497909650939450505050565b60008060408385031215612dca57600080fd5b82356001600160401b03811115612de057600080fd5b612dec85828601612bf1565b9250506020830135612d4481612c3e565b634e487b7160e01b600052604160045260246000fd5b6040516101a081016001600160401b0381118282101715612e3657612e36612dfd565b60405290565b604080519081016001600160401b0381118282101715612e3657612e36612dfd565b60405161022081016001600160401b0381118282101715612e3657612e36612dfd565b600082601f830112612e9257600080fd5b81356001600160401b0380821115612eac57612eac612dfd565b604051601f8301601f19908116603f01168101908282118183101715612ed457612ed4612dfd565b81604052838152866020858801011115612eed57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101a08236031215612f2057600080fd5b612f28612e13565b82358152612f3860208401612b6a565b60208201526040830135604082015260608301356060820152612f5d60808401612b6a565b6080820152612f6e60a08401612b6a565b60a0820152612f7f60c08401612b6a565b60c082015260e08381013590820152610100808401359082015261012080840135908201526101408084013590820152610160808401356001600160401b0380821115612fcb57600080fd5b612fd736838801612e81565b83850152610180925082860135915080821115612ff357600080fd5b5061300036828701612e81565b918301919091525092915050565b60006020828403121561302057600080fd5b815161053781612b55565b6d7369676e616c5f7365727669636560901b8152901515602082015260400190565b60006020828403121561305f57600080fd5b815161053781612c3e565b60005b8381101561308557818101518382015260200161306d565b50506000910152565b600081518084526130a681602086016020860161306a565b601f01601f19169290920160200192915050565b6020815281516020820152600060208301516130e160408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015161311060a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a061018080850182905261318e6101c086018461308e565b90860151858203601f1901838701529092506131aa838261308e565b9695505050505050565b9182526562726964676560d01b60208301521515604082015260600190565b600083516131e581846020880161306a565b9190910191825250602001919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561053a5761053a6131f5565b6a195d1a195c97dd985d5b1d60aa1b8152901515602082015260400190565b60006001820161324f5761324f6131f5565b5060010190565b60006020828403121561326857600080fd5b5051919050565b8581526001600160a01b0385166020820152604081018490526080606082018190528101829052818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b600082601f8301126132cf57600080fd5b6040516101008082018281106001600160401b03821117156132f3576132f3612dfd565b6040528301818582111561330657600080fd5b845b82811015613320578035825260209182019101613308565b509195945050505050565b80356001600160801b038116811461077757600080fd5b80356001600160401b038116811461077757600080fd5b60006020828403121561336b57600080fd5b81356001600160401b038082111561338257600080fd5b908301906040828603121561339657600080fd5b61339e612e3c565b8235828111156133ad57600080fd5b830161030081880312156133c057600080fd5b6133c8612e5e565b81358152602082013560208201526133e260408301612b6a565b6040820152606082013560608201526080820135608082015260a082013560a08201526134128860c084016132be565b60c08201526101c08083013560e08301526101e061343181850161332b565b610100840152610200613445818601613342565b6101208501526134586102208601613342565b61014085015261346b6102408601613342565b6101608501526102608501358781111561348457600080fd5b6134908c828801612e81565b610180860152506102808501356101a08501526134b06102a08601613342565b838501526102c0850135828501526102e08501358185015250505080835250506020830135828111156134e257600080fd5b6134ee87828601612e81565b60208301525095945050505050565b85815260018060a01b038516602082015283604082015282606082015260a06080820152600061107f60a083018461308e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000808335601e1984360301811261359257600080fd5b8301803591506001600160401b038211156135ac57600080fd5b602001915036819003821315612cc657600080fd5b8183823760009101908152919050565b604081016135df8285612bc1565b6001600160a01b039290921660209190910152919050565b634e487b7160e01b600052603260045260246000fd5b60008183825b6008811015613632578151835260209283019290910190600101613613565b5050506101008201905092915050565b6000835161365481846020880161306a565b83519083019061366881836020880161306a565b01949350505050565b60ff818116838216019081111561053a5761053a6131f5565b634e487b7160e01b600052601260045260246000fd5b6000826136af576136af61368a565b500490565b808202811582820484141761053a5761053a6131f5565b8181038181111561053a5761053a6131f5565b600181815b808511156137195781600019048211156136ff576136ff6131f5565b8085161561370c57918102915b93841c93908002906136e3565b509250929050565b6000826137305750600161053a565b8161373d5750600061053a565b8160018114613753576002811461375d57613779565b600191505061053a565b60ff84111561376e5761376e6131f5565b50506001821b61053a565b5060208310610133831016604e8410600b841016171561379c575081810a61053a565b6137a683836136de565b80600019048211156137ba576137ba6131f5565b029392505050565b60006105378383613721565b6000826137dd576137dd61368a565b50069056fea26469706673582212209944d85d0cc8409987bf496ae9ba9d199c3992cdf3a3f5d304737e8c526b4f3c64736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000004" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000002": { + "storage": {}, + "code": "0x6080604052600436106100e85760003560e01c8063780b64f01161008a578063a86f9d9e11610059578063a86f9d9e146102ca578063c287e578146102ea578063ee1490b21461032a578063f2fde38b1461033d57600080fd5b8063780b64f0146101fc5780638da5cb5b1461025b5780639754149b146102795780639aa8605c1461029957600080fd5b80633ab76e9f116100c65780633ab76e9f1461014f57806367090ccf146101865780636c6563f6146101c7578063715018a6146101e757600080fd5b80630652b57a146100ed5780630c6fab821461010f57806319ab453c1461012f575b600080fd5b3480156100f957600080fd5b5061010d610108366004611fe4565b61035d565b005b34801561011b57600080fd5b5061010d61012a366004612001565b6103e0565b34801561013b57600080fd5b5061010d61014a366004611fe4565b6105f7565b34801561015b57600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019257600080fd5b506101696101a1366004612070565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156101d357600080fd5b506101696101e23660046120ae565b61070f565b3480156101f357600080fd5b5061010d610726565b34801561020857600080fd5b5061023c6102173660046120e7565b60cc60205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161017d565b34801561026757600080fd5b506065546001600160a01b0316610169565b34801561028557600080fd5b5061010d610294366004612100565b61073a565b3480156102a557600080fd5b506102b96102b4366004611fe4565b610a88565b60405161017d9594939291906121f0565b3480156102d657600080fd5b506101696102e5366004612241565b610bd9565b3480156102f657600080fd5b5061031a610305366004611fe4565b60c96020526000908152604090205460ff1681565b604051901515815260200161017d565b61010d6103383660046122d5565b610bef565b34801561034957600080fd5b5061010d610358366004611fe4565b61141f565b610365611498565b6001600160a01b03811661038c57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b6103e86114f2565b6562726964676560d01b6103fd816000610bd9565b6001600160a01b0316336001600160a01b03161461042e57604051630d85cccf60e11b815260040160405180910390fd5b6000336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561046e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061049291906123b4565b90506104b281604001516a1d1bdad95b97dd985d5b1d60aa1b600061070f565b6001600160a01b031681602001516001600160a01b0316146104e7576040516320258b8760e21b815260040160405180910390fd5b60004687350361051c576105016040880160208901611fe4565b90506105176001600160a01b038216868661154b565b61058c565b610525876115ae565b6040516342e91bb360e01b81526001600160a01b03878116600483015260248201879052919250908216906342e91bb390604401600060405180830381600087803b15801561057357600080fd5b505af1158015610587573d6000803e3d6000fd5b505050505b815160408084015181519081526001600160a01b0384811660208301529181018790528188169291891691907fe5da926519fc972010fe65b35c1e3339e6dc72b35ffaec203999c2a2a2593eac9060600160405180910390a45050506105f160018055565b50505050565b600054610100900460ff16158080156106175750600054600160ff909116105b806106315750303b158015610631575060005460ff166001145b6106995760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156106bc576000805461ff0019166101001790555b6106c58261160d565b801561070b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061071c848484611626565b90505b9392505050565b61072e611498565b61073860006116da565b565b6107426114f2565b600061075460a0850160808601611fe4565b6001600160a01b03160361077b576040516372b41cdf60e01b815260040160405180910390fd5b4683604001351461079f576040516348bc100560e01b815260040160405180910390fd5b60006107b56562726964676560d01b6000610bd9565b90506000816001600160a01b0316635817b0c3866040518263ffffffff1660e01b81526004016107e5919061248c565b602060405180830381865afa158015610802573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082691906125aa565b600081815260cc6020526040902080546001909101549192506001600160a01b0316908161086757604051637c6addb760e01b815260040160405180910390fd5b60405163ce70f39b60e01b81526001600160a01b0385169063ce70f39b9061089d90869060608c0135908b908b906004016125c3565b602060405180830381865afa1580156108ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108de91906125ed565b6108fb576040516308ba49e560e31b815260040160405180910390fd5b6040805180820182526000808252602080830182815287835260cc909152929020905181546001600160a01b0319166001600160a01b0390911617815590516001909101558015610a0f576001600160a01b038216600090815260c9602052604090205460ff16156109eb576001600160a01b0382166342e91bb361098660a08a0160808b01611fe4565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401600060405180830381600087803b1580156109ce57600080fd5b505af11580156109e2573d6000803e3d6000fd5b50505050610a0f565b610a0f6109fe60a0890160808a01611fe4565b6001600160a01b038416908361154b565b610a1f60a0880160808901611fe4565b6001600160a01b0316837fc5d9f7cd7998e24ecf12ad69eca9339764e2cb13788d5d9616f502601b219af68484604051610a6e9291906001600160a01b03929092168252602082015260400190565b60405180910390a350505050610a8360018055565b505050565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b03831693600160a01b90930460ff1692909190610ac89061260a565b80601f0160208091040260200160405190810160405280929190818152602001828054610af49061260a565b8015610b415780601f10610b1657610100808354040283529160200191610b41565b820191906000526020600020905b815481529060010190602001808311610b2457829003601f168201915b505050505090806003018054610b569061260a565b80601f0160208091040260200160405190810160405280929190818152602001828054610b829061260a565b8015610bcf5780601f10610ba457610100808354040283529160200191610bcf565b820191906000526020600020905b815481529060010190602001808311610bb257829003601f168201915b5050505050905085565b6000610be6468484611626565b90505b92915050565b610bf76114f2565b6001600160a01b0387161580610c375750610c22886a1d1bdad95b97dd985d5b1d60aa1b600061070f565b6001600160a01b0316876001600160a01b0316145b15610c5557604051634694641b60e01b815260040160405180910390fd5b6001600160a01b038616610c7c57604051637c6addb760e01b815260040160405180910390fd5b84600003610c9c5760405162af849960e11b815260040160405180910390fd5b6040805160a08101825260008082526020820181905291810191909152606080820181905260808201526001600160a01b038716600090815260c9602052604081205460ff1615610ef357604051630ef7c31560e31b8152336004820152602481018890526001600160a01b038916906377be18a890604401600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b505050506001600160a01b03888116600090815260ca6020908152604091829020825160a08101845281548152600182015494851692810192909252600160a01b90930460ff1691810191909152600282018054919291606084019190610da99061260a565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd59061260a565b8015610e225780601f10610df757610100808354040283529160200191610e22565b820191906000526020600020905b815481529060010190602001808311610e0557829003601f168201915b50505050508152602001600382018054610e3b9061260a565b80601f0160208091040260200160405190810160405280929190818152602001828054610e679061260a565b8015610eb45780601f10610e8957610100808354040283529160200191610eb4565b820191906000526020600020905b815481529060010190602001808311610e9757829003601f168201915b5050509190925250505060208101519092506001600160a01b0316610eec57604051633e45a03560e21b815260040160405180910390fd5b5085611153565b60008890506040518060a001604052804681526020018a6001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7a9190612653565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610fc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fe89190810190612670565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801561102b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110539190810190612670565b90526040516370a0823160e01b81523060048201529093506000906001600160a01b038316906370a0823190602401602060405180830381865afa15801561109f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c391906125aa565b90506110da6001600160a01b03831633308c61172c565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015611120573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114491906125aa565b61114e91906126e7565b925050505b6111e2604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018b90523360808201526112098b6a1d1bdad95b97dd985d5b1d60aa1b600061070f565b6001600160a01b031660a08201526080810151604051630637d5c160e11b9161123b918691908e908790602401612708565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526101608201526101408101879052610120810186905261128d86346126e7565b60e08201526001600160a01b03851660c0820152610180810184905260006112be6562726964676560d01b82610bd9565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b81526004016112ea91906127a0565b60206040518083038185885af1158015611308573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061132d91906125aa565b905060405180604001604052808b6001600160a01b031681526020018481525060cc600083815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550602082015181600101559050508a6001600160a01b031682608001516001600160a01b0316827f325cab7553038374e17f39bb45e2a2c90f66c6a52798cb5f95c20d94c11c95e28f8e88604051611400939291909283526001600160a01b03919091166020830152604082015260600190565b60405180910390a45050505061141560018055565b5050505050505050565b611427611498565b6001600160a01b03811661148c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610690565b611495816116da565b50565b6065546001600160a01b031633146107385760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610690565b6002600154036115445760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610690565b6002600155565b6040516001600160a01b038316602482015260448101829052610a8390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611764565b8035600090815260cb602090815260408083208392909183916115d5918701908701611fe4565b6001600160a01b03908116825260208201929092526040016000205416905080610be95761160283611836565b61071f565b60018055565b611615611abb565b61161d611aea565b61149581611b19565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015611677573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169b9190612890565b9050811580156116b257506001600160a01b038116155b1561071f57604051631467050360e21b81526004810185905260248101849052604401610690565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526105f19085906323b872dd60e01b90608401611577565b60006117b9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b629092919063ffffffff16565b805190915015610a8357808060200190518101906117d791906125ed565b610a835760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610690565b60006118af81833561184e6040860160208701611fe4565b60405161187192916001600160a01b031690602001918252602082015260400190565b604051602081830303815290604052805190602001206040518060200161189790611fb2565b601f1982820381018352601f90910116604052611b71565b6097549091506001600160a01b0380831691636c0db62b91166118d86040860160208701611fe4565b85356118ea60608801604089016128ad565b6118f760608901896128ca565b61190460808b018b6128ca565b61190e8c35611c75565b60405160200161192093929190612911565b6040516020818303038152906040526040518863ffffffff1660e01b8152600401611951979695949392919061295a565b600060405180830381600087803b15801561196b57600080fd5b505af115801561197f573d6000803e3d6000fd5b5050506001600160a01b038216600090815260c960209081526040808320805460ff1916600117905560ca90915290208391506119bc8282612ac6565b50508135600090815260cb602090815260408083208493909290916119e691908701908701611fe4565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b0316826020016020810190611a479190611fe4565b6001600160a01b031683357f9e465b29e576a3e01584e31d607353f21b80c055e813af907c0a495f6cf4f7bc611a8060608701876128ca565b611a8d60808901896128ca565b611a9d60608b0160408c016128ad565b604051611aae959493929190612b4d565b60405180910390a4919050565b600054610100900460ff16611ae25760405162461bcd60e51b815260040161069090612b8a565b610738611d08565b600054610100900460ff16611b115760405162461bcd60e51b815260040161069090612b8a565b610738611d2f565b6001600160a01b038116611b4057604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b606061071c8484600085611d5f565b600083471015611bc35760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401610690565b8151600003611c145760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401610690565b8282516020840186f590506001600160a01b03811661071f5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401610690565b60606000611c8283611e3c565b600101905060008167ffffffffffffffff811115611ca257611ca2612266565b6040519080825280601f01601f191660200182016040528015611ccc576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611cd657509392505050565b600054610100900460ff166116075760405162461bcd60e51b815260040161069090612b8a565b600054610100900460ff16611d565760405162461bcd60e51b815260040161069090612b8a565b610738336116da565b606082471015611dc05760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610690565b600080866001600160a01b03168587604051611ddc9190612bd5565b60006040518083038185875af1925050503d8060008114611e19576040519150601f19603f3d011682016040523d82523d6000602084013e611e1e565b606091505b5091509150611e2f87838387611f14565b925050505b949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e7b5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611ea7576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611ec557662386f26fc10000830492506010015b6305f5e1008310611edd576305f5e100830492506008015b6127108310611ef157612710830492506004015b60648310611f03576064830492506002015b600a8310610be95760010192915050565b60608315611f83578251600003611f7c576001600160a01b0385163b611f7c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610690565b5081611e34565b611e348383815115611f985781518083602001fd5b8060405162461bcd60e51b81526004016106909190612bf1565b6116ce80612c0583390190565b6001600160a01b038116811461149557600080fd5b8035611fdf81611fbf565b919050565b600060208284031215611ff657600080fd5b813561071f81611fbf565b6000806000806080858703121561201757600080fd5b843567ffffffffffffffff81111561202e57600080fd5b850160a0818803121561204057600080fd5b9350602085013561205081611fbf565b9250604085013561206081611fbf565b9396929550929360600135925050565b6000806040838503121561208357600080fd5b82359150602083013561209581611fbf565b809150509250929050565b801515811461149557600080fd5b6000806000606084860312156120c357600080fd5b833592506020840135915060408401356120dc816120a0565b809150509250925092565b6000602082840312156120f957600080fd5b5035919050565b60008060006040848603121561211557600080fd5b833567ffffffffffffffff8082111561212d57600080fd5b908501906101a0828803121561214257600080fd5b9093506020850135908082111561215857600080fd5b818601915086601f83011261216c57600080fd5b81358181111561217b57600080fd5b87602082850101111561218d57600080fd5b6020830194508093505050509250925092565b60005b838110156121bb5781810151838201526020016121a3565b50506000910152565b600081518084526121dc8160208601602086016121a0565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260ff8416604082015260a060608201819052600090612223908301856121c4565b828103608084015261223581856121c4565b98975050505050505050565b6000806040838503121561225457600080fd5b823591506020830135612095816120a0565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156122a5576122a5612266565b604052919050565b600067ffffffffffffffff8211156122c7576122c7612266565b50601f01601f191660200190565b600080600080600080600080610100898b0312156122f257600080fd5b88359750602089013561230481611fbf565b9650604089013561231481611fbf565b9550606089013594506080890135935060a0890135925060c089013561233981611fbf565b915060e089013567ffffffffffffffff81111561235557600080fd5b8901601f81018b1361236657600080fd5b8035612379612374826122ad565b61227c565b8181528c602083850101111561238e57600080fd5b816020840160208301376000602083830101528093505050509295985092959890939650565b6000606082840312156123c657600080fd5b6040516060810181811067ffffffffffffffff821117156123e9576123e9612266565b6040528251815260208301516123fe81611fbf565b60208201526040928301519281019290925250919050565b6000808335601e1984360301811261242d57600080fd5b830160208101925035905067ffffffffffffffff81111561244d57600080fd5b80360382131561245c57600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081528135602082015260006124a560208401611fd4565b6001600160a01b03811660408401525060408301356060830152606083013560808301526124d560808401611fd4565b6001600160a01b03811660a0840152506124f160a08401611fd4565b6001600160a01b03811660c08401525061250d60c08401611fd4565b6001600160a01b03811660e08401525061010060e08401358184015261012081850135818501526101409150808501358285015250610160818501358185015261255981860186612416565b925090506101a061018081818701526125776101c087018585612463565b935061258581880188612416565b878603601f1901848901529350905061259f848483612463565b979650505050505050565b6000602082840312156125bc57600080fd5b5051919050565b8481528360208201526060604082015260006125e3606083018486612463565b9695505050505050565b6000602082840312156125ff57600080fd5b815161071f816120a0565b600181811c9082168061261e57607f821691505b60208210810361263e57634e487b7160e01b600052602260045260246000fd5b50919050565b60ff8116811461149557600080fd5b60006020828403121561266557600080fd5b815161071f81612644565b60006020828403121561268257600080fd5b815167ffffffffffffffff81111561269957600080fd5b8201601f810184136126aa57600080fd5b80516126b8612374826122ad565b8181528560208385010111156126cd57600080fd5b6126de8260208301602086016121a0565b95945050505050565b81810381811115610be957634e487b7160e01b600052601160045260246000fd5b60808152845160808201526000602086015160018060a01b0380821660a085015260ff60408901511660c08501526060880151915060a060e08501526127526101208501836121c4565b91506080880151607f198584030161010086015261277083826121c4565b9188166020860152506001600160a01b038616604085015291506127919050565b82606083015295945050505050565b6020815281516020820152600060208301516127c760408401826001600160a01b03169052565b50604083015160608301526060830151608083015260808301516127f660a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a06101808085018290526128746101c08601846121c4565b90860151858203601f1901838701529092506125e383826121c4565b6000602082840312156128a257600080fd5b815161071f81611fbf565b6000602082840312156128bf57600080fd5b813561071f81612644565b6000808335601e198436030181126128e157600080fd5b83018035915067ffffffffffffffff8211156128fc57600080fd5b60200191503681900382131561245c57600080fd5b8284823760008382016b050c4e4d2c8cecac9e13f19160a31b8152835161293f81600c8401602088016121a0565b602960f81b600c9290910191820152600d0195945050505050565b6001600160a01b038881168252871660208201526040810186905260ff8516606082015260c0608082018190526000906129979083018587612463565b82810360a08401526129a981856121c4565b9a9950505050505050505050565b601f821115610a8357600081815260208120601f850160051c810160208610156129de5750805b601f850160051c820191505b818110156129fd578281556001016129ea565b505050505050565b67ffffffffffffffff831115612a1d57612a1d612266565b612a3183612a2b835461260a565b836129b7565b6000601f841160018114612a655760008515612a4d5750838201355b600019600387901b1c1916600186901b178355612abf565b600083815260209020601f19861690835b82811015612a965786850135825560209485019460019092019101612a76565b5086821015612ab35760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b81358155600181016020830135612adc81611fbf565b81546040850135612aec81612644565b60ff60a01b60a09190911b166001600160a01b03929092166001600160a81b03199190911617179055612b2260608301836128ca565b612b30818360028601612a05565b5050612b3f60808301836128ca565b6105f1818360038601612a05565b606081526000612b61606083018789612463565b8281036020840152612b74818688612463565b91505060ff831660408301529695505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251612be78184602087016121a0565b9190910192915050565b602081526000610be660208301846121c456fe608060405234801561001057600080fd5b506116ae806100206000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80636c6563f6116100c357806395d89b411161007c57806395d89b4114610305578063a457c2d71461030d578063a86f9d9e14610320578063a9059cbb14610333578063dd62ed3e14610346578063f2fde38b1461035957600080fd5b80636c6563f61461028a57806370a082311461029d578063715018a6146102c657806377be18a8146102ce5780637cf8ed0d146102e15780638da5cb5b146102f457600080fd5b8063395093511161011557806339509351146101ed5780633ab76e9f1461020057806342e91bb31461022557806349d126051461023857806367e828bf146102415780636c0db62b1461027757600080fd5b80630652b57a1461015d57806306fdde0314610172578063095ea7b31461019057806318160ddd146101b357806323b872dd146101c5578063313ce567146101d8575b600080fd5b61017061016b3660046111d3565b61036c565b005b61017a6103ef565b60405161018791906111f0565b60405180910390f35b6101a361019e36600461123e565b610481565b6040519015158152602001610187565b60cb545b604051908152602001610187565b6101a36101d336600461126a565b61049b565b60fd5460405160ff9091168152602001610187565b6101a36101fb36600461123e565b6104db565b6097546001600160a01b03165b6040516001600160a01b039091168152602001610187565b61017061023336600461123e565b6104fd565b6101b760fc5481565b61025860fb5460fc546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610187565b61017061028536600461134e565b61059a565b61020d61029836600461140d565b610740565b6101b76102ab3660046111d3565b6001600160a01b0316600090815260c9602052604090205490565b61017061074d565b6101706102dc36600461123e565b610761565b60fb5461020d906001600160a01b031681565b6065546001600160a01b031661020d565b61017a6107f1565b6101a361031b36600461123e565b610800565b61020d61032e366004611442565b610886565b6101a361034136600461123e565b610893565b6101b761035436600461146e565b6108c8565b6101706103673660046111d3565b6108f3565b61037461096c565b6001600160a01b03811661039b57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b606060cc80546103fe906114a7565b80601f016020809104026020016040519081016040528092919081815260200182805461042a906114a7565b80156104775780601f1061044c57610100808354040283529160200191610477565b820191906000526020600020905b81548152906001019060200180831161045a57829003601f168201915b5050505050905090565b60003361048f8185856109c6565b60019150505b92915050565b6000306001600160a01b038416036104c6576040516319a6f37760e21b815260040160405180910390fd5b6104d1848484610aeb565b90505b9392505050565b60003361048f8185856104ee83836108c8565b6104f891906114e1565b6109c6565b6a1d1bdad95b97dd985d5b1d60aa1b610517816000610886565b6001600160a01b0316336001600160a01b03161461054857604051630d85cccf60e11b815260040160405180910390fd5b6105528383610b04565b826001600160a01b03167f397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa68360405161058d91815260200190565b60405180910390a2505050565b600054610100900460ff16158080156105ba5750600054600160ff909116105b806105d45750303b1580156105d4575060005460ff166001145b61063c5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561065f576000805461ff0019166101001790555b6001600160a01b0386161580610673575084155b8061067d57504685145b8061068757508251155b8061069157508151155b156106af576040516301e25ab360e71b815260040160405180910390fd5b6106b887610bc6565b6106c28284610bdf565b60fb80546001600160a01b0319166001600160a01b03881617905560fc85905560fd805460ff191660ff86161790558015610737576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b60006104d1848484610c10565b61075561096c565b61075f6000610cc4565b565b6a1d1bdad95b97dd985d5b1d60aa1b61077b816000610886565b6001600160a01b0316336001600160a01b0316146107ac57604051630d85cccf60e11b815260040160405180910390fd5b6107b68383610d16565b826001600160a01b03167f9b5b9a05e4726d8bb959f1440e05c6b8109443f2083bc4e386237d76545265538360405161058d91815260200190565b606060cd80546103fe906114a7565b6000338161080e82866108c8565b90508381101561086e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610633565b61087b82868684036109c6565b506001949350505050565b60006104d4468484610c10565b6000306001600160a01b038416036108be576040516319a6f37760e21b815260040160405180910390fd5b6104d48383610e47565b6001600160a01b03918216600090815260ca6020908152604080832093909416825291909152205490565b6108fb61096c565b6001600160a01b0381166109605760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610633565b61096981610cc4565b50565b6065546001600160a01b0316331461075f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610633565b6001600160a01b038316610a285760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610633565b6001600160a01b038216610a895760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610633565b6001600160a01b03838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600033610af9858285610e55565b61087b858585610ecf565b6001600160a01b038216610b5a5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610633565b8060cb6000828254610b6c91906114e1565b90915550506001600160a01b038216600081815260c960209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b5050565b610bce61107a565b610bd66110a9565b610969816110d8565b600054610100900460ff16610c065760405162461bcd60e51b815260040161063390611502565b610bc28282611121565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610c61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c85919061154d565b905081158015610c9c57506001600160a01b038116155b156104d457604051631467050360e21b81526004810185905260248101849052604401610633565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216610d765760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610633565b6001600160a01b038216600090815260c9602052604090205481811015610dea5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610633565b6001600160a01b038316600081815260c960209081526040808320868603905560cb80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610ade565b505050565b60003361048f818585610ecf565b6000610e6184846108c8565b90506000198114610ec95781811015610ebc5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610633565b610ec984848484036109c6565b50505050565b6001600160a01b038316610f335760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610633565b6001600160a01b038216610f955760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610633565b6001600160a01b038316600090815260c960205260409020548181101561100d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610633565b6001600160a01b03808516600081815260c9602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061106d9086815260200190565b60405180910390a3610ec9565b600054610100900460ff166110a15760405162461bcd60e51b815260040161063390611502565b61075f611161565b600054610100900460ff166110d05760405162461bcd60e51b815260040161063390611502565b61075f61118e565b6001600160a01b0381166110ff57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166111485760405162461bcd60e51b815260040161063390611502565b60cc61115483826115b8565b5060cd610e4282826115b8565b600054610100900460ff166111885760405162461bcd60e51b815260040161063390611502565b60018055565b600054610100900460ff166111b55760405162461bcd60e51b815260040161063390611502565b61075f33610cc4565b6001600160a01b038116811461096957600080fd5b6000602082840312156111e557600080fd5b81356104d4816111be565b600060208083528351808285015260005b8181101561121d57858101830151858201604001528201611201565b506000604082860101526040601f19601f8301168501019250505092915050565b6000806040838503121561125157600080fd5b823561125c816111be565b946020939093013593505050565b60008060006060848603121561127f57600080fd5b833561128a816111be565b9250602084013561129a816111be565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126112d257600080fd5b813567ffffffffffffffff808211156112ed576112ed6112ab565b604051601f8301601f19908116603f01168101908282118183101715611315576113156112ab565b8160405283815286602085880101111561132e57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c0878903121561136757600080fd5b8635611372816111be565b95506020870135611382816111be565b945060408701359350606087013560ff8116811461139f57600080fd5b9250608087013567ffffffffffffffff808211156113bc57600080fd5b6113c88a838b016112c1565b935060a08901359150808211156113de57600080fd5b506113eb89828a016112c1565b9150509295509295509295565b8035801515811461140857600080fd5b919050565b60008060006060848603121561142257600080fd5b8335925060208401359150611439604085016113f8565b90509250925092565b6000806040838503121561145557600080fd5b82359150611465602084016113f8565b90509250929050565b6000806040838503121561148157600080fd5b823561148c816111be565b9150602083013561149c816111be565b809150509250929050565b600181811c908216806114bb57607f821691505b6020821081036114db57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561049557634e487b7160e01b600052601160045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561155f57600080fd5b81516104d4816111be565b601f821115610e4257600081815260208120601f850160051c810160208610156115915750805b601f850160051c820191505b818110156115b05782815560010161159d565b505050505050565b815167ffffffffffffffff8111156115d2576115d26112ab565b6115e6816115e084546114a7565b8461156a565b602080601f83116001811461161b57600084156116035750858301515b600019600386901b1c1916600185901b1785556115b0565b600085815260208120601f198616915b8281101561164a5788860151825594840194600190910190840161162b565b50858210156116685787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea26469706673582212205ce93c18102792779a2e35d561c62ea243b85b80c5963767b571fcdab9e3d74a64736f6c63430008120033a26469706673582212205b590be2c7b9e2eb2401e8170149f7dba7d88f43691401f4ee5b704b6bdc8bb364736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000002" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000003": { + "storage": {}, + "code": "0x6080604052600436106100ab5760003560e01c80638da5cb5b116100645780638da5cb5b146101c0578063a86f9d9e146101de578063ba0bbd95146101fe578063d73bb3d01461021e578063f2fde38b1461023e578063fe9fbb801461025e57600080fd5b80630652b57a146100f457806319ab453c146101145780632d1fb389146101345780633ab76e9f146101545780636c6563f61461018b578063715018a6146101ab57600080fd5b366100ef5747158015906100cf575033600090815260c9602052604090205460ff16155b156100ed57604051634fa3f24560e01b815260040160405180910390fd5b005b600080fd5b34801561010057600080fd5b506100ed61010f366004610a90565b6102a7565b34801561012057600080fd5b506100ed61012f366004610a90565b61032a565b34801561014057600080fd5b506100ed61014f366004610ac2565b610442565b34801561016057600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019757600080fd5b5061016e6101a6366004610af7565b6104fb565b3480156101b757600080fd5b506100ed610512565b3480156101cc57600080fd5b506065546001600160a01b031661016e565b3480156101ea57600080fd5b5061016e6101f9366004610b2c565b610526565b34801561020a57600080fd5b506100ed610219366004610b4f565b610533565b34801561022a57600080fd5b506100ed610239366004610b7b565b6105f1565b34801561024a57600080fd5b506100ed610259366004610a90565b610674565b34801561026a57600080fd5b50610297610279366004610a90565b6001600160a01b0316600090815260c9602052604090205460ff1690565b6040519015158152602001610182565b6102af6106ea565b6001600160a01b0381166102d657604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff161580801561034a5750600054600160ff909116105b806103645750303b158015610364575060005460ff166001145b6103cc5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156103ef576000805461ff0019166101001790555b6103f882610744565b801561043e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b61044a6106ea565b6001600160a01b038216158061047e57506001600160a01b038216600090815260c9602052604090205460ff161515811515145b1561049c57604051631bebdfa760e21b815260040160405180910390fd5b6001600160a01b038216600081815260c96020908152604091829020805460ff191685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b600061050884848461075d565b90505b9392505050565b61051a6106ea565b6105246000610811565b565b600061050b46848461075d565b33600090815260c9602052604090205460ff1661056357604051634fa3f24560e01b815260040160405180910390fd5b61056b610863565b6001600160a01b0382166105925760405163687563df60e01b815260040160405180910390fd5b6105a56001600160a01b038316826108bc565b816001600160a01b03167f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e826040516105e091815260200190565b60405180910390a261043e60018055565b33600090815260c9602052604090205460ff1661062157604051634fa3f24560e01b815260040160405180910390fd5b610629610863565b61063333826108bc565b60405181815233907f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e9060200160405180910390a261067160018055565b50565b61067c6106ea565b6001600160a01b0381166106e15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103c3565b61067181610811565b6065546001600160a01b031633146105245760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c3565b61074c61097d565b6107546109ac565b610671816109db565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156107ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d29190610b94565b9050811580156107e957506001600160a01b038116155b1561050b57604051631467050360e21b815260048101859052602481018490526044016103c3565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6002600154036108b55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103c3565b6002600155565b8015806108d057506001600160a01b038216155b156108d9575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610926576040519150601f19603f3d011682016040523d82523d6000602084013e61092b565b606091505b50509050806109725760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016103c3565b505050565b60018055565b600054610100900460ff166109a45760405162461bcd60e51b81526004016103c390610bb1565b610524610a24565b600054610100900460ff166109d35760405162461bcd60e51b81526004016103c390610bb1565b610524610a4b565b6001600160a01b038116610a0257604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166109775760405162461bcd60e51b81526004016103c390610bb1565b600054610100900460ff16610a725760405162461bcd60e51b81526004016103c390610bb1565b61052433610811565b6001600160a01b038116811461067157600080fd5b600060208284031215610aa257600080fd5b813561050b81610a7b565b80358015158114610abd57600080fd5b919050565b60008060408385031215610ad557600080fd5b8235610ae081610a7b565b9150610aee60208401610aad565b90509250929050565b600080600060608486031215610b0c57600080fd5b8335925060208401359150610b2360408501610aad565b90509250925092565b60008060408385031215610b3f57600080fd5b82359150610aee60208401610aad565b60008060408385031215610b6257600080fd5b8235610b6d81610a7b565b946020939093013593505050565b600060208284031215610b8d57600080fd5b5035919050565b600060208284031215610ba657600080fd5b815161050b81610a7b565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212207583c25e67e1b9db0f317fbe1c15cd5a0919373c4d9b26d98238ed2046695f9264736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xa738d3397c1eb96f671d7e4bd29cabbfa1a9c9ebc0db4142aee17809c43ab720": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000003" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0xffffffffffffff21f494c589bfffffff" + }, + "0x0000777700000000000000000000000000000007": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80636c6563f6116100715780636c6563f614610162578063715018a6146101755780638da5cb5b1461017d578063a86f9d9e1461018e578063f2fde38b146101a1578063f8f3f844146101b457600080fd5b80630652b57a146100b957806319ab453c146100ce57806332676bc6146100e15780633ab76e9f146101095780635221f6131461012e57806366ca2bc014610141575b600080fd5b6100cc6100c7366004611a18565b6101e0565b005b6100cc6100dc366004611a18565b610263565b6100f46100ef366004611a35565b61037b565b60405190151581526020015b60405180910390f35b6097546001600160a01b03165b6040516001600160a01b039091168152602001610100565b6100f461013c366004611a61565b6103ed565b61015461014f366004611af7565b61055d565b604051908152602001610100565b610116610170366004611b25565b6105a2565b6100cc6105b9565b6065546001600160a01b0316610116565b61011661019c366004611b5a565b6105cd565b6100cc6101af366004611a18565b6105da565b6101546101c2366004611a35565b6040805192835260208301919091526034600c830120918101905290565b6101e8610653565b6001600160a01b03811661020f57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b9060200160405180910390a150565b600054610100900460ff16158080156102835750600054600160ff909116105b8061029d5750303b15801561029d575060005460ff166001145b6103055760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610328576000805461ff0019166101001790555b610331826106ad565b8015610377576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60006001600160a01b0383166103a4576040516354cdfc8d60e11b815260040160405180910390fd5b60008290036103c65760405163014f1da760e21b815260040160405180910390fd5b5060408051838152602081018390526034600c820120908201909152546001145b92915050565b600046860361040f5760405163e822b48d60e01b815260040160405180910390fd5b6001600160a01b038516610436576040516354cdfc8d60e11b815260040160405180910390fd5b60008490036104585760405163014f1da760e21b815260040160405180910390fd5b600061046683850185611bf6565b9050600061047d647461696b6f60d81b60006105cd565b8251604051632e24533960e21b81526001600160a01b03929092169163b8914ce4916104af9160040190815260200190565b602060405180830381865afa1580156104cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f09190611cbd565b60408051898152602081018990526034600c820120818301909252606081019190915290915061055190608001604051602081830303815290604052604051806040016040528060018152602001600160f81b8152508460200151846106c6565b98975050505050505050565b600081810361057f5760405163014f1da760e21b815260040160405180910390fd5b506040805133815260208101929092526034600c83012091810190526001815590565b60006105af8484846106ea565b90505b9392505050565b6105c1610653565b6105cb600061079e565b565b60006105b24684846106ea565b6105e2610653565b6001600160a01b0381166106475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016102fc565b6106508161079e565b50565b6065546001600160a01b031633146105cb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102fc565b6106b56107f0565b6106bd61081f565b6106508161084e565b6000806106d286610897565b90506106e0818686866108c9565b9695505050505050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa15801561073b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075f9190611cd6565b90508115801561077657506001600160a01b038116155b156105b257604051631467050360e21b815260048101859052602481018490526044016102fc565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166108175760405162461bcd60e51b81526004016102fc90611cf3565b6105cb610906565b600054610100900460ff166108465760405162461bcd60e51b81526004016102fc90611cf3565b6105cb610933565b6001600160a01b03811661087557604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b606081805190602001206040516020016108b391815260200190565b6040516020818303038152906040529050919050565b60008060006108d9878686610963565b915091508180156108fb57508051602080830191909120875191880191909120145b979650505050505050565b600054610100900460ff1661092d5760405162461bcd60e51b81526004016102fc90611cf3565b60018055565b600054610100900460ff1661095a5760405162461bcd60e51b81526004016102fc90611cf3565b6105cb3361079e565b60006060600061097285610a3e565b90506000806000610984848a89610b37565b815192955090935091501580806109985750815b6109e45760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e00000000000060448201526064016102fc565b600081610a005760405180602001604052806000815250610a2c565b610a2c86610a0f600188611d54565b81518110610a1f57610a1f611d67565b6020026020010151610f57565b919b919a509098505050505050505050565b60606000610a4b83610f7e565b90506000815167ffffffffffffffff811115610a6957610a69611b86565b604051908082528060200260200182016040528015610aae57816020015b6040805180820190915260608082526020820152815260200190600190039081610a875790505b50905060005b8251811015610b2f576000610ae1848381518110610ad457610ad4611d67565b6020026020010151610fb1565b90506040518060400160405280610af783610f7e565b815260200182815250838381518110610b1257610b12611d67565b60200260200101819052505080610b2890611d7d565b9050610ab4565b509392505050565b600060606000806000610b4987611041565b90506000869050600080610b70604051806040016040528060608152602001606081525090565b60005b8c51811015610f2f578c8181518110610b8e57610b8e611d67565b602002602001015191508284610ba49190611d96565b9350610bb1600188611d96565b965083600003610c0e578482602001518051906020012014610c095760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b60448201526064016102fc565b610cd0565b602082602001515110610c75578482602001518051906020012014610c095760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c2068617368000000000060448201526064016102fc565b84610c83836020015161117a565b14610cd05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f6465206861736800000000000060448201526064016102fc565b610cdc60106001611da9565b60ff1682600001515103610d4a5785518414610f2f576000868581518110610d0657610d06611d67565b01602001518351805160f89290921c925060009183908110610d2a57610d2a611d67565b60200260200101519050610d3d816111a2565b9650600194505050610f1f565b81515160011901610ed7576000610d60836111d8565b9050600081600081518110610d7757610d77611d67565b016020015160f81c90506000610d8e600283611dc2565b610d99906002611df2565b90506000610daa848360ff166111fc565b90506000610db88b8a6111fc565b90506000610dc68383611232565b905060ff851660021480610ddd575060ff85166003145b15610e1757808351148015610df25750808251145b15610e0457610e01818b611d96565b99505b50600160ff1b9950610f2f945050505050565b60ff85161580610e2a575060ff85166001145b15610e805782518114610e4a5750600160ff1b9950610f2f945050505050565b610e718860000151600181518110610e6457610e64611d67565b60200260200101516111a2565b9a509750610f1f945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b60648201526084016102fc565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e00000060448201526064016102fc565b610f2881611d7d565b9050610b73565b50600160ff1b841486610f4287866111fc565b909e909d50909b509950505050505050505050565b805180516060916103e791610f6e90600190611d54565b81518110610ad457610ad4611d67565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906103e7906112ac565b60606000806000610fc185611498565b919450925090506000816001811115610fdc57610fdc611e0b565b146110295760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e000000000000000060448201526064016102fc565b611038856020015184846117e2565b95945050505050565b60606000825160026110539190611e21565b67ffffffffffffffff81111561106b5761106b611b86565b6040519080825280601f01601f191660200182016040528015611095576020820181803683370190505b50905060005b83518110156111735760048482815181106110b8576110b8611d67565b01602001516001600160f81b031916901c826110d5836002611e21565b815181106110e5576110e5611d67565b60200101906001600160f81b031916908160001a905350601084828151811061111057611110611d67565b0160200151611122919060f81c611dc2565b60f81b82611131836002611e21565b61113c906001611d96565b8151811061114c5761114c611d67565b60200101906001600160f81b031916908160001a90535061116c81611d7d565b905061109b565b5092915050565b600060208251101561118e57506020015190565b818060200190518101906103e79190611cbd565b600060606020836000015110156111c3576111bc8361188b565b90506111cf565b6111cc83610fb1565b90505b6105b28161117a565b60606103e76111f78360000151600081518110610ad457610ad4611d67565b611041565b60608251821061121b57506040805160208101909152600081526103e7565b6105b2838384865161122d9190611d54565b611896565b6000805b8084511180156112465750808351115b8015611297575082818151811061125f5761125f611d67565b602001015160f81c60f81b6001600160f81b03191684828151811061128657611286611d67565b01602001516001600160f81b031916145b156105b2576112a581611d7d565b9050611236565b60606000806112ba84611498565b919350909150600190508160018111156112d6576112d6611e0b565b146113235760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e00000000000000000060448201526064016102fc565b6040805160208082526104208201909252600091816020015b604080518082019091526000808252602082015281526020019060019003908161133c5790505090506000835b865181101561148d57602082106113d55760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b60648201526084016102fc565b6000806114126040518060400160405280858c600001516113f69190611d54565b8152602001858c6020015161140b9190611d96565b9052611498565b50915091506040518060400160405280838361142e9190611d96565b8152602001848b602001516114439190611d96565b81525085858151811061145857611458611d67565b602090810291909101015261146e600185611d96565b935061147a8183611d96565b6114849084611d96565b92505050611369565b508152949350505050565b6000806000808460000151116114f05760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e000000000000000060448201526064016102fc565b6020840151805160001a607f81116115155760006001600094509450945050506117db565b60b7811161159157600061152a608083611d54565b90508087600001511161157f5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e0000000000000060448201526064016102fc565b600195509350600092506117db915050565b60bf81116116805760006115a660b783611d54565b9050808760000151116115fb5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e0060448201526064016102fc565b600183015160208290036101000a90046116158183611d96565b8851116116645760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e000000000000000060448201526064016102fc565b61166f826001611d96565b96509450600093506117db92505050565b60f781116116fb57600061169560c083611d54565b9050808760000151116116ea5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e00000000000000000060448201526064016102fc565b6001955093508492506117db915050565b600061170860f783611d54565b90508087600001511161175d5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e00000060448201526064016102fc565b600183015160208290036101000a90046117778183611d96565b8851116117bf5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b60448201526064016102fc565b6117ca826001611d96565b96509450600193506117db92505050565b9193909250565b606060008267ffffffffffffffff8111156117ff576117ff611b86565b6040519080825280601f01601f191660200182016040528015611829576020820181803683370190505b509050805160000361183c5790506105b2565b8484016020820160005b8581101561185e578281015182820152602001611846565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606103e7826119ed565b6060816118a481601f611d96565b10156118e35760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102fc565b826118ee8382611d96565b101561192d5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102fc565b6119378284611d96565b8451101561197b5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016102fc565b60608215801561199a57604051915060008252602082016040526119e4565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119d35780518352602092830192016119bb565b5050858452601f01601f1916604052505b50949350505050565b60606103e78260200151600084600001516117e2565b6001600160a01b038116811461065057600080fd5b600060208284031215611a2a57600080fd5b81356105b281611a03565b60008060408385031215611a4857600080fd5b8235611a5381611a03565b946020939093013593505050565b600080600080600060808688031215611a7957600080fd5b853594506020860135611a8b81611a03565b935060408601359250606086013567ffffffffffffffff80821115611aaf57600080fd5b818801915088601f830112611ac357600080fd5b813581811115611ad257600080fd5b896020828501011115611ae457600080fd5b9699959850939650602001949392505050565b600060208284031215611b0957600080fd5b5035919050565b80358015158114611b2057600080fd5b919050565b600080600060608486031215611b3a57600080fd5b8335925060208401359150611b5160408501611b10565b90509250925092565b60008060408385031215611b6d57600080fd5b82359150611b7d60208401611b10565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bbf57611bbf611b86565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bee57611bee611b86565b604052919050565b60006020808385031215611c0957600080fd5b823567ffffffffffffffff80821115611c2157600080fd5b9084019060408287031215611c3557600080fd5b611c3d611b9c565b823581528383013582811115611c5257600080fd5b80840193505086601f840112611c6757600080fd5b823582811115611c7957611c79611b86565b611c8b601f8201601f19168601611bc5565b92508083528785828601011115611ca157600080fd5b8085850186850137600090830185015292830152509392505050565b600060208284031215611ccf57600080fd5b5051919050565b600060208284031215611ce857600080fd5b81516105b281611a03565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b818103818111156103e7576103e7611d3e565b634e487b7160e01b600052603260045260246000fd5b600060018201611d8f57611d8f611d3e565b5060010190565b808201808211156103e7576103e7611d3e565b60ff81811683821601908111156103e7576103e7611d3e565b600060ff831680611de357634e487b7160e01b600052601260045260246000fd5b8060ff84160691505092915050565b60ff82811682821603908111156103e7576103e7611d3e565b634e487b7160e01b600052602160045260246000fd5b80820281158282048414176103e7576103e7611d3e56fea2646970667358221220914fd418156d9d9a0e4aa8f2d563552ff29aa367381c04f0e5db5dcc63b0ce7264736f6c63430008120033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000007": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000007" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106c2565b610118565b61005b6100933660046106dd565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106c2565b6101ed565b3480156100f557600080fd5b506100ad61020d565b610106610269565b6101166101116102fe565b610308565b565b61012061032c565b6001600160a01b0316330361014d5761014a8160405180602001604052806000815250600061035f565b50565b61014a6100fe565b61015d61032c565b6001600160a01b031633036101b4576101af8383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061035f915050565b505050565b6101af6100fe565b60006101c661032c565b6001600160a01b031633036101e2576101dd6102fe565b905090565b6101ea6100fe565b90565b6101f561032c565b6001600160a01b0316330361014d5761014a8161038a565b600061021761032c565b6001600160a01b031633036101e2576101dd61032c565b606061025383836040518060600160405280602781526020016107d4602791396103de565b9392505050565b6001600160a01b03163b151590565b61027161032c565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd610456565b3660008037600080366000845af43d6000803e808015610327573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103688361047e565b6000825111806103755750805b156101af57610384838361022e565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103b361032c565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a816104be565b6060600080856001600160a01b0316856040516103fb9190610784565b600060405180830381855af49150503d8060008114610436576040519150601f19603f3d011682016040523d82523d6000602084013e61043b565b606091505b509150915061044c86838387610567565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610350565b610487816105e8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105235760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f5565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b606083156105d65782516000036105cf576001600160a01b0385163b6105cf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102f5565b50816105e0565b6105e0838361067c565b949350505050565b6001600160a01b0381163b6106555760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102f5565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610546565b81511561068c5781518083602001fd5b8060405162461bcd60e51b81526004016102f591906107a0565b80356001600160a01b03811681146106bd57600080fd5b919050565b6000602082840312156106d457600080fd5b610253826106a6565b6000806000604084860312156106f257600080fd5b6106fb846106a6565b9250602084013567ffffffffffffffff8082111561071857600080fd5b818601915086601f83011261072c57600080fd5b81358181111561073b57600080fd5b87602082850101111561074d57600080fd5b6020830194508093505050509250925092565b60005b8381101561077b578181015183820152602001610763565b50506000910152565b60008251610796818460208701610760565b9190910192915050565b60208152600082518060208401526107bf816040850160208701610760565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f44b4bd0f73d4a6c872717d3b99f5935a2080af0980894ed447890241a743cdb64736f6c63430008120033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000003e8000", + "0xc4fd933fc30203af5f8bd19ad30e064c96642a369b9fc4288ea95569541f4034": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x967c153683def525608ec6efe0cac3319a9c97a6d4164fb43765c79311abffdc": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x55385a0c2ad17c21b4fe396be9b1f10f500e7eebad11fcd1afe36c68ee5fa4cd": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x478db7f3c43c550c1670aa0517a6d515b9e15f22ea28e4f99e8c5f8bcf58e406": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069c565b60405180910390f35b6100df6100da366004610706565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610730565b61024c565b604051601281526020016100c3565b6100df610131366004610706565b610270565b6100f361014436600461076c565b6001600160a01b031660009081526020819052604090205490565b6100b6610292565b6100df610175366004610706565b6102a1565b6100df610188366004610706565b610321565b6100f361019b36600461078e565b61032f565b6060600380546101af906107c1565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c1565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b60003361024081858561035a565b60019150505b92915050565b60003361025a85828561047e565b6102658585856104f8565b506001949350505050565b600033610240818585610283838361032f565b61028d91906107fb565b61035a565b6060600480546101af906107c1565b600033816102af828661032f565b9050838110156103145760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b610265828686840361035a565b6000336102408185856104f8565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103bc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161030b565b6001600160a01b03821661041d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161030b565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061048a848461032f565b905060001981146104f257818110156104e55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161030b565b6104f2848484840361035a565b50505050565b6001600160a01b03831661055c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161030b565b6001600160a01b0382166105be5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161030b565b6001600160a01b038316600090815260208190526040902054818110156106365760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161030b565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f2565b600060208083528351808285015260005b818110156106c9578581018301518582016040015282016106ad565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461070157600080fd5b919050565b6000806040838503121561071957600080fd5b610722836106ea565b946020939093013593505050565b60008060006060848603121561074557600080fd5b61074e846106ea565b925061075c602085016106ea565b9150604084013590509250925092565b60006020828403121561077e57600080fd5b610787826106ea565b9392505050565b600080604083850312156107a157600080fd5b6107aa836106ea565b91506107b8602084016106ea565b90509250929050565b600181811c908216806107d557607f821691505b6020821081036107f557634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561024657634e487b7160e01b600052601160045260246000fdfea26469706673582212209d989a5d58a4967fd0a1f669587c6ef0bd08d65b4de1b60d2f761d4c7661886164736f6c63430008120033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/internal_l2a.json b/crates/primitives/res/genesis/taiko/internal_l2a.json new file mode 100644 index 000000000000..28291cd056f0 --- /dev/null +++ b/crates/primitives/res/genesis/taiko/internal_l2a.json @@ -0,0 +1,339 @@ +{ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { + "balance": "0x3782dace9d90000000" + }, + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { + "balance": "0x3782dace9d90000000" + }, + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC": { + "balance": "0x3782dace9d90000000" + }, + "0x90F79bf6EB2c4f870365E785982E1f101E93b906": { + "balance": "0x3782dace9d90000000" + }, + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65": { + "balance": "0x3782dace9d90000000" + }, + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": { + "balance": "0x3782dace9d90000000" + }, + "0x976EA74026E726554dB657fA54763abd0C3a0aa9": { + "balance": "0x3782dace9d90000000" + }, + "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955": { + "balance": "0x3782dace9d90000000" + }, + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { + "balance": "0x3782dace9d90000000" + }, + "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720": { + "balance": "0x3782dace9d90000000" + }, + "0xBcd4042DE499D14e55001CcbB24a551F3b954096": { + "balance": "0x3782dace9d90000000" + }, + "0x71bE63f3384f5fb98995898A86B02Fb2426c5788": { + "balance": "0x3782dace9d90000000" + }, + "0xFABB0ac9d68B0B445fB7357272Ff202C5651694a": { + "balance": "0x3782dace9d90000000" + }, + "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec": { + "balance": "0x3782dace9d90000000" + }, + "0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097": { + "balance": "0x3782dace9d90000000" + }, + "0xcd3B766CCDd6AE721141F452C550Ca635964ce71": { + "balance": "0x3782dace9d90000000" + }, + "0x2546BcD3c84621e976D8185a91A922aE77ECEc30": { + "balance": "0x3782dace9d90000000" + }, + "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E": { + "balance": "0x3782dace9d90000000" + }, + "0xdD2FD4581271e230360230F9337D5c0430Bf44C0": { + "balance": "0x3782dace9d90000000" + }, + "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199": { + "balance": "0x3782dace9d90000000" + }, + "0x7D86687F980A56b832e9378952B738b614A99dc6": { + "balance": "0x3782dace9d90000000" + }, + "0x11e8F3eA3C6FcF12EcfF2722d75CEFC539c51a1C": { + "balance": "0x3782dace9d90000000" + }, + "0x9eAF5590f2c84912A08de97FA28d0529361Deb9E": { + "balance": "0x3782dace9d90000000" + }, + "0x1003ff39d25F2Ab16dBCc18EcE05a9B6154f65F4": { + "balance": "0x3782dace9d90000000" + }, + "0x4779d18931B35540F84b0cd0e9633855B84df7b8": { + "balance": "0x3782dace9d90000000" + }, + "0x1c87Bb9234aeC6aDc580EaE6C8B59558A4502220": { + "balance": "0x3782dace9d90000000" + }, + "0x0d803cdeEe5990f22C2a8DF10A695D2312dA26CC": { + "balance": "0x3782dace9d90000000" + }, + "0xAb707cb80e7de7C75d815B1A653433F3EEc44c74": { + "balance": "0x3782dace9d90000000" + }, + "0xe8B1ff302A740fD2C6e76B620d45508dAEc2DDFf": { + "balance": "0x3782dace9d90000000" + }, + "0xa0EC9eE47802CeB56eb58ce80F3E41630B771b04": { + "balance": "0x3782dace9d90000000" + }, + "0x042a63149117602129B6922ecFe3111168C2C323": { + "balance": "0x3782dace9d90000000" + }, + "0xA1196426b41627ae75Ea7f7409E074BE97367da2": { + "balance": "0x3782dace9d90000000" + }, + "0xE74cEf90b6CF1a77FEfAd731713e6f53e575C183": { + "balance": "0x3782dace9d90000000" + }, + "0x7Df8Efa6d6F1CB5C4f36315e0AcB82b02Ae8BA40": { + "balance": "0x3782dace9d90000000" + }, + "0x9E126C57330FA71556628e0aabd6B6B6783d99fA": { + "balance": "0x3782dace9d90000000" + }, + "0xcBDc0F9a4C38f1e010bD3B6e43598A55D1868c23": { + "balance": "0x3782dace9d90000000" + }, + "0xBc5BdceE96b1BC47822C74e6f64186fbA7d686be": { + "balance": "0x3782dace9d90000000" + }, + "0x0536896a5e38BbD59F3F369FF3682677965aBD19": { + "balance": "0x3782dace9d90000000" + }, + "0xFE0f143FcAD5B561b1eD2AC960278A2F23559Ef9": { + "balance": "0x3782dace9d90000000" + }, + "0x98D08079928FcCB30598c6C6382ABfd7dbFaA1cD": { + "balance": "0x3782dace9d90000000" + }, + "0x0167001000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x6080604052600436106100fa575f3560e01c80635c975abb116100925780638da5cb5b116100625780638da5cb5b14610299578063a86f9d9e146102b6578063d8f4648f146102d5578063e30c3978146102f4578063f2fde38b14610311575f80fd5b80635c975abb1461022d578063715018a61461025d57806379ba5097146102715780638456cb5914610285575f80fd5b80633eb6b8cf116100cd5780633eb6b8cf146101c55780633f4ba83a146101e45780634f1ef286146101f857806352d1902d1461020b575f80fd5b806319ab453c146100fe57806328f713cc1461011f5780633659cfe6146101875780633ab76e9f146101a6575b5f80fd5b348015610109575f80fd5b5061011d610118366004610f4b565b610330565b005b34801561012a575f80fd5b5061016a610139366004610f82565b67ffffffffffffffff919091165f90815260fb6020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610192575f80fd5b5061011d6101a1366004610f4b565b610442565b3480156101b1575f80fd5b5060975461016a906001600160a01b031681565b3480156101d0575f80fd5b5061016a6101df366004610fb9565b61051f565b3480156101ef575f80fd5b5061011d610535565b61011d610206366004611006565b6105b4565b348015610216575f80fd5b5061021f61067f565b60405190815260200161017e565b348015610238575f80fd5b5061024d60c954610100900460ff1660021490565b604051901515815260200161017e565b348015610268575f80fd5b5061011d610730565b34801561027c575f80fd5b5061011d610741565b348015610290575f80fd5b5061011d6107b8565b3480156102a4575f80fd5b506033546001600160a01b031661016a565b3480156102c1575f80fd5b5061016a6102d03660046110c4565b610829565b3480156102e0575f80fd5b5061011d6102ef3660046110ee565b610835565b3480156102ff575f80fd5b506065546001600160a01b031661016a565b34801561031c575f80fd5b5061011d61032b366004610f4b565b610913565b5f54610100900460ff161580801561034e57505f54600160ff909116105b806103675750303b15801561036757505f5460ff166001145b6103cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156103f0575f805461ff0019166101001790555b6103f982610984565b801561043e575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000616300361048a5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670010000000000000000000000000000000066001600160a01b03166104d25f80516020611265833981519152546001600160a01b031690565b6001600160a01b0316146104f85760405162461bcd60e51b81526004016103c690611177565b610501816109b4565b604080515f8082526020820190925261051c918391906109bc565b50565b5f61052b848484610b2b565b90505b9392505050565b61054960c954610100900460ff1660021490565b6105665760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a16105b233610c19565b565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000000061630036105fc5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670010000000000000000000000000000000066001600160a01b03166106445f80516020611265833981519152546001600160a01b031690565b6001600160a01b03161461066a5760405162461bcd60e51b81526004016103c690611177565b610673826109b4565b61043e828260016109bc565b5f306001600160a01b037f0000000000000000000000000167001000000000000000000000000000000006161461071e5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016103c6565b505f8051602061126583398151915290565b610738610c31565b6105b25f610c8b565b60655433906001600160a01b031681146107af5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103c6565b61051c81610c8b565b6107cc60c954610100900460ff1660021490565b156107ea5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016105a1565b5f61052e468484610b2b565b61083d610c31565b67ffffffffffffffff83165f90815260fb602090815260408083208584529091529020546001600160a01b0390811690821681900361088f576040516327b026fb60e21b815260040160405180910390fd5b67ffffffffffffffff84165f81815260fb6020908152604080832087845282529182902080546001600160a01b0319166001600160a01b038781169182179092558351908152908516918101919091528592917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b61091b610c31565b606580546001600160a01b0383166001600160a01b0319909116811790915561094c6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6109a26001600160a01b0382161561099c5781610c8b565b33610c8b565b5060c9805461ff001916610100179055565b61051c610c31565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109f4576109ef83610ca4565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4e575060408051601f3d908101601f19168201909252610a4b918101906111c3565b60015b610ab15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016103c6565b5f805160206112658339815191528114610b1f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016103c6565b506109ef838383610d3f565b6097545f906001600160a01b0316610b5657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015610bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd191906111da565b905081158015610be857506001600160a01b038116155b1561052e57604051632b0d65db60e01b815267ffffffffffffffff85166004820152602481018490526044016103c6565b60405162580a9560e71b815260040160405180910390fd5b6033546001600160a01b031633146105b25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c6565b606580546001600160a01b031916905561051c81610d69565b6001600160a01b0381163b610d115760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016103c6565b5f8051602061126583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610d4883610dba565b5f82511180610d545750805b156109ef57610d638383610df9565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610dc381610ca4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061052e83836040518060600160405280602781526020016112856027913960605f80856001600160a01b031685604051610e359190611217565b5f60405180830381855af49150503d805f8114610e6d576040519150601f19603f3d011682016040523d82523d5f602084013e610e72565b606091505b5091509150610e8386838387610e8d565b9695505050505050565b60608315610efb5782515f03610ef4576001600160a01b0385163b610ef45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c6565b5081610f05565b610f058383610f0d565b949350505050565b815115610f1d5781518083602001fd5b8060405162461bcd60e51b81526004016103c69190611232565b6001600160a01b038116811461051c575f80fd5b5f60208284031215610f5b575f80fd5b813561052e81610f37565b803567ffffffffffffffff81168114610f7d575f80fd5b919050565b5f8060408385031215610f93575f80fd5b610f9c83610f66565b946020939093013593505050565b80358015158114610f7d575f80fd5b5f805f60608486031215610fcb575f80fd5b610fd484610f66565b925060208401359150610fe960408501610faa565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611017575f80fd5b823561102281610f37565b9150602083013567ffffffffffffffff8082111561103e575f80fd5b818501915085601f830112611051575f80fd5b81358181111561106357611063610ff2565b604051601f8201601f19908116603f0116810190838211818310171561108b5761108b610ff2565b816040528281528860208487010111156110a3575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156110d5575f80fd5b823591506110e560208401610faa565b90509250929050565b5f805f60608486031215611100575f80fd5b61110984610f66565b925060208401359150604084013561112081610f37565b809150509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f602082840312156111d3575f80fd5b5051919050565b5f602082840312156111ea575f80fd5b815161052e81610f37565b5f5b8381101561120f5781810151838201526020016111f7565b50505f910152565b5f82516112288184602087016111f5565b9190910192915050565b602081525f82518060208401526112508160408501602087016111f5565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220cc98ce1f870c6bb16d1d5f2f7fbcc9dcf424754d8f8ecafbdf9491cb4cfd521764736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0xc64d73fae391b0ac595df47d373c227e7f86156e3d98ea2db53384d097ed1368": "0x0000000000000000000000001670010000000000000000000000000000000001", + "0x874594376407a7a3ecea7d4704f3d74c6c46d5ebede74ed82e228810d8de14e8": "0x0000000000000000000000001670010000000000000000000000000000000002", + "0x2723bcf67bd1580da6815ff7d2e86d877ad3a715975e5ec695c979712859d633": "0x0000000000000000000000001670010000000000000000000000000000000003", + "0x0b9331c6e6848711b59bebda4cb38292225176ce8cfca5d6019d5b562dc3ed9e": "0x0000000000000000000000001670010000000000000000000000000000000004", + "0x30e0422248fc90822e500074357003173b9f5edac82e6cc3679f5f9b5ae0843a": "0x0000000000000000000000001670010000000000000000000000000000000005", + "0xfe44fe816c0baa33783639d99e595cb6de463e186ec113aaed043e42d2c4e279": "0x0000000000000000000000000167001000000000000000000000000000010096", + "0xd2d6c2a7f8afdb0440c97960518d1f1133dc92587d9c6884dbaff6290e06319c": "0x0000000000000000000000000167001000000000000000000000000000010097", + "0x6db8284aa664f2ba76ffc7a2219f82b728ba258e79df0e93d3eb45b5cb231a69": "0x0000000000000000000000000167001000000000000000000000000000010098", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000006" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x6080604052600436106101e9575f3560e01c8063715018a611610108578063b916a0be1161009d578063d8beb5c31161006d578063d8beb5c314610611578063e30c397814610640578063eefbf17e1461065d578063f09a401614610694578063f2fde38b146106b3575f80fd5b8063b916a0be1461056b578063d0496d6a1461058a578063d1aaa5df146105d2578063d6ba38b2146105f2575f80fd5b80638da5cb5b116100d85780638da5cb5b146104d25780638e3881a9146104ef5780639939a2dc1461052d578063a86f9d9e1461054c575f80fd5b8063715018a61461046d5780637844845b1461048157806379ba5097146104aa5780638456cb59146104be575f80fd5b806348548f251161017e5780635c975abb1161014e5780635c975abb1461039f5780636be4eb55146103bf5780636c334e2e146103de5780636edbad04146103ff575f80fd5b806348548f251461033a5780634f1ef2861461035957806352d1902d1461036c57806357209f4814610380575f80fd5b80633ab76e9f116101b95780633ab76e9f146102955780633c6cf473146102cc5780633eb6b8cf146103075780633f4ba83a14610326575f80fd5b806316b205c1146101f4578063302ac39914610215578063324c058e146102475780633659cfe614610276575f80fd5b366101f057005b5f80fd5b3480156101ff575f80fd5b5061021361020e366004612db9565b6106d2565b005b348015610220575f80fd5b5061023461022f366004613075565b610c03565b6040519081526020015b60405180910390f35b348015610252575f80fd5b50610266610261366004612db9565b610c32565b604051901515815260200161023e565b348015610281575f80fd5b506102136102903660046130a6565b610ca7565b3480156102a0575f80fd5b506097546102b4906001600160a01b031681565b6040516001600160a01b03909116815260200161023e565b3480156102d7575f80fd5b506102fa6102e63660046130c1565b60fc6020525f908152604090205460ff1681565b60405161023e91906130ec565b348015610312575f80fd5b506102b461032136600461311f565b610d8d565b348015610331575f80fd5b50610213610d99565b348015610345575f80fd5b5061021361035436600461315c565b610e18565b6102136103673660046131cf565b610f4f565b348015610377575f80fd5b5061023461101e565b34801561038b575f80fd5b5061021361039a36600461321b565b6110d0565b3480156103aa575f80fd5b5061026660c954610100900460ff1660021490565b3480156103ca575f80fd5b506102666103d9366004612db9565b611229565b6103f16103ec366004613252565b61128a565b60405161023e9291906133f4565b34801561040a575f80fd5b506104466104193660046130c1565b6101006020525f90815260409020546001600160401b03811690600160401b90046001600160a01b031682565b604080516001600160401b0390931683526001600160a01b0390911660208301520161023e565b348015610478575f80fd5b50610213611591565b34801561048c575f80fd5b506104956115a2565b6040805192835260208301919091520161023e565b3480156104b5575f80fd5b50610213611634565b3480156104c9575f80fd5b506102136116ab565b3480156104dd575f80fd5b506033546001600160a01b03166102b4565b3480156104fa575f80fd5b5061050e61050936600461340c565b61171c565b6040805192151583526001600160a01b0390911660208301520161023e565b348015610538575f80fd5b50610266610547366004613252565b611748565b348015610557575f80fd5b506102b4610566366004613425565b611816565b348015610576575f80fd5b50610213610585366004613448565b611822565b348015610595575f80fd5b5061059e6119cf565b60408051825181526020808401516001600160a01b031690820152918101516001600160401b03169082015260600161023e565b3480156105dd575f80fd5b506102346105ec3660046130c1565b60031890565b3480156105fd575f80fd5b5061021361060c366004612db9565b611a23565b34801561061c575f80fd5b5061026661062b3660046130a6565b60ff60208190525f9182526040909120541681565b34801561064b575f80fd5b506065546001600160a01b03166102b4565b348015610668575f80fd5b5060fb5461067c906001600160801b031681565b6040516001600160801b03909116815260200161023e565b34801561069f575f80fd5b506102136106ae36600461348b565b611e10565b3480156106be575f80fd5b506102136106cd3660046130a6565b611f1e565b60026106dc611f8f565b60ff16036106fd5760405163dfc60d8560e01b815260040160405180910390fd5b6107076002611fc8565b61071b60c954610100900460ff1660021490565b156107395760405163bae6e2a960e01b815260040160405180910390fd5b610749608084016060850161340c565b46816001600160401b03161461077257604051631c6c777560e31b815260040160405180910390fd5b5f61077f61022f866134b7565b90505f8082815260fc602052604090205460ff1660048111156107a4576107a46130d8565b146107c257604051630cfafbf960e01b815260040160405180910390fd5b5f6107de6d7369676e616c5f7365727669636560901b5f611816565b5f83815261010060205260408120549192506001600160401b039091169081151590806108096115a2565b91509150826108e05761082e858761082760608e0160408f0161340c565b8c8c61200a565b61084b57604051635ea5ecc760e01b815260040160405180910390fd5b42935081156108e0576040518060400160405280856001600160401b031681526020018b61014001355f146108805733610890565b61089060c08d0160a08e016130a6565b6001600160a01b039081169091525f88815261010060209081526040909120835181549490920151909216600160401b026001600160e01b03199093166001600160401b03909116179190911790555b811580159061090d57505f8681526101006020526040902054600160401b90046001600160a01b03163314155b1561091757908101905b61092a6001600160401b038516836134d6565b4210610b90576101408a0135158015610964575061094e60c08b0160a08c016130a6565b6001600160a01b0316336001600160a01b031614155b15610982576040516372b6e1c360e11b815260040160405180910390fd5b5f8681526101006020526040812080546001600160e01b0319169055806109af60e08d0160c08e016130a6565b6001600160a01b031614806109db5750306109d060e08d0160c08e016130a6565b6001600160a01b0316145b80610a0657506001600160a01b0386166109fb60e08d0160c08e016130a6565b6001600160a01b0316145b80610a3c575060ff5f610a1f60e08e0160c08f016130a6565b6001600160a01b0316815260208101919091526040015f205460ff165b15610a5857506101008a0135610a538760026120c7565b610abd565b5f610a6960c08d0160a08e016130a6565b6001600160a01b0316336001600160a01b031614610a8c578b6101400135610a8e565b5a5b9050610a9b8c898361220b565b15610ab057610aab8860026120c7565b610abb565b610abb8860016120c7565b505b5f80610ad06101008e0160e08f016130a6565b6001600160a01b031614610af457610aef6101008d0160e08e016130a6565b610b04565b610b0460c08d0160a08e016130a6565b90506001600160a01b0381163303610b3d57610b38610b28836101208f01356134d6565b6001600160a01b03831690612362565b610b5f565b610b4c336101208e0135612362565b610b5f6001600160a01b03821683612362565b60405188907fe7d1e1f435233f7a187624ac11afaf32ee0da368cef8a5625be394412f619254905f90a25050610bed565b82610bd457857f3a7420670ebb84feae884388421d5f63bb1f9e073c54c8103e9e2ca7a98346e58b5f604051610bc79291906136a0565b60405180910390a2610bed565b60405163714f083160e11b815260040160405180910390fd5b50505050505050610bfe6001611fc8565b505050565b5f81604051602001610c1591906136c3565b604051602081830303815290604052805190602001209050919050565b5f46610c44606086016040870161340c565b6001600160401b031614610c5957505f610ca0565b610c9d610c776d7369676e616c5f7365727669636560901b5f611816565b610c866105ec61022f886134b7565b610c96608088016060890161340c565b868661200a565b90505b9392505050565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000000001163003610cf85760405162461bcd60e51b8152600401610cef906136f9565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000000016001600160a01b0316610d405f8051602061397f833981519152546001600160a01b031690565b6001600160a01b031614610d665760405162461bcd60e51b8152600401610cef90613745565b610d6f8161236d565b604080515f80825260208201909252610d8a91839190612375565b50565b5f610c9d8484846124df565b610dad60c954610100900460ff1660021490565b610dca5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610e16336125cb565b565b6e6272696467655f7761746368646f6760881b610e3d6033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015610e7a5750610e64816001611816565b6001600160a01b0316336001600160a01b031614155b15610e9857604051630d85cccf60e11b815260040160405180910390fd5b5f82610ea45742610ead565b6001600160401b035b90505f5b84811015610f47575f868683818110610ecc57610ecc613791565b602090810292909201355f8181526101008452604090819020805467ffffffffffffffff19166001600160401b0389161790558051828152891515948101949094529093507f3d7eb9ac1cd3da1c44f39d566b6364f64e5a71bfc4dc99effcbd176c1cafdf1c9201905060405180910390a150600101610eb1565b505050505050565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000000001163003610f975760405162461bcd60e51b8152600401610cef906136f9565b7f00000000000000000000000001670010000000000000000000000000000000016001600160a01b0316610fdf5f8051602061397f833981519152546001600160a01b031690565b6001600160a01b0316146110055760405162461bcd60e51b8152600401610cef90613745565b61100e8261236d565b61101a82826001612375565b5050565b5f306001600160a01b037f000000000000000000000000016700100000000000000000000000000000000116146110bd5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610cef565b505f8051602061397f8339815191525b90565b6e6272696467655f7761746368646f6760881b6110f56033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015611132575061111c816001611816565b6001600160a01b0316336001600160a01b031614155b1561115057604051630d85cccf60e11b815260040160405180910390fd5b600261115a611f8f565b60ff160361117b5760405163dfc60d8560e01b815260040160405180910390fd5b6111856002611fc8565b6001600160a01b0383165f90815260ff602081905260409091205483151591161515036111c5576040516319d893ad60e21b815260040160405180910390fd5b6001600160a01b0383165f81815260ff6020908152604091829020805460ff191686151590811790915591519182527f7113ce15c395851033544a97557341cdc71886964b54ff108a685d359ed4cdf8910160405180910390a2610bfe6001611fc8565b5f4661123b608086016060870161340c565b6001600160401b03161461125057505f610ca0565b610c9d61126e6d7369676e616c5f7365727669636560901b5f611816565b61127a61022f876134b7565b610c96606088016040890161340c565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820181905261018082015260026112fa611f8f565b60ff160361131b5760405163dfc60d8560e01b815260040160405180910390fd5b6113256002611fc8565b61133960c954610100900460ff1660021490565b156113575760405163bae6e2a960e01b815260040160405180910390fd5b5f61136860a08501608086016130a6565b6001600160a01b0316148061139457505f61138960c0850160a086016130a6565b6001600160a01b0316145b156113b257604051633c4f94dd60e11b815260040160405180910390fd5b5f6113c6610509608086016060870161340c565b509050806113e757604051631c6c777560e31b815260040160405180910390fd5b466113f8608086016060870161340c565b6001600160401b03160361141f57604051631c6c777560e31b815260040160405180910390fd5b5f6114346101208601356101008701356134d6565b905034811461145657604051634ac2abdf60e11b815260040160405180910390fd5b61145f856134b7565b60fb80549194506001600160801b03909116905f61147c836137a5565b82546101009290920a6001600160801b03818102199093169183160217909155168352336020840152466001600160401b031660408401526114bd83610c03565b93506114da6d7369676e616c5f7365727669636560901b5f611816565b6001600160a01b03166366ca2bc0856040518263ffffffff1660e01b815260040161150791815260200190565b6020604051808303815f875af1158015611523573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061154791906137ca565b50837f9a4c6dce9e49d66f9d79b5f213b08c30c2bcef51424e23934a80f4865e1f70398460405161157891906137e1565b60405180910390a2505061158c6001611fc8565b915091565b611599612649565b610e165f6126a3565b5f80466001036115b85750610e10916101809150565b46600214806115c75750466004145b806115d25750466005145b806115dd575046602a145b806115e9575046614268145b806115f657504662aa36a7145b156116075750610708916101809150565b617e2c461015801561161b5750617e904611155b1561162c575061012c916101809150565b505f91829150565b60655433906001600160a01b031681146116a25760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610cef565b610d8a816126a3565b6116bf60c954610100900460ff1660021490565b156116dd5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610e05565b5f80611733836562726964676560d01b6001610d8d565b6001600160a01b038116151594909350915050565b5f4661175a606084016040850161340c565b6001600160401b03161461176f57505f919050565b61178a6d7369676e616c5f7365727669636560901b5f611816565b6001600160a01b03166332676bc6306117a561022f866134b7565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156117ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181091906137f3565b92915050565b5f610ca04684846124df565b600261182c611f8f565b60ff160361184d5760405163dfc60d8560e01b815260040160405180910390fd5b6118576002611fc8565b61186b60c954610100900460ff1660021490565b156118895760405163bae6e2a960e01b815260040160405180910390fd5b611899608083016060840161340c565b46816001600160401b0316146118c257604051631c6c777560e31b815260040160405180910390fd5b61014083013515806118d15750815b15611917576118e660c0840160a085016130a6565b6001600160a01b0316336001600160a01b031614611917576040516372b6e1c360e11b815260040160405180910390fd5b5f61192461022f856134b7565b905060015f82815260fc602052604090205460ff16600481111561194a5761194a6130d8565b1461196857604051636e10a9f360e01b815260040160405180910390fd5b61197384825a61220b565b15611988576119838160026120c7565b611999565b8215611999576119998160036120c7565b60405181907f72d1525c4df70aedf1877ec89702311c795a01c082917308a30fb40059da2cc7905f90a2505061101a6001611fc8565b604080516060810182525f80825260208201819052918101919091526119f36126bc565b80519091501580611a05575080515f19145b156110cd57604051635ceed17360e01b815260040160405180910390fd5b6002611a2d611f8f565b60ff1603611a4e5760405163dfc60d8560e01b815260040160405180910390fd5b611a586002611fc8565b611a6c60c954610100900460ff1660021490565b15611a8a5760405163bae6e2a960e01b815260040160405180910390fd5b611a9a606084016040850161340c565b46816001600160401b031614611ac357604051631c6c777560e31b815260040160405180910390fd5b5f611ad061022f866134b7565b90505f8082815260fc602052604090205460ff166004811115611af557611af56130d8565b14611b1357604051630cfafbf960e01b815260040160405180910390fd5b5f81815261010060205260409020546001600160401b031680151580611c4b575f611b4f6d7369676e616c5f7365727669636560901b5f611816565b604051631933b5e360e11b8152306004820152602481018690529091506001600160a01b038216906332676bc690604401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf91906137f3565b611bdc5760405163ab035ad560e01b815260040160405180910390fd5b60038418611bfc8282611bf560808d0160608e0161340c565b8b8b61200a565b611c195760405163f149234f60e01b815260040160405180910390fd5b50505f83815261010060205260409020805467ffffffffffffffff1916426001600160401b0381169190911790915591505b5f611c546115a2565b509050611c6a6001600160401b038416826134d6565b4210611dc0575f8481526101006020908152604080832080546001600160e01b031916905560fc825291829020805460ff19166004179055611ccc91631e37aef160e11b91611cbd918c01908c016130a6565b6001600160a01b0316906127b0565b15611d6957611ceb8430611ce660608c0160408d0161340c565b61283d565b611cfb6040890160208a016130a6565b6001600160a01b0316633c6f5de28961010001358a876040518463ffffffff1660e01b8152600401611d2e92919061380e565b5f604051808303818588803b158015611d45575f80fd5b505af1158015611d57573d5f803e3d5ffd5b5050505050611d64612908565b611d91565b611d91610100890135611d8260a08b0160808c016130a6565b6001600160a01b031690612362565b60405184907fc6fbc1fa0145a394c9c414b2ae7bd634eb50dd888938bcd75692ae427b680fa2905f90a2611e01565b81610bd457837f3a7420670ebb84feae884388421d5f63bb1f9e073c54c8103e9e2ca7a98346e5896001604051611df89291906136a0565b60405180910390a25b5050505050610bfe6001611fc8565b5f54610100900460ff1615808015611e2e57505f54600160ff909116105b80611e475750303b158015611e4757505f5460ff166001145b611eaa5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610cef565b5f805460ff191660011790558015611ecb575f805461ff0019166101001790555b611ed58383612927565b8015610bfe575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b611f26612649565b606580546001600160a01b0383166001600160a01b03199091168117909155611f576033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f46600103611fbe57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b46600103611ff657807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f8084612021866562726964676560d01b5f610d8d565b87868660405160240161203895949392919061382f565b60408051601f198184030181529181526020820180516001600160e01b031663910af6ed60e01b179052519091506001600160a01b0388169061207c908390613865565b5f60405180830381855afa9150503d805f81146120b4576040519150601f19603f3d011682016040523d82523d5f602084013e6120b9565b606091505b509098975050505050505050565b8060048111156120d9576120d96130d8565b5f83815260fc602052604090205460ff1660048111156120fb576120fb6130d8565b03612104575050565b5f82815260fc60205260409020805482919060ff1916600183600481111561212e5761212e6130d8565b0217905550817f6c51882bc2ed67617f77a1e9b9a25d2caad8448647ecb093b357a603b25756348260405161216391906130ec565b60405180910390a2600381600481111561217f5761217f6130d8565b0361101a5761219f6d7369676e616c5f7365727669636560901b5f611816565b60405163019b28af60e61b81526003841860048201526001600160a01b0391909116906366ca2bc0906024016020604051808303815f875af11580156121e7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bfe91906137ca565b5f815f0361222c576040516308c2ad5360e01b815260040160405180910390fd5b3061223d60408601602087016130a6565b6001600160a01b03160361225357612253613880565b6122778361226760408701602088016130a6565b611ce6606088016040890161340c565b6004612287610160860186613894565b9050101580156122be5750637f07c94760e01b6122a8610160860186613894565b6122b1916138d6565b6001600160e01b03191614155b80156122e757506122e76122d860e0860160c087016130a6565b6001600160a01b03163b151590565b156122f357505f61235a565b61235661230660e0860160c087016130a6565b83610100870135604061231d6101608a018a613894565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061298692505050565b5090505b610ca0612908565b61101a82825a612a0b565b610d8a612649565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156123a857610bfe83612a75565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612402575060408051601f3d908101601f191682019092526123ff918101906137ca565b60015b6124655760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610cef565b5f8051602061397f83398151915281146124d35760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610cef565b50610bfe838383612b10565b6097545f906001600160a01b031661250a57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015612560573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125849190613906565b90508115801561259b57506001600160a01b038116155b15610ca057604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610cef565b6c313934b233b2afb830bab9b2b960991b6125ee6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561262b5750612615816001611816565b6001600160a01b0316336001600160a01b031614155b1561101a57604051630d85cccf60e11b815260040160405180910390fd5b6033546001600160a01b03163314610e165760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cef565b606580546001600160a01b0319169055610d8a81612b34565b604080516060810182525f8082526020820181905291810191909152466001036127745750604080516060810182527fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2b95c81526001600160a01b037fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2ba5c1660208201526001600160401b037fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2bb5c169181019190915290565b506040805160608101825260fd54815260fe546001600160a01b0381166020830152600160a01b90046001600160401b03169181019190915290565b5f6001600160a01b0383163b6127c757505f611810565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015612831575060408051601f3d908101601f1916820190925261282e918101906137f3565b60015b15611810579392505050565b466001036128b357827fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2b95d817fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2ba5d807fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2bb5d505050565b604080516060810182528481526001600160a01b0393909316602084018190526001600160401b0392909216920182905260fd9290925560fe80546001600160e01b031916909217600160a01b909102179055565b4660010361291b57610e165f808061283d565b610e165f19808061283d565b5f54610100900460ff1661294d5760405162461bcd60e51b8152600401610cef90613921565b61295682612b85565b6001600160a01b03811661297d576040516375cabfef60e11b815260040160405180910390fd5b61101a81612bb5565b5f60605f805f8661ffff166001600160401b038111156129a8576129a8612e47565b6040519080825280601f01601f1916602001820160405280156129d2576020820181803683370190505b5090505f808751602089018b8e8ef191503d9250868311156129f2578692505b828152825f602083013e90999098509650505050505050565b6001600160a01b038316612a3257604051634c67134d60e11b815260040160405180910390fd5b5f612a4e8483856040805180602001604052805f815250612986565b50905080612a6f57604051634c67134d60e11b815260040160405180910390fd5b50505050565b6001600160a01b0381163b612ae25760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610cef565b5f8051602061397f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612b1983612c25565b5f82511180612b255750805b15610bfe57612a6f8383612c64565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b612ba36001600160a01b03821615612b9d57816126a3565b336126a3565b5060c9805461ff001916610100179055565b5f54610100900460ff16612bdb5760405162461bcd60e51b8152600401610cef90613921565b6001600160401b03461115612c035760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b612c2e81612a75565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610ca0838360405180606001604052806027815260200161399f6027913960605f80856001600160a01b031685604051612ca09190613865565b5f60405180830381855af49150503d805f8114612cd8576040519150601f19603f3d011682016040523d82523d5f602084013e612cdd565b606091505b5091509150612cee86838387612cf8565b9695505050505050565b60608315612d665782515f03612d5f576001600160a01b0385163b612d5f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cef565b5081612d70565b612d708383612d78565b949350505050565b815115612d885781518083602001fd5b8060405162461bcd60e51b8152600401610cef919061396c565b5f6101a08284031215612db3575f80fd5b50919050565b5f805f60408486031215612dcb575f80fd5b83356001600160401b0380821115612de1575f80fd5b612ded87838801612da2565b94506020860135915080821115612e02575f80fd5b818601915086601f830112612e15575f80fd5b813581811115612e23575f80fd5b876020828501011115612e34575f80fd5b6020830194508093505050509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b0381118282101715612e7e57612e7e612e47565b60405290565b80356001600160801b0381168114612e9a575f80fd5b919050565b6001600160a01b0381168114610d8a575f80fd5b8035612e9a81612e9f565b80356001600160401b0381168114612e9a575f80fd5b5f82601f830112612ee3575f80fd5b81356001600160401b0380821115612efd57612efd612e47565b604051601f8301601f19908116603f01168101908282118183101715612f2557612f25612e47565b81604052838152866020858801011115612f3d575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6101a08284031215612f6d575f80fd5b612f75612e5b565b9050612f8082612e84565b8152612f8e60208301612eb3565b6020820152612f9f60408301612ebe565b6040820152612fb060608301612ebe565b6060820152612fc160808301612eb3565b6080820152612fd260a08301612eb3565b60a0820152612fe360c08301612eb3565b60c0820152612ff460e08301612eb3565b60e0820152610100828101359082015261012080830135908201526101408083013590820152610160808301356001600160401b0380821115613035575f80fd5b61304186838701612ed4565b8385015261018092508285013591508082111561305c575f80fd5b5061306985828601612ed4565b82840152505092915050565b5f60208284031215613085575f80fd5b81356001600160401b0381111561309a575f80fd5b612d7084828501612f5c565b5f602082840312156130b6575f80fd5b8135610ca081612e9f565b5f602082840312156130d1575f80fd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b602081016005831061310c57634e487b7160e01b5f52602160045260245ffd5b91905290565b8015158114610d8a575f80fd5b5f805f60608486031215613131575f80fd5b61313a84612ebe565b925060208401359150604084013561315181613112565b809150509250925092565b5f805f6040848603121561316e575f80fd5b83356001600160401b0380821115613184575f80fd5b818601915086601f830112613197575f80fd5b8135818111156131a5575f80fd5b8760208260051b85010111156131b9575f80fd5b6020928301955093505084013561315181613112565b5f80604083850312156131e0575f80fd5b82356131eb81612e9f565b915060208301356001600160401b03811115613205575f80fd5b61321185828601612ed4565b9150509250929050565b5f806040838503121561322c575f80fd5b823561323781612e9f565b9150602083013561324781613112565b809150509250929050565b5f60208284031215613262575f80fd5b81356001600160401b03811115613277575f80fd5b612d7084828501612da2565b5f5b8381101561329d578181015183820152602001613285565b50505f910152565b5f81518084526132bc816020860160208601613283565b601f01601f19169290920160200192915050565b80516001600160801b031682525f6101a060208301516132fb60208601826001600160a01b03169052565b50604083015161331660408601826001600160401b03169052565b50606083015161333160608601826001600160401b03169052565b50608083015161334c60808601826001600160a01b03169052565b5060a083015161336760a08601826001600160a01b03169052565b5060c083015161338260c08601826001600160a01b03169052565b5060e083015161339d60e08601826001600160a01b03169052565b50610100838101519085015261012080840151908501526101408084015190850152610160808401518186018390526133d8838701826132a5565b925050506101808084015185830382870152612cee83826132a5565b828152604060208201525f610c9d60408301846132d0565b5f6020828403121561341c575f80fd5b610ca082612ebe565b5f8060408385031215613436575f80fd5b82359150602083013561324781613112565b5f8060408385031215613459575f80fd5b82356001600160401b0381111561346e575f80fd5b61347a85828601612da2565b925050602083013561324781613112565b5f806040838503121561349c575f80fd5b82356134a781612e9f565b9150602083013561324781612e9f565b5f6118103683612f5c565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611810576118106134c2565b5f808335601e198436030181126134fe575f80fd5b83016020810192503590506001600160401b0381111561351c575f80fd5b80360382131561352a575f80fd5b9250929050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f6101a06135778461356a85612e84565b6001600160801b03169052565b61358360208401612eb3565b6001600160a01b0316602085015261359d60408401612ebe565b6001600160401b031660408501526135b760608401612ebe565b6001600160401b031660608501526135d160808401612eb3565b6001600160a01b031660808501526135eb60a08401612eb3565b6001600160a01b031660a085015261360560c08401612eb3565b6001600160a01b031660c085015261361f60e08401612eb3565b6001600160a01b031660e085015261010083810135908501526101208084013590850152610140808401359085015261016061365d818501856134e9565b838388015261366f8488018284613531565b9350505050610180613683818501856134e9565b86840383880152613695848284613531565b979650505050505050565b604081525f6136b26040830185613559565b905082151560208301529392505050565b60408152600d60408201526c5441494b4f5f4d45535341474560981b6060820152608060208201525f610ca060808301846132d0565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52603260045260245ffd5b5f6001600160801b038083168181036137c0576137c06134c2565b6001019392505050565b5f602082840312156137da575f80fd5b5051919050565b602081525f610ca060208301846132d0565b5f60208284031215613803575f80fd5b8151610ca081613112565b604081525f6138206040830185613559565b90508260208301529392505050565b6001600160401b038616815260018060a01b0385166020820152836040820152608060608201525f613695608083018486613531565b5f8251613876818460208701613283565b9190910192915050565b634e487b7160e01b5f52600160045260245ffd5b5f808335601e198436030181126138a9575f80fd5b8301803591506001600160401b038211156138c2575f80fd5b60200191503681900382131561352a575f80fd5b6001600160e01b031981358181169160048510156138fe5780818660040360031b1b83161692505b505092915050565b5f60208284031215613916575f80fd5b8151610ca081612e9f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b602081525f610ca060208301846132a556fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122002e4e1af6a15e5a9ab300edee272e7da12dae8b08e4d11c6e01741b46399a4fe64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x033b25902da0379e68000000" + }, + "0x0167001000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x60806040526004361062000163575f3560e01c8063715018a611620000c2578063a86f9d9e1162000076578063a86f9d9e14620003f8578063caec3e4e146200041c578063e30c3978146200044f578063f09a4016146200046e578063f2fde38b1462000492578063fa233d0c14620004b6575f80fd5b8063715018a6146200034657806379ba5097146200035d5780637f07c94714620003745780638456cb59146200038b5780638da5cb5b14620003a25780639aa8605c14620003c1575f80fd5b80633eb6b8cf116200011a5780633eb6b8cf14620002775780633f4ba83a146200029b5780634f1ef28614620002b257806352d1902d14620002c95780635c975abb14620002e057806367090ccf1462000302575f80fd5b806301ffc9a7146200016757806306fdde0314620001b05780630ecd8be914620001dc5780633659cfe614620002195780633ab76e9f146200023f5780633c6f5de21462000260575b5f80fd5b34801562000173575f80fd5b506200019b6200018536600462002fdc565b6001600160e01b031916631e37aef160e11b1490565b60405190151581526020015b60405180910390f35b348015620001bc575f80fd5b506a195c98cc8c17dd985d5b1d60aa1b5b604051908152602001620001a7565b348015620001e8575f80fd5b5062000200620001fa3660046200301a565b620004dc565b6040516001600160a01b039091168152602001620001a7565b34801562000225575f80fd5b506200023d6200023736600462003071565b62000bb3565b005b3480156200024b575f80fd5b5060975462000200906001600160a01b031681565b6200023d620002713660046200308f565b62000ca5565b34801562000283575f80fd5b506200020062000295366004620030fb565b62000e4d565b348015620002a7575f80fd5b506200023d62000e65565b6200023d620002c336600462003258565b62000ee8565b348015620002d5575f80fd5b50620001cd62000fbf565b348015620002ec575f80fd5b506200019b60c954610100900460ff1660021490565b3480156200030e575f80fd5b506200020062000320366004620032aa565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000352575f80fd5b506200023d62001074565b34801562000369575f80fd5b506200023d62001089565b6200023d62000385366004620032d0565b62001104565b34801562000397575f80fd5b506200023d62001297565b348015620003ae575f80fd5b506033546001600160a01b031662000200565b348015620003cd575f80fd5b50620003e5620003df36600462003071565b6200130b565b604051620001a795949392919062003391565b34801562000404575f80fd5b506200020062000416366004620033ee565b62001470565b34801562000428575f80fd5b506200019b6200043a36600462003071565b61012f6020525f908152604090205460ff1681565b3480156200045b575f80fd5b506065546001600160a01b031662000200565b3480156200047a575f80fd5b506200023d6200048c36600462003414565b6200147e565b3480156200049e575f80fd5b506200023d620004b036600462003071565b62001596565b620004cd620004c736600462003433565b6200160a565b604051620001a791906200346d565b5f6002620004e962001a94565b60ff16036200050b5760405163dfc60d8560e01b815260040160405180910390fd5b62000517600262001ace565b6200052c60c954610100900460ff1660021490565b156200054b5760405163bae6e2a960e01b815260040160405180910390fd5b6200055562001b11565b6001600160a01b03821615806200058c57506001600160a01b038281165f90815261012d6020526040902054600160401b90041615155b15620005ab5760405163dc63f98760e01b815260040160405180910390fd5b6001600160a01b0382165f90815261012f602052604090205460ff1615620005e6576040516375c42fc160e01b815260040160405180910390fd5b6033546001600160a01b03166001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000638573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200065e9190620035a0565b6001600160a01b031614620006865760405163c0507c1760e01b815260040160405180910390fd5b61012e5f620006996020860186620035be565b6001600160401b031681526020019081526020015f205f846020016020810190620006c5919062003071565b6001600160a01b03908116825260208201929092526040015f2054169050801562000a50576001600160a01b038181165f90815261012d60209081526040808320815160a08101835281546001600160401b0381168252600160401b810490961693810193909352600160e01b90940460ff1690820152600183018054929391926060840191906200075790620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200078590620035dc565b8015620007d45780601f10620007aa57610100808354040283529160200191620007d4565b820191905f5260205f20905b815481529060010190602001808311620007b657829003601f168201915b50505050508152602001600282018054620007ef90620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200081d90620035dc565b80156200086c5780601f1062000842576101008083540402835291602001916200086c565b820191905f5260205f20905b8154815290600101906020018083116200084e57829003601f168201915b50505050508152505090508360400160208101906200088c919062003632565b60ff16816040015160ff16141580620008d65750620008af606085018562003650565b604051620008bf9291906200369c565b604051809103902081606001518051906020012014155b80620009135750620008ec608085018562003650565b604051620008fc9291906200369c565b604051809103902081608001518051906020012014155b156200093257604051632f9d1d7b60e11b815260040160405180910390fd5b6001600160a01b0383165f90815261012d6020526040812080546001600160e81b03191681559062000968600183018262002f7c565b62000977600283015f62002f7c565b50506001600160a01b038281165f81815261012f6020526040808220805460ff191660011790555163b8f2e0c560e01b8152928616600484015260248301529063b8f2e0c5906044015f604051808303815f87803b158015620009d8575f80fd5b505af1158015620009eb573d5f803e3d5ffd5b505060405163b8f2e0c560e01b81526001600160a01b038581166004830152600160248301528616925063b8f2e0c591506044015f604051808303815f87803b15801562000a37575f80fd5b505af115801562000a4a573d5f803e3d5ffd5b50505050505b6001600160a01b0382165f90815261012d60205260409020839062000a768282620037c0565b5082905061012e5f62000a8d6020870187620035be565b6001600160401b031681526020019081526020015f205f85602001602081019062000ab9919062003071565b6001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555082602001602081019062000b10919062003071565b6001600160a01b031662000b286020850185620035be565b6001600160401b03167f031d68e1805917560c34a5f55a7dd91bef98f911190ed02cdbb53caedae6c39d838562000b63606089018962003650565b62000b7260808b018b62003650565b62000b8460608d0160408e0162003632565b60405162000b999796959493929190620038bd565b60405180910390a362000bad600162001ace565b92915050565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000216300362000c075760405162461bcd60e51b815260040162000bfe9062003918565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000000026001600160a01b031662000c515f805160206200468b833981519152546001600160a01b031690565b6001600160a01b03161462000c7a5760405162461bcd60e51b815260040162000bfe9062003964565b62000c858162001b6d565b604080515f8082526020820190925262000ca29183919062001b77565b50565b600262000cb162001a94565b60ff160362000cd35760405163dfc60d8560e01b815260040160405180910390fd5b62000cdf600262001ace565b62000cf460c954610100900460ff1660021490565b1562000d135760405163bae6e2a960e01b815260040160405180910390fd5b62000d1d62001cee565b505f62000d2f61016084018462003650565b62000d3f916004908290620039b0565b81019062000d4e9190620039d9565b90505f808280602001905181019062000d68919062003a71565b9350505091505f62000d908387608001602081019062000d89919062003071565b8462001de5565b905062000dbe61010087013562000dae60a0890160808a0162003071565b6001600160a01b03169062001e91565b62000dd060a087016080880162003071565b6001600160a01b0316857f3dea0f5955b148debf6212261e03bd80eaf8534bee43780452d16637dcc22dd58560200151848660405162000e31939291906001600160a01b039384168152919092166020820152604081019190915260600190565b60405180910390a35050505062000e49600162001ace565b5050565b5f62000e5b84848462001e9e565b90505b9392505050565b62000e7a60c954610100900460ff1660021490565b62000e985760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000ee63362001b6d565b565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000216300362000f335760405162461bcd60e51b815260040162000bfe9062003918565b7f00000000000000000000000001670010000000000000000000000000000000026001600160a01b031662000f7d5f805160206200468b833981519152546001600160a01b031690565b6001600160a01b03161462000fa65760405162461bcd60e51b815260040162000bfe9062003964565b62000fb18262001b6d565b62000e498282600162001b77565b5f306001600160a01b037f00000000000000000000000001670010000000000000000000000000000000021614620010605760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000bfe565b505f805160206200468b8339815191525b90565b6200107e62001b11565b62000ee65f62001f91565b60655433906001600160a01b03168114620010f95760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840162000bfe565b62000ca28162001f91565b60026200111062001a94565b60ff1603620011325760405163dfc60d8560e01b815260040160405180910390fd5b6200113e600262001ace565b6200115360c954610100900460ff1660021490565b15620011725760405163bae6e2a960e01b815260040160405180910390fd5b5f808080620011848587018762003b7d565b93509350935093505f6200119762001fac565b90506001600160a01b0383161580620011b857506001600160a01b03831630145b15620011d75760405163def9481360e01b815260040160405180910390fd5b5f620011e586858562001de5565b9050620011fc6001600160a01b0385163462001e91565b836001600160a01b0316856001600160a01b0316835f01517f75a051823424fc80e92556c41cb0ad977ae1dcb09c68a9c38acab86b11a69f8985604001518a6020015186896040516200127d94939291906001600160401b039490941684526001600160a01b03928316602085015291166040830152606082015260800190565b60405180910390a450505050505062000e49600162001ace565b620012ac60c954610100900460ff1660021490565b15620012cb5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000ed3565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b84046001600160a01b031693600160e01b900460ff169290916200135590620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200138390620035dc565b8015620013d25780601f10620013a857610100808354040283529160200191620013d2565b820191905f5260205f20905b815481529060010190602001808311620013b457829003601f168201915b505050505090806002018054620013e990620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200141790620035dc565b8015620014665780601f106200143c5761010080835404028352916020019162001466565b820191905f5260205f20905b8154815290600101906020018083116200144857829003601f168201915b5050505050905085565b5f62000e5e46848462001e9e565b5f54610100900460ff16158080156200149d57505f54600160ff909116105b80620014b85750303b158015620014b857505f5460ff166001145b6200151d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000bfe565b5f805460ff1916600117905580156200153f575f805461ff0019166101001790555b6200154b8383620020d1565b801562001591575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b620015a062001b11565b606580546001600160a01b0383166001600160a01b03199091168117909155620015d26033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820192909252610160810182905261018081019190915260026200168062001a94565b60ff1603620016a25760405163dfc60d8560e01b815260040160405180910390fd5b620016ae600262001ace565b620016c360c954610100900460ff1660021490565b15620016e25760405163bae6e2a960e01b815260040160405180910390fd5b81608001355f036200170757604051634299323b60e11b815260040160405180910390fd5b5f6200171a608084016060850162003071565b6001600160a01b03160362001742576040516303f8a7d360e01b815260040160405180910390fd5b61012f5f62001758608085016060860162003071565b6001600160a01b0316815260208101919091526040015f205460ff161562001793576040516375c42fc160e01b815260040160405180910390fd5b5f8080620017ca33620017ad608088016060890162003071565b620017bf6060890160408a0162003071565b886080013562002138565b604080516101a0810182525f808252602080830182905292820181905294975092955090935060608201906200180390890189620035be565b6001600160401b03168152602001336001600160a01b031681526020015f6001600160a01b03168860200160208101906200183f919062003071565b6001600160a01b03160362001855573362001867565b620018676040890160208a0162003071565b6001600160a01b03168152602090810190620018a2906200188b908a018a620035be565b6a195c98cc8c17dd985d5b1d60aa1b5b5f62000e4d565b6001600160a01b03168152602001620018c3610100890160e08a0162003071565b6001600160a01b03168152602001620018e160c08901353462003c7c565b815260c0880135602082015260a08801356040820152606081018690526080016200191161010089018962003650565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250939094525092935091506200196190506562726964676560d01b8262001470565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b81526004016200198f91906200346d565b5f6040518083038185885af1158015620019ab573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620019d5919081019062003cb3565b96509050620019eb606088016040890162003071565b60808701516001600160a01b039182169116827feb8a69f21b7a981e25f90d9f1e2ab7fa5bdbfddbc0ac160344145fc5caa6ddd262001a2e60208c018c620035be565b602089015162001a4560808e0160608f0162003071565b604080516001600160401b0390941684526001600160a01b0392831660208501529116908201526060810188905260800160405180910390a4505050505062001a8f600162001ace565b919050565b5f4660010362001ac457507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010362001afd57807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b6033546001600160a01b0316331462000ee65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000bfe565b62000ca262001b11565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001bad5762001591836200266f565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001c0a575060408051601f3d908101601f1916820190925262001c079181019062003e12565b60015b62001c6f5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000bfe565b5f805160206200468b833981519152811462001ce05760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000bfe565b50620015918383836200270d565b604080516060810182525f808252602082018190529181019190915262001d1f6562726964676560d01b5f62001470565b6001600160a01b0316336001600160a01b03161462001d5157604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001d8e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001db4919062003e2a565b60208101519091506001600160a01b031633146200107157604051632583296b60e01b815260040160405180910390fd5b5f46845f01516001600160401b03160362001e1c5750602083015162001e166001600160a01b03821684846200273d565b62000e5e565b62001e2784620027a2565b6040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052919250908216906340c10f19906044015f604051808303815f87803b15801562001e73575f80fd5b505af115801562001e86573d5f803e3d5ffd5b505050509392505050565b62000e4982825a620027e7565b6097545f906001600160a01b031662001eca57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001f21573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001f479190620035a0565b90508115801562001f5f57506001600160a01b038116155b1562000e5e57604051632b0d65db60e01b81526001600160401b03851660048201526024810184905260440162000bfe565b606580546001600160a01b031916905562000ca2816200284f565b604080516060810182525f808252602082018190529181019190915262001fdd6562726964676560d01b5f62001470565b6001600160a01b0316336001600160a01b0316146200200f57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156200204c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002072919062003e2a565b90505f6200209482604001516200189b6a195c98cc8c17dd985d5b1d60aa1b90565b9050806001600160a01b031682602001516001600160a01b031614620020cd57604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff16620020fa5760405162461bcd60e51b815260040162000bfe9062003e98565b6200210582620028a0565b6001600160a01b0381166200212d576040516375cabfef60e11b815260040160405180910390fd5b62000e4981620028d4565b6040805160a0810182525f80825260208083018290528284018290526060808401819052608084018190526001600160a01b03888116845261012d90925293822054600160401b9004161562002380576001600160a01b038681165f90815261012d6020908152604091829020825160a08101845281546001600160401b0381168252600160401b810490951692810192909252600160e01b90930460ff1691810191909152600182018054919291606084019190620021f890620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200222690620035dc565b8015620022755780601f106200224b5761010080835404028352916020019162002275565b820191905f5260205f20905b8154815290600101906020018083116200225757829003601f168201915b505050505081526020016002820180546200229090620035dc565b80601f0160208091040260200160405190810160405280929190818152602001828054620022be90620035dc565b80156200230d5780601f10620022e3576101008083540402835291602001916200230d565b820191905f5260205f20905b815481529060010190602001808311620022ef57829003601f168201915b505050919092525050604051632770a7eb60e21b815233600482015260248101879052919350506001600160a01b03871690639dc29fac906044015f604051808303815f87803b15801562002360575f80fd5b505af115801562002373573d5f803e3d5ffd5b50505050839050620025ef565b5f8690506040518060a00160405280466001600160401b03168152602001886001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620023ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002410919062003ee3565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562002454573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200247d919081019062003f01565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa158015620024be573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620024e7919081019062003f01565b90526040516370a0823160e01b815230600482015290935087905f906001600160a01b038316906370a0823190602401602060405180830381865afa15801562002533573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002559919062003e12565b9050620025726001600160a01b03831633308a62002948565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015620025b7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620025dd919062003e12565b620025e9919062003c7c565b93505050505b306001600160a01b0316637f07c9478389888560405160200162002617949392919062003f36565b60408051601f1981840301815290829052620026369160240162003fdb565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505092509450945094915050565b6001600160a01b0381163b620026de5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000bfe565b5f805160206200468b83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b620027188362002982565b5f82511180620027255750805b156200159157620027378383620029c3565b50505050565b6040516001600160a01b0383166024820152604481018290526200159190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620029eb565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b039081168552925290912054168062001a8f5762000bad8262002ac3565b6001600160a01b0383166200280f57604051634c67134d60e11b815260040160405180910390fd5b5f6200282d8483856040805180602001604052805f81525062002cd5565b509050806200273757604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620028c26001600160a01b03821615620028bb578162001f91565b3362001f91565b5060c9805461ff001916610100179055565b5f54610100900460ff16620028fd5760405162461bcd60e51b815260040162000bfe9062003e98565b6001600160401b03461115620029265760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6040516001600160a01b0380851660248301528316604482015260648101829052620027379085906323b872dd60e01b906084016200276a565b6200298d816200266f565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000e5e8383604051806060016040528060278152602001620046ab6027913962002d5f565b5f62002a41826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662002dd99092919063ffffffff16565b80519091501562001591578080602001905181019062002a62919062003fef565b620015915760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000bfe565b5f8062002ad86033546001600160a01b031690565b60975460208501518551604080880151606089015160808a0151925162002b1097966001600160a01b0316959493906024016200400d565b60408051601f198184030181529190526020810180516001600160e01b031663bb86ef9360e01b179052905062002b586c0627269646765645f657263323609c1b5f62001470565b8160405162002b679062002fb8565b62002b749291906200407c565b604051809103905ff08015801562002b8e573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d602090815260409182902087518154928901519389015160ff16600160e01b0260ff60e01b1994909516600160401b026001600160e01b03199093166001600160401b0390911617919091179190911691909117815560608501519193508491600182019062002c129082620040a1565b506080820151600282019062002c299082620040a1565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b0319168885169081179091559151885160608a015160808b0151848c01519451959850929095169516937fb6b427556e8cb0ebf9175da4bc48c64c4f56e44cfaf8c3ab5ebf8e2ea13090799362002cc793919291906200416d565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b0381111562002cfa5762002cfa6200313f565b6040519080825280601f01601f19166020018201604052801562002d25576020820181803683370190505b5090505f808751602089018b8e8ef191503d92508683111562002d46578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b03168560405162002d7d9190620041a9565b5f60405180830381855af49150503d805f811462002db7576040519150601f19603f3d011682016040523d82523d5f602084013e62002dbc565b606091505b509150915062002dcf8683838762002de9565b9695505050505050565b606062000e5b84845f8562002e70565b6060831562002e5c5782515f0362002e54576001600160a01b0385163b62002e545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000bfe565b508162002e68565b62002e68838362002f4f565b949350505050565b60608247101562002ed35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000bfe565b5f80866001600160a01b0316858760405162002ef09190620041a9565b5f6040518083038185875af1925050503d805f811462002f2c576040519150601f19603f3d011682016040523d82523d5f602084013e62002f31565b606091505b509150915062002f448783838762002de9565b979650505050505050565b81511562002f605781518083602001fd5b8060405162461bcd60e51b815260040162000bfe919062003fdb565b50805462002f8a90620035dc565b5f825580601f1062002f9a575050565b601f0160209004905f5260205f209081019062000ca2919062002fc6565b6104c480620041c783390190565b5b80821115620020cd575f815560010162002fc7565b5f6020828403121562002fed575f80fd5b81356001600160e01b03198116811462000e5e575f80fd5b6001600160a01b038116811462000ca2575f80fd5b5f80604083850312156200302c575f80fd5b82356001600160401b0381111562003042575f80fd5b830160a0818603121562003054575f80fd5b91506020830135620030668162003005565b809150509250929050565b5f6020828403121562003082575f80fd5b813562000e5e8162003005565b5f8060408385031215620030a1575f80fd5b82356001600160401b03811115620030b7575f80fd5b83016101a08186031215620030ca575f80fd5b946020939093013593505050565b6001600160401b038116811462000ca2575f80fd5b801515811462000ca2575f80fd5b5f805f606084860312156200310e575f80fd5b83356200311b81620030d8565b92506020840135915060408401356200313481620030ed565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160a081016001600160401b03811182821017156200317857620031786200313f565b60405290565b6040516101a081016001600160401b03811182821017156200317857620031786200313f565b604051601f8201601f191681016001600160401b0381118282101715620031cf57620031cf6200313f565b604052919050565b5f6001600160401b03821115620031f257620031f26200313f565b50601f01601f191660200190565b5f82601f83011262003210575f80fd5b8135620032276200322182620031d7565b620031a4565b8181528460208386010111156200323c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156200326a575f80fd5b8235620032778162003005565b915060208301356001600160401b0381111562003292575f80fd5b620032a08582860162003200565b9150509250929050565b5f8060408385031215620032bc575f80fd5b823591506020830135620030668162003005565b5f8060208385031215620032e2575f80fd5b82356001600160401b0380821115620032f9575f80fd5b818501915085601f8301126200330d575f80fd5b8135818111156200331c575f80fd5b8660208285010111156200332e575f80fd5b60209290920196919550909350505050565b5f5b838110156200335c57818101518382015260200162003342565b50505f910152565b5f81518084526200337d81602086016020860162003340565b601f01601f19169290920160200192915050565b6001600160401b03861681526001600160a01b038516602082015260ff8416604082015260a0606082018190525f90620033ce9083018562003364565b8281036080840152620033e2818562003364565b98975050505050505050565b5f806040838503121562003400575f80fd5b8235915060208301356200306681620030ed565b5f806040838503121562003426575f80fd5b8235620030548162003005565b5f6020828403121562003444575f80fd5b81356001600160401b038111156200345a575f80fd5b8201610120818503121562000e5e575f80fd5b60208152620034886020820183516001600160801b03169052565b5f6020830151620034a460408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101006200352b818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a061018080860182905291925090620035756101c086018462003364565b90860151858203601f19018387015290925062002dcf838262003364565b805162001a8f8162003005565b5f60208284031215620035b1575f80fd5b815162000e5e8162003005565b5f60208284031215620035cf575f80fd5b813562000e5e81620030d8565b600181811c90821680620035f157607f821691505b6020821081036200361057634e487b7160e01b5f52602260045260245ffd5b50919050565b60ff8116811462000ca2575f80fd5b803562001a8f8162003616565b5f6020828403121562003643575f80fd5b813562000e5e8162003616565b5f808335601e1984360301811262003666575f80fd5b8301803591506001600160401b0382111562003680575f80fd5b60200191503681900382131562003695575f80fd5b9250929050565b818382375f9101908152919050565b601f8211156200159157805f5260205f20601f840160051c81016020851015620036d25750805b601f840160051c820191505b81811015620036f3575f8155600101620036de565b5050505050565b6001600160401b038311156200371457620037146200313f565b6200372c83620037258354620035dc565b83620036ab565b5f601f84116001811462003760575f8515620037485750838201355b5f19600387901b1c1916600186901b178355620036f3565b5f83815260208120601f198716915b828110156200379157868501358255602094850194600190920191016200376f565b5086821015620037ae575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b8135620037cd81620030d8565b6001600160401b03811690508154816001600160401b031982161783556020840135620037fa8162003005565b68010000000000000000600160e01b03604091821b166001600160e01b0319831684178117855590850135620038308162003616565b60ff60e01b8160e01b1660ff60e01b19851662ffffff60e81b85161783171785555050505062003864606083018362003650565b62003874818360018601620036fa565b505062003885608083018362003650565b62002737818360028601620036fa565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0388811682528716602082015260a0604082018190525f90620038eb908301878962003895565b82810360608401526200390081868862003895565b91505060ff8316608083015298975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f8085851115620039bf575f80fd5b83861115620039cc575f80fd5b5050820193919092039150565b5f60208284031215620039ea575f80fd5b81356001600160401b0381111562003a00575f80fd5b62002e688482850162003200565b805162001a8f81620030d8565b805162001a8f8162003616565b5f82601f83011262003a38575f80fd5b815162003a496200322182620031d7565b81815284602083860101111562003a5e575f80fd5b62002e6882602083016020870162003340565b5f805f806080858703121562003a85575f80fd5b84516001600160401b038082111562003a9c575f80fd5b9086019060a0828903121562003ab0575f80fd5b62003aba62003153565b825162003ac781620030d8565b8152602083015162003ad98162003005565b602082015262003aec6040840162003a1b565b604082015260608301518281111562003b03575f80fd5b62003b118a82860162003a28565b60608301525060808301518281111562003b29575f80fd5b62003b378a82860162003a28565b608083015250955062003b509150506020860162003593565b925062003b606040860162003593565b6060959095015193969295505050565b803562001a8f8162003005565b5f805f806080858703121562003b91575f80fd5b84356001600160401b038082111562003ba8575f80fd5b9086019060a0828903121562003bbc575f80fd5b62003bc662003153565b823562003bd381620030d8565b8152602083013562003be58162003005565b602082015262003bf86040840162003625565b604082015260608301358281111562003c0f575f80fd5b62003c1d8a82860162003200565b60608301525060808301358281111562003c35575f80fd5b62003c438a82860162003200565b608083015250955062003c5c9150506020860162003b70565b925062003c6c6040860162003b70565b9396929550929360600135925050565b8181038181111562000bad57634e487b7160e01b5f52601160045260245ffd5b80516001600160801b038116811462001a8f575f80fd5b5f806040838503121562003cc5575f80fd5b8251915060208301516001600160401b038082111562003ce3575f80fd5b908401906101a0828703121562003cf8575f80fd5b62003d026200317e565b62003d0d8362003c9c565b815262003d1d6020840162003593565b602082015262003d306040840162003a0e565b604082015262003d436060840162003a0e565b606082015262003d566080840162003593565b608082015262003d6960a0840162003593565b60a082015262003d7c60c0840162003593565b60c082015262003d8f60e0840162003593565b60e0820152610100838101519082015261012080840151908201526101408084015190820152610160808401518381111562003dc9575f80fd5b62003dd78982870162003a28565b828401525050610180808401518381111562003df1575f80fd5b62003dff8982870162003a28565b8284015250508093505050509250929050565b5f6020828403121562003e23575f80fd5b5051919050565b5f6060828403121562003e3b575f80fd5b604051606081018181106001600160401b038211171562003e605762003e606200313f565b60405282518152602083015162003e778162003005565b6020820152604083015162003e8c81620030d8565b60408201529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f6020828403121562003ef4575f80fd5b815162000e5e8162003616565b5f6020828403121562003f12575f80fd5b81516001600160401b0381111562003f28575f80fd5b62002e688482850162003a28565b608081526001600160401b03855116608082015260018060a01b0360208601511660a082015260ff60408601511660c08201525f606086015160a060e084015262003f8661012084018262003364565b90506080870151607f198483030161010085015262003fa6828262003364565b9250505062003fc060208301866001600160a01b03169052565b6001600160a01b039390931660408201526060015292915050565b602081525f62000e5e602083018462003364565b5f6020828403121562004000575f80fd5b815162000e5e81620030ed565b6001600160a01b0388811682528781166020830152861660408201526001600160401b038516606082015260ff8416608082015260e060a082018190525f906200405a9083018562003364565b82810360c08401526200406e818562003364565b9a9950505050505050505050565b6001600160a01b03831681526040602082018190525f9062000e5b9083018462003364565b81516001600160401b03811115620040bd57620040bd6200313f565b620040d581620040ce8454620035dc565b84620036ab565b602080601f8311600181146200410b575f8415620040f35750858301515b5f19600386901b1c1916600185901b17855562004165565b5f85815260208120601f198616915b828110156200413b578886015182559484019460019091019084016200411a565b50858210156200415957878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b606081525f62004181606083018662003364565b828103602084015262004195818662003364565b91505060ff83166040830152949350505050565b5f8251620041bc81846020870162003340565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d882bf842f972377a47949b222d70f7df9fd5bdbf62dfddc31a07da24277734264736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x6080604052600436106200019b575f3560e01c80635c975abb11620000de5780638456cb591162000092578063a86f9d9e116200006a578063a86f9d9e14620004c9578063e30c397814620004ed578063f09a4016146200050c578063f2fde38b1462000530575f80fd5b80638456cb59146200045d5780638da5cb5b14620004745780639aa8605c1462000493575f80fd5b80635c975abb146200039c578063634da63a14620003be57806367090ccf14620003d4578063715018a6146200041857806379ba5097146200042f5780637f07c9471462000446575f80fd5b80633ab76e9f11620001525780633f4ba83a116200012a5780633f4ba83a146200033b5780634f1ef286146200035257806352d1902d146200036957806359f4a9071462000380575f80fd5b80633ab76e9f14620002c65780633c6f5de214620003005780633eb6b8cf1462000317575f80fd5b806301ffc9a7146200019f57806306fdde0314620001e85780631507cc471462000215578063150b7a02146200023b5780632ca069a514620002845780633659cfe614620002a0575b5f80fd5b348015620001ab575f80fd5b50620001d3620001bd3660046200276b565b6001600160e01b031916631e37aef160e11b1490565b60405190151581526020015b60405180910390f35b348015620001f4575f80fd5b506b195c98cdcc8c57dd985d5b1d60a21b5b604051908152602001620001df565b6200022c62000226366004620029aa565b62000554565b604051620001df919062002b2f565b34801562000247575f80fd5b506200026a6200025936600462002c9c565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001620001df565b34801562000290575f80fd5b506200026a636cdb3d1360e11b81565b348015620002ac575f80fd5b50620002c4620002be36600462002d11565b6200095e565b005b348015620002d2575f80fd5b50609754620002e7906001600160a01b031681565b6040516001600160a01b039091168152602001620001df565b620002c46200031136600462002d2f565b62000a50565b34801562000323575f80fd5b50620002e76200033536600462002d86565b62000c22565b34801562000347575f80fd5b50620002c462000c3a565b620002c46200036336600462002dca565b62000cbd565b34801562000375575f80fd5b506200020662000d94565b3480156200038c575f80fd5b506200026a6380ac58cd60e01b81565b348015620003a8575f80fd5b50620001d360c954610100900460ff1660021490565b348015620003ca575f80fd5b5062000206600a81565b348015620003e0575f80fd5b50620002e7620003f236600462002e1c565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000424575f80fd5b50620002c462000e49565b3480156200043b575f80fd5b50620002c462000e5e565b620002c46200045736600462002e4d565b62000ed9565b34801562000469575f80fd5b50620002c46200108a565b34801562000480575f80fd5b506033546001600160a01b0316620002e7565b3480156200049f575f80fd5b50620004b7620004b136600462002d11565b620010fe565b604051620001df949392919062002e8f565b348015620004d5575f80fd5b50620002e7620004e736600462002ee2565b62001259565b348015620004f9575f80fd5b506065546001600160a01b0316620002e7565b34801562000518575f80fd5b50620002c46200052a36600462002f08565b62001270565b3480156200053c575f80fd5b50620002c46200054e36600462002d11565b62001388565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082019290925261016081018290526101808101919091526002620005ca620013fc565b60ff1603620005ec5760405163dfc60d8560e01b815260040160405180910390fd5b620005f8600262001436565b6200060d60c954610100900460ff1660021490565b156200062c5760405163bae6e2a960e01b815260040160405180910390fd5b818060a001515181608001515114620006585760405163196e8a4160e31b815260040160405180910390fd5b600a8160800151511115620006805760405163e4a4c1c760e01b815260040160405180910390fd5b60608101516001600160a01b0316620006ac576040516303f8a7d360e01b815260040160405180910390fd5b5f5b83608001515181101562000706578360a001518181518110620006d557620006d562002f39565b60200260200101515f14620006fd57604051634299323b60e11b815260040160405180910390fd5b600101620006ae565b50606083015162000728906001600160a01b03166380ac58cd60e01b62001479565b6200074657604051633ee915f560e11b815260040160405180910390fd5b5f806200075433866200150c565b604080516101a0810182525f808252602080830182905292820181905289516001600160401b03166060830152336080830152918901519395509193509160a08201906001600160a01b0316620007ac5733620007b2565b87602001515b6001600160a01b03168152602001620007e6885f0151620007df6b195c98cdcc8c57dd985d5b1d60a21b90565b5f62000c22565b6001600160a01b031681526020018761010001516001600160a01b031681526020018760e00151346200081a919062002f4d565b81526020018760e0015181526020018760c00151815260200184815260200187610120015181525090505f6200085a6562726964676560d01b5f62001259565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b815260040162000888919062002b2f565b5f6040518083038185885af1158015620008a4573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620008ce919081019062002fe7565b809750819250505086604001516001600160a01b031686608001516001600160a01b0316827fabbf62a1459339f9ac59136d313a5ccd83d2706cc6d4c04d90642520169144dc896060015187602001518c606001518d608001518e60a001516040516200094095949392919062003182565b60405180910390a4505050505062000959600162001436565b919050565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000000003163003620009b25760405162461bcd60e51b8152600401620009a990620031de565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000000036001600160a01b0316620009fc5f8051602062003e9c833981519152546001600160a01b031690565b6001600160a01b03161462000a255760405162461bcd60e51b8152600401620009a9906200322a565b62000a3081620019d7565b604080515f8082526020820190925262000a4d91839190620019e1565b50565b600262000a5c620013fc565b60ff160362000a7e5760405163dfc60d8560e01b815260040160405180910390fd5b62000a8a600262001436565b62000a9f60c954610100900460ff1660021490565b1562000abe5760405163bae6e2a960e01b815260040160405180910390fd5b62000ac862001b58565b505f62000ada61016084018462003276565b62000aea916004908290620032bb565b81019062000af99190620032e4565b90505f808280602001905181019062000b1391906200337c565b9350505091505f62000b3b8387608001602081019062000b34919062002d11565b8462001c4f565b905062000b6961010087013562000b5960a0890160808a0162002d11565b6001600160a01b03169062001dd9565b62000b7b60a087016080880162002d11565b6001600160a01b0316857fe48bef18455e47bca14864ab6e82dffa29df148b051c09de95aec44ecf13598c8560200151848687516001600160401b0381111562000bc95762000bc962002794565b60405190808252806020026020018201604052801562000bf3578160200160208202803683370190505b5060405162000c06949392919062003486565b60405180910390a35050505062000c1e600162001436565b5050565b5f62000c3084848462001de6565b90505b9392505050565b62000c4f60c954610100900460ff1660021490565b62000c6d5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000cbb33620019d7565b565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000316300362000d085760405162461bcd60e51b8152600401620009a990620031de565b7f00000000000000000000000001670010000000000000000000000000000000036001600160a01b031662000d525f8051602062003e9c833981519152546001600160a01b031690565b6001600160a01b03161462000d7b5760405162461bcd60e51b8152600401620009a9906200322a565b62000d8682620019d7565b62000c1e82826001620019e1565b5f306001600160a01b037f0000000000000000000000000167001000000000000000000000000000000003161462000e355760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401620009a9565b505f8051602062003e9c8339815191525b90565b62000e5362001ed9565b62000cbb5f62001f35565b60655433906001600160a01b0316811462000ece5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401620009a9565b62000a4d8162001f35565b600262000ee5620013fc565b60ff160362000f075760405163dfc60d8560e01b815260040160405180910390fd5b62000f13600262001436565b62000f2860c954610100900460ff1660021490565b1562000f475760405163bae6e2a960e01b815260040160405180910390fd5b5f80808062000f5985870187620034c7565b93509350935093505f62000f6c62001f50565b90506001600160a01b038316158062000f8d57506001600160a01b03831630145b1562000fac5760405163def9481360e01b815260040160405180910390fd5b5f62000fba86858562001c4f565b905062000fd16001600160a01b0385163462001dd9565b836001600160a01b0316856001600160a01b0316835f01517f895f73e418d1bbbad2a311d085fad00e5d98a960e9f2afa4b942071d39bec43a85604001518a6020015186898a516001600160401b0381111562001032576200103262002794565b6040519080825280602002602001820160405280156200105c578160200160208202803683370190505b506040516200107095949392919062003182565b60405180910390a450505050505062000c1e600162001436565b6200109f60c954610100900460ff1660021490565b15620010be5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000ca8565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b03169291906200113e90620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200116c90620035c5565b8015620011bb5780601f106200119157610100808354040283529160200191620011bb565b820191905f5260205f20905b8154815290600101906020018083116200119d57829003601f168201915b505050505090806002018054620011d290620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200120090620035c5565b80156200124f5780601f1062001225576101008083540402835291602001916200124f565b820191905f5260205f20905b8154815290600101906020018083116200123157829003601f168201915b5050505050905084565b5f6200126746848462001de6565b90505b92915050565b5f54610100900460ff16158080156200128f57505f54600160ff909116105b80620012aa5750303b158015620012aa57505f5460ff166001145b6200130f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620009a9565b5f805460ff19166001179055801562001331575f805461ff0019166101001790555b6200133d838362002076565b801562001383575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6200139262001ed9565b606580546001600160a01b0383166001600160a01b03199091168117909155620013c46033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f466001036200142c57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b466001036200146557807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f6001600160a01b0383163b6200149257505f6200126a565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015620014ff575060408051601f3d908101601f19168201909252620014fc91810190620035ff565b60015b156200126a579392505050565b604080516080810182525f8082526020820152606091810182905280820182905260608301516001600160a01b039081165f90815261012d6020526040902054600160401b90041615620017925760608301516001600160a01b039081165f90815261012d6020908152604091829020825160808101845281546001600160401b0381168252600160401b9004909416918401919091526001810180549192840191620015b990620035c5565b80601f0160208091040260200160405190810160405280929190818152602001828054620015e790620035c5565b8015620016365780601f106200160c5761010080835404028352916020019162001636565b820191905f5260205f20905b8154815290600101906020018083116200161857829003601f168201915b505050505081526020016002820180546200165190620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200167f90620035c5565b8015620016ce5780601f10620016a457610100808354040283529160200191620016ce565b820191905f5260205f20905b815481529060010190602001808311620016b057829003601f168201915b50505050508152505090505f5b8360800151518110156200178b5783606001516001600160a01b0316639dc29fac868660800151848151811062001716576200171662002f39565b60200260200101516040518363ffffffff1660e01b8152600401620017509291906001600160a01b03929092168252602082015260400190565b5f604051808303815f87803b15801562001768575f80fd5b505af11580156200177b573d5f803e3d5ffd5b50505050806001019050620016db565b5062001952565b5f836060015190506040518060800160405280466001600160401b0316815260200185606001516001600160a01b03168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562001803573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200182c91908101906200361d565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa1580156200186d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200189691908101906200361d565b905291505f5b8460800151518110156200194f57816001600160a01b03166342842e0e873088608001518581518110620018d457620018d462002f39565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156200192c575f80fd5b505af11580156200193f573d5f803e3d5ffd5b505050508060010190506200189c565b50505b306001600160a01b0316637f07c94782868660400151876080015160405160200162001982949392919062003652565b60408051601f1981840301815290829052620019a191602401620036e1565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505091509250929050565b62000a4d62001ed9565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001a17576200138383620020dd565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001a74575060408051601f3d908101601f1916820190925262001a7191810190620036f5565b60015b62001ad95760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401620009a9565b5f8051602062003e9c833981519152811462001b4a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401620009a9565b50620013838383836200217b565b604080516060810182525f808252602082018190529181019190915262001b896562726964676560d01b5f62001259565b6001600160a01b0316336001600160a01b03161462001bbb57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001bf8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001c1e91906200370d565b60208101519091506001600160a01b0316331462000e4657604051632583296b60e01b815260040160405180910390fd5b5f46845f01516001600160401b03160362001d1e575060208301515f5b825181101562001d1757816001600160a01b03166342842e0e308686858151811062001c9c5762001c9c62002f39565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b15801562001cf4575f80fd5b505af115801562001d07573d5f803e3d5ffd5b5050505080600101905062001c6c565b5062000c33565b62001d2984620021ab565b90505f5b825181101562001dd157816001600160a01b03166340c10f198585848151811062001d5c5762001d5c62002f39565b60200260200101516040518363ffffffff1660e01b815260040162001d969291906001600160a01b03929092168252602082015260400190565b5f604051808303815f87803b15801562001dae575f80fd5b505af115801562001dc1573d5f803e3d5ffd5b5050505080600101905062001d2d565b509392505050565b62000c1e82825a620021f0565b6097545f906001600160a01b031662001e1257604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001e69573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001e8f91906200377b565b90508115801562001ea757506001600160a01b038116155b1562000c3357604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401620009a9565b6033546001600160a01b0316331462000cbb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620009a9565b606580546001600160a01b031916905562000a4d8162002258565b604080516060810182525f808252602082018190529181019190915262001f816562726964676560d01b5f62001259565b6001600160a01b0316336001600160a01b03161462001fb357604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001ff0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200201691906200370d565b90505f620020398260400151620007df6b195c98cdcc8c57dd985d5b1d60a21b90565b9050806001600160a01b031682602001516001600160a01b0316146200207257604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff166200209f5760405162461bcd60e51b8152600401620009a99062003799565b620020aa82620022a9565b6001600160a01b038116620020d2576040516375cabfef60e11b815260040160405180910390fd5b62000c1e81620022dd565b6001600160a01b0381163b6200214c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620009a9565b5f8051602062003e9c83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b620021868362002351565b5f82511180620021935750805b156200138357620021a5838362002392565b50505050565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b039081168552925290912054168062000959576200126a82620023ba565b6001600160a01b0383166200221857604051634c67134d60e11b815260040160405180910390fd5b5f620022368483856040805180602001604052805f815250620025a5565b50905080620021a557604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620022cb6001600160a01b03821615620022c4578162001f35565b3362001f35565b5060c9805461ff001916610100179055565b5f54610100900460ff16620023065760405162461bcd60e51b8152600401620009a99062003799565b6001600160401b034611156200232f5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6200235c81620020dd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062001267838360405180606001604052806027815260200162003ebc602791396200262f565b5f80620023cf6033546001600160a01b031690565b60975460208501518551604080880151606089015191516200240296956001600160a01b031694939290602401620037e4565b60408051601f198184030181529190526020810180516001600160e01b03166377c6257360e11b17905290506200244b6d627269646765645f65726337323160901b5f62001259565b816040516200245a906200275d565b6200246792919062003849565b604051809103905ff08015801562002481573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620024e79082620038bd565b5060608201516002820190620024fe9082620038bd565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b9262002597929062003989565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b03811115620025ca57620025ca62002794565b6040519080825280601f01601f191660200182016040528015620025f5576020820181803683370190505b5090505f808751602089018b8e8ef191503d92508683111562002616578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b0316856040516200264d9190620039ba565b5f60405180830381855af49150503d805f811462002687576040519150601f19603f3d011682016040523d82523d5f602084013e6200268c565b606091505b50915091506200269f86838387620026a9565b9695505050505050565b606083156200271c5782515f0362002714576001600160a01b0385163b620027145760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620009a9565b508162002728565b62002728838362002730565b949350505050565b815115620027415781518083602001fd5b8060405162461bcd60e51b8152600401620009a99190620036e1565b6104c480620039d883390190565b5f602082840312156200277c575f80fd5b81356001600160e01b03198116811462001267575f80fd5b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715620027ce57620027ce62002794565b60405290565b6040516101a081016001600160401b0381118282101715620027ce57620027ce62002794565b604051608081016001600160401b0381118282101715620027ce57620027ce62002794565b604051601f8201601f191681016001600160401b03811182821017156200284a576200284a62002794565b604052919050565b6001600160401b038116811462000a4d575f80fd5b8035620009598162002852565b6001600160a01b038116811462000a4d575f80fd5b8035620009598162002874565b5f6001600160401b03821115620028b157620028b162002794565b5060051b60200190565b5f82601f830112620028cb575f80fd5b81356020620028e4620028de8362002896565b6200281f565b8083825260208201915060208460051b87010193508684111562002906575f80fd5b602086015b848110156200292457803583529183019183016200290b565b509695505050505050565b5f6001600160401b038211156200294a576200294a62002794565b50601f01601f191660200190565b5f82601f83011262002968575f80fd5b813562002979620028de826200292f565b8181528460208386010111156200298e575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215620029bb575f80fd5b81356001600160401b0380821115620029d2575f80fd5b908301906101408286031215620029e7575f80fd5b620029f1620027a8565b620029fc8362002867565b815262002a0c6020840162002889565b602082015262002a1f6040840162002889565b604082015262002a326060840162002889565b606082015260808301358281111562002a49575f80fd5b62002a5787828601620028bb565b60808301525060a08301358281111562002a6f575f80fd5b62002a7d87828601620028bb565b60a08301525060c083013560c082015260e083013560e082015261010062002aa781850162002889565b90820152610120838101358381111562002abf575f80fd5b62002acd8882870162002958565b918301919091525095945050505050565b5f5b8381101562002afa57818101518382015260200162002ae0565b50505f910152565b5f815180845262002b1b81602086016020860162002ade565b601f01601f19169290920160200192915050565b6020815262002b4a6020820183516001600160801b03169052565b5f602083015162002b6660408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010062002bed818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a06101808086018290529192509062002c376101c086018462002b02565b90860151858203601f1901838701529092506200269f838262002b02565b5f8083601f84011262002c66575f80fd5b5081356001600160401b0381111562002c7d575f80fd5b60208301915083602082850101111562002c95575f80fd5b9250929050565b5f805f805f6080868803121562002cb1575f80fd5b853562002cbe8162002874565b9450602086013562002cd08162002874565b93506040860135925060608601356001600160401b0381111562002cf2575f80fd5b62002d008882890162002c55565b969995985093965092949392505050565b5f6020828403121562002d22575f80fd5b8135620012678162002874565b5f806040838503121562002d41575f80fd5b82356001600160401b0381111562002d57575f80fd5b83016101a0818603121562002d6a575f80fd5b946020939093013593505050565b801515811462000a4d575f80fd5b5f805f6060848603121562002d99575f80fd5b833562002da68162002852565b925060208401359150604084013562002dbf8162002d78565b809150509250925092565b5f806040838503121562002ddc575f80fd5b823562002de98162002874565b915060208301356001600160401b0381111562002e04575f80fd5b62002e128582860162002958565b9150509250929050565b5f806040838503121562002e2e575f80fd5b82359150602083013562002e428162002874565b809150509250929050565b5f806020838503121562002e5f575f80fd5b82356001600160401b0381111562002e75575f80fd5b62002e838582860162002c55565b90969095509350505050565b6001600160401b03851681526001600160a01b03841660208201526080604082018190525f9062002ec39083018562002b02565b828103606084015262002ed7818562002b02565b979650505050505050565b5f806040838503121562002ef4575f80fd5b82359150602083013562002e428162002d78565b5f806040838503121562002f1a575f80fd5b823562002f278162002874565b9150602083013562002e428162002874565b634e487b7160e01b5f52603260045260245ffd5b818103818111156200126a57634e487b7160e01b5f52601160045260245ffd5b80516001600160801b038116811462000959575f80fd5b8051620009598162002874565b8051620009598162002852565b5f82601f83011262002fae575f80fd5b815162002fbf620028de826200292f565b81815284602083860101111562002fd4575f80fd5b6200272882602083016020870162002ade565b5f806040838503121562002ff9575f80fd5b8251915060208301516001600160401b038082111562003017575f80fd5b908401906101a082870312156200302c575f80fd5b62003036620027d4565b620030418362002f6d565b8152620030516020840162002f84565b6020820152620030646040840162002f91565b6040820152620030776060840162002f91565b60608201526200308a6080840162002f84565b60808201526200309d60a0840162002f84565b60a0820152620030b060c0840162002f84565b60c0820152620030c360e0840162002f84565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015183811115620030fd575f80fd5b6200310b8982870162002f9e565b828401525050610180808401518381111562003125575f80fd5b620031338982870162002f9e565b8284015250508093505050509250929050565b5f815180845260208085019450602084015f5b83811015620031775781518752958201959082019060010162003159565b509495945050505050565b6001600160401b03861681526001600160a01b0385811660208301528416604082015260a0606082018190525f90620031be9083018562003146565b8281036080840152620031d2818562003146565b98975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f808335601e198436030181126200328c575f80fd5b8301803591506001600160401b03821115620032a6575f80fd5b60200191503681900382131562002c95575f80fd5b5f8085851115620032ca575f80fd5b83861115620032d7575f80fd5b5050820193919092039150565b5f60208284031215620032f5575f80fd5b81356001600160401b038111156200330b575f80fd5b620027288482850162002958565b5f82601f83011262003329575f80fd5b815160206200333c620028de8362002896565b8083825260208201915060208460051b8701019350868411156200335e575f80fd5b602086015b8481101562002924578051835291830191830162003363565b5f805f806080858703121562003390575f80fd5b84516001600160401b0380821115620033a7575f80fd5b9086019060808289031215620033bb575f80fd5b620033c5620027fa565b8251620033d28162002852565b81526020830151620033e48162002874565b6020820152604083015182811115620033fb575f80fd5b620034098a82860162002f9e565b60408301525060608301518281111562003421575f80fd5b6200342f8a82860162002f9e565b6060830152509550620034456020880162002f84565b9450620034556040880162002f84565b935060608701519150808211156200346b575f80fd5b506200347a8782880162003319565b91505092959194509250565b6001600160a01b038581168252841660208201526080604082018190525f90620034b39083018562003146565b828103606084015262002ed7818562003146565b5f805f8060808587031215620034db575f80fd5b84356001600160401b0380821115620034f2575f80fd5b908601906080828903121562003506575f80fd5b62003510620027fa565b82356200351d8162002852565b815260208301356200352f8162002874565b602082015260408301358281111562003546575f80fd5b620035548a82860162002958565b6040830152506060830135828111156200356c575f80fd5b6200357a8a82860162002958565b6060830152509550620035906020880162002889565b9450620035a06040880162002889565b93506060870135915080821115620035b6575f80fd5b506200347a87828801620028bb565b600181811c90821680620035da57607f821691505b602082108103620035f957634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121562003610575f80fd5b8151620012678162002d78565b5f602082840312156200362e575f80fd5b81516001600160401b0381111562003644575f80fd5b620027288482850162002f9e565b608080825285516001600160401b03168282015260208601516001600160a01b0390811660a0840152604087015160c08401929092525f91906200369b61010085018362002b02565b91506060880151607f198584030160e0860152620036ba838262002b02565b88831660208701529187166040860152508381036060850152905062002ed7818562003146565b602081525f62001267602083018462002b02565b5f6020828403121562003706575f80fd5b5051919050565b5f606082840312156200371e575f80fd5b604051606081018181106001600160401b038211171562003743576200374362002794565b6040528251815260208301516200375a8162002874565b602082015260408301516200376f8162002852565b60408201529392505050565b5f602082840312156200378c575f80fd5b8151620012678162002874565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b0387811682528681166020830152851660408201526001600160401b038416606082015260c0608082018190525f90620038289083018562002b02565b82810360a08401526200383c818562002b02565b9998505050505050505050565b6001600160a01b03831681526040602082018190525f9062000c309083018462002b02565b601f8211156200138357805f5260205f20601f840160051c81016020851015620038955750805b601f840160051c820191505b81811015620038b6575f8155600101620038a1565b5050505050565b81516001600160401b03811115620038d957620038d962002794565b620038f181620038ea8454620035c5565b846200386e565b602080601f83116001811462003927575f84156200390f5750858301515b5f19600386901b1c1916600185901b17855562003981565b5f85815260208120601f198616915b82811015620039575788860151825594840194600190910190840162003936565b50858210156200397557878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f6200399d604083018562002b02565b8281036020840152620039b1818562002b02565b95945050505050565b5f8251620039cd81846020870162002ade565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220838a65434637367b0dce4f01d48f09f1bff466edff41473526507bfd76721ee164736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000003" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x608060405260043610620001b7575f3560e01c8063634da63a11620000fa5780639aa8605c1162000092578063e30c3978116200006a578063e30c397814620004fd578063f09a4016146200051c578063f23a6e611462000540578063f2fde38b1462000570575f80fd5b80639aa8605c1462000471578063a86f9d9e14620004a7578063bc197c8114620004cb575f80fd5b806379ba509711620000d257806379ba5097146200040d5780637f07c94714620004245780638456cb59146200043b5780638da5cb5b1462000452575f80fd5b8063634da63a146200039c57806367090ccf14620003b2578063715018a614620003f6575f80fd5b80633c6f5de2116200016e5780634f1ef28611620001465780634f1ef286146200033057806352d1902d146200034757806359f4a907146200035e5780635c975abb146200037a575f80fd5b80633c6f5de214620002de5780633eb6b8cf14620002f55780633f4ba83a1462000319575f80fd5b806301ffc9a714620001bb57806306fdde0314620001f45780631507cc4714620002225780632ca069a514620002485780633659cfe6146200027e5780633ab76e9f14620002a4575b5f80fd5b348015620001c7575f80fd5b50620001df620001d936600462002745565b62000594565b60405190151581526020015b60405180910390f35b34801562000200575f80fd5b506c195c98cc4c4d4d57dd985d5b1d609a1b5b604051908152602001620001eb565b620002396200023336600462002984565b620005cb565b604051620001eb919062002b09565b34801562000254575f80fd5b5062000264636cdb3d1360e11b81565b6040516001600160e01b03199091168152602001620001eb565b3480156200028a575f80fd5b50620002a26200029c36600462002c2f565b620009d6565b005b348015620002b0575f80fd5b50609754620002c5906001600160a01b031681565b6040516001600160a01b039091168152602001620001eb565b620002a2620002ef36600462002c4d565b62000ac8565b34801562000301575f80fd5b50620002c56200031336600462002ca4565b62000c59565b34801562000325575f80fd5b50620002a262000c71565b620002a26200034136600462002ce8565b62000cf4565b34801562000353575f80fd5b506200021362000dcb565b3480156200036a575f80fd5b50620002646380ac58cd60e01b81565b34801562000386575f80fd5b50620001df60c954610100900460ff1660021490565b348015620003a8575f80fd5b5062000213600a81565b348015620003be575f80fd5b50620002c5620003d036600462002d3a565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000402575f80fd5b50620002a262000e80565b34801562000419575f80fd5b50620002a262000e95565b620002a26200043536600462002db2565b62000f10565b34801562000447575f80fd5b50620002a262001080565b3480156200045e575f80fd5b506033546001600160a01b0316620002c5565b3480156200047d575f80fd5b50620004956200048f36600462002c2f565b620010f4565b604051620001eb949392919062002df4565b348015620004b3575f80fd5b50620002c5620004c536600462002e47565b6200124f565b348015620004d7575f80fd5b5062000264620004e936600462002eb0565b63bc197c8160e01b98975050505050505050565b34801562000509575f80fd5b506065546001600160a01b0316620002c5565b34801562000528575f80fd5b50620002a26200053a36600462002f74565b6200125d565b3480156200054c575f80fd5b50620002646200055e36600462002fa5565b63f23a6e6160e01b9695505050505050565b3480156200057c575f80fd5b50620002a26200058e36600462002c2f565b62001375565b5f6001600160e01b031982166301ffc9a760e01b1480620005c55750631e37aef160e11b6001600160e01b03198316145b92915050565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101829052610180810191909152600262000641620013e9565b60ff1603620006635760405163dfc60d8560e01b815260040160405180910390fd5b6200066f600262001423565b6200068460c954610100900460ff1660021490565b15620006a35760405163bae6e2a960e01b815260040160405180910390fd5b818060a001515181608001515114620006cf5760405163196e8a4160e31b815260040160405180910390fd5b600a8160800151511115620006f75760405163e4a4c1c760e01b815260040160405180910390fd5b60608101516001600160a01b031662000723576040516303f8a7d360e01b815260040160405180910390fd5b5f5b8360a00151518110156200077d578360a0015181815181106200074c576200074c62003023565b60200260200101515f036200077457604051634299323b60e11b815260040160405180910390fd5b60010162000725565b5060608301516200079f906001600160a01b0316636cdb3d1360e11b62001466565b620007bd57604051633ee915f560e11b815260040160405180910390fd5b5f80620007cb3386620014f9565b604080516101a0810182525f808252602080830182905292820181905289516001600160401b03166060830152336080830152918901519395509193509160a08201906001600160a01b031662000823573362000829565b87602001515b6001600160a01b031681526020016200085e885f0151620008576c195c98cc4c4d4d57dd985d5b1d609a1b90565b5f62000c59565b6001600160a01b031681526020018761010001516001600160a01b031681526020018760e001513462000892919062003037565b81526020018760e0015181526020018760c00151815260200184815260200187610120015181525090505f620008d26562726964676560d01b5f6200124f565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b815260040162000900919062002b09565b5f6040518083038185885af11580156200091c573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620009469190810190620030d1565b809750819250505086604001516001600160a01b031686608001516001600160a01b0316827fabbf62a1459339f9ac59136d313a5ccd83d2706cc6d4c04d90642520169144dc896060015187602001518c606001518d608001518e60a00151604051620009b89594939291906200326c565b60405180910390a45050505050620009d1600162001423565b919050565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000416300362000a2a5760405162461bcd60e51b815260040162000a2190620032c8565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000000046001600160a01b031662000a745f805160206200408f833981519152546001600160a01b031690565b6001600160a01b03161462000a9d5760405162461bcd60e51b815260040162000a219062003314565b62000aa88162001a4b565b604080515f8082526020820190925262000ac59183919062001a55565b50565b600262000ad4620013e9565b60ff160362000af65760405163dfc60d8560e01b815260040160405180910390fd5b62000b02600262001423565b62000b1760c954610100900460ff1660021490565b1562000b365760405163bae6e2a960e01b815260040160405180910390fd5b62000b4062001bcc565b505f62000b5261016084018462003360565b62000b62916004908290620033a5565b81019062000b719190620033ce565b90505f805f8380602001905181019062000b8c919062003466565b94509450505092505f62000bb78488608001602081019062000baf919062002c2f565b858562001cc3565b905062000be561010088013562000bd560a08a0160808b0162002c2f565b6001600160a01b03169062001dbf565b62000bf760a088016080890162002c2f565b6001600160a01b0316867fe48bef18455e47bca14864ab6e82dffa29df148b051c09de95aec44ecf13598c866020015184878760405162000c3c949392919062003596565b60405180910390a3505050505062000c55600162001423565b5050565b5f62000c6784848462001dcc565b90505b9392505050565b62000c8660c954610100900460ff1660021490565b62000ca45760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000cf23362001a4b565b565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000416300362000d3f5760405162461bcd60e51b815260040162000a2190620032c8565b7f00000000000000000000000001670010000000000000000000000000000000046001600160a01b031662000d895f805160206200408f833981519152546001600160a01b031690565b6001600160a01b03161462000db25760405162461bcd60e51b815260040162000a219062003314565b62000dbd8262001a4b565b62000c558282600162001a55565b5f306001600160a01b037f0000000000000000000000000167001000000000000000000000000000000004161462000e6c5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000a21565b505f805160206200408f8339815191525b90565b62000e8a62001ebf565b62000cf25f62001f1b565b60655433906001600160a01b0316811462000f055760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840162000a21565b62000ac58162001f1b565b600262000f1c620013e9565b60ff160362000f3e5760405163dfc60d8560e01b815260040160405180910390fd5b62000f4a600262001423565b62000f5f60c954610100900460ff1660021490565b1562000f7e5760405163bae6e2a960e01b815260040160405180910390fd5b5f8080808062000f9186880188620035d7565b945094509450945094505f62000fa662001f36565b90506001600160a01b038416158062000fc757506001600160a01b03841630145b1562000fe65760405163def9481360e01b815260040160405180910390fd5b5f62000ff58786868662001cc3565b90506200100c6001600160a01b0386163462001dbf565b846001600160a01b0316866001600160a01b0316835f01517f895f73e418d1bbbad2a311d085fad00e5d98a960e9f2afa4b942071d39bec43a85604001518b60200151868a8a604051620010659594939291906200326c565b60405180910390a45050505050505062000c55600162001423565b6200109560c954610100900460ff1660021490565b15620010b45760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000cdf565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b03169291906200113490620036fa565b80601f01602080910402602001604051908101604052809291908181526020018280546200116290620036fa565b8015620011b15780601f106200118757610100808354040283529160200191620011b1565b820191905f5260205f20905b8154815290600101906020018083116200119357829003601f168201915b505050505090806002018054620011c890620036fa565b80601f0160208091040260200160405190810160405280929190818152602001828054620011f690620036fa565b8015620012455780601f106200121b5761010080835404028352916020019162001245565b820191905f5260205f20905b8154815290600101906020018083116200122757829003601f168201915b5050505050905084565b5f62000c6a46848462001dcc565b5f54610100900460ff16158080156200127c57505f54600160ff909116105b80620012975750303b1580156200129757505f5460ff166001145b620012fc5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000a21565b5f805460ff1916600117905580156200131e575f805461ff0019166101001790555b6200132a83836200205d565b801562001370575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6200137f62001ebf565b606580546001600160a01b0383166001600160a01b03199091168117909155620013b16033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f466001036200141957507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b466001036200145257807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f6001600160a01b0383163b6200147f57505f620005c5565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015620014ec575060408051601f3d908101601f19168201909252620014e99181019062003734565b60015b15620005c5579392505050565b604080516080810182525f8082526020820152606091810182905280820182905260608301516001600160a01b039081165f90815261012d6020526040902054600160401b90041615620017a55760608301516001600160a01b039081165f90815261012d6020908152604091829020825160808101845281546001600160401b0381168252600160401b9004909416918401919091526001810180549192840191620015a690620036fa565b80601f0160208091040260200160405190810160405280929190818152602001828054620015d490620036fa565b8015620016235780601f10620015f95761010080835404028352916020019162001623565b820191905f5260205f20905b8154815290600101906020018083116200160557829003601f168201915b505050505081526020016002820180546200163e90620036fa565b80601f01602080910402602001604051908101604052809291908181526020018280546200166c90620036fa565b8015620016bb5780601f106200169157610100808354040283529160200191620016bb565b820191905f5260205f20905b8154815290600101906020018083116200169d57829003601f168201915b50505050508152505090505f5b8360800151518110156200179e5783606001516001600160a01b031663f5298aca868660800151848151811062001703576200170362003023565b60200260200101518760a00151858151811062001724576200172462003023565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064015f604051808303815f87803b1580156200177b575f80fd5b505af11580156200178e573d5f803e3d5ffd5b50505050806001019050620016c8565b50620019c9565b6040518060800160405280466001600160401b0316815260200184606001516001600160a01b0316815260200160405180602001604052805f815250815260200160405180602001604052805f81525081525090505f83606001519050806001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa9250505080156200186257506040513d5f823e601f3d908101601f191682016040526200185f919081019062003752565b60015b156200186e5760608301525b806001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015620018ce57506040513d5f823e601f3d908101601f19168201604052620018cb919081019062003752565b60015b15620018da5760408301525b5f5b846080015151811015620019c65784606001516001600160a01b031663f242432a33308860800151858151811062001918576200191862003023565b60200260200101518960a00151868151811062001939576200193962003023565b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a060848201525f60a482015260c4015f604051808303815f87803b158015620019a3575f80fd5b505af1158015620019b6573d5f803e3d5ffd5b50505050806001019050620018dc565b50505b604080840151608085015160a086015192513093637f07c94793620019f69387938b939060200162003787565b60408051601f198184030181529082905262001a15916024016200383e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505091509250929050565b62000ac562001ebf565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001a8b576200137083620020c4565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001ae8575060408051601f3d908101601f1916820190925262001ae59181019062003852565b60015b62001b4d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000a21565b5f805160206200408f833981519152811462001bbe5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000a21565b506200137083838362002162565b604080516060810182525f808252602082018190529181019190915262001bfd6562726964676560d01b5f6200124f565b6001600160a01b0316336001600160a01b03161462001c2f57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001c6c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001c9291906200386a565b60208101519091506001600160a01b0316331462000e7d57604051632583296b60e01b815260040160405180910390fd5b5f46855f01516001600160401b03160362001d4757506020840151604051631759616b60e11b81526001600160a01b03821690632eb2c2d69062001d12903090889088908890600401620038d8565b5f604051808303815f87803b15801562001d2a575f80fd5b505af115801562001d3d573d5f803e3d5ffd5b5050505062001db7565b62001d528562002192565b60405163d81d0a1560e01b81529091506001600160a01b0382169063d81d0a159062001d879087908790879060040162003935565b5f604051808303815f87803b15801562001d9f575f80fd5b505af115801562001db2573d5f803e3d5ffd5b505050505b949350505050565b62000c5582825a620021d7565b6097545f906001600160a01b031662001df857604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001e4f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001e7591906200396e565b90508115801562001e8d57506001600160a01b038116155b1562000c6a57604051632b0d65db60e01b81526001600160401b03851660048201526024810184905260440162000a21565b6033546001600160a01b0316331462000cf25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000a21565b606580546001600160a01b031916905562000ac5816200223f565b604080516060810182525f808252602082018190529181019190915262001f676562726964676560d01b5f6200124f565b6001600160a01b0316336001600160a01b03161462001f9957604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001fd6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001ffc91906200386a565b90505f620020208260400151620008576c195c98cc4c4d4d57dd985d5b1d609a1b90565b9050806001600160a01b031682602001516001600160a01b0316146200205957604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff16620020865760405162461bcd60e51b815260040162000a21906200398c565b620020918262002290565b6001600160a01b038116620020b9576040516375cabfef60e11b815260040160405180910390fd5b62000c5581620022c4565b6001600160a01b0381163b620021335760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000a21565b5f805160206200408f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6200216d8362002338565b5f825111806200217a5750805b1562001370576200218c838362002379565b50505050565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b0390811685529252909120541680620009d157620005c582620023a1565b6001600160a01b038316620021ff57604051634c67134d60e11b815260040160405180910390fd5b5f6200221d8483856040805180602001604052805f8152506200258d565b509050806200218c57604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620022b26001600160a01b03821615620022ab578162001f1b565b3362001f1b565b5060c9805461ff001916610100179055565b5f54610100900460ff16620022ed5760405162461bcd60e51b815260040162000a21906200398c565b6001600160401b03461115620023165760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6200234381620020c4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000c6a8383604051806060016040528060278152602001620040af6027913962002617565b5f80620023b66033546001600160a01b031690565b6097546020850151855160408088015160608901519151620023e996956001600160a01b031694939290602401620039d7565b60408051601f198184030181529190526020810180516001600160e01b03166377c6257360e11b1790529050620024336e627269646765645f6572633131353560881b5f6200124f565b81604051620024429062002737565b6200244f92919062003a3c565b604051809103905ff08015801562002469573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620024cf908262003ab0565b5060608201516002820190620024e6908262003ab0565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b926200257f929062003b7c565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b03811115620025b257620025b26200276e565b6040519080825280601f01601f191660200182016040528015620025dd576020820181803683370190505b5090505f808751602089018b8e8ef191503d925086831115620025fe578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b03168560405162002635919062003bad565b5f60405180830381855af49150503d805f81146200266f576040519150601f19603f3d011682016040523d82523d5f602084013e62002674565b606091505b5091509150620026878683838762002691565b9695505050505050565b60608315620027045782515f03620026fc576001600160a01b0385163b620026fc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000a21565b508162001db7565b62001db783838151156200271b5781518083602001fd5b8060405162461bcd60e51b815260040162000a2191906200383e565b6104c48062003bcb83390190565b5f6020828403121562002756575f80fd5b81356001600160e01b03198116811462000c6a575f80fd5b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715620027a857620027a86200276e565b60405290565b6040516101a081016001600160401b0381118282101715620027a857620027a86200276e565b604051608081016001600160401b0381118282101715620027a857620027a86200276e565b604051601f8201601f191681016001600160401b03811182821017156200282457620028246200276e565b604052919050565b6001600160401b038116811462000ac5575f80fd5b8035620009d1816200282c565b6001600160a01b038116811462000ac5575f80fd5b8035620009d1816200284e565b5f6001600160401b038211156200288b576200288b6200276e565b5060051b60200190565b5f82601f830112620028a5575f80fd5b81356020620028be620028b88362002870565b620027f9565b8083825260208201915060208460051b870101935086841115620028e0575f80fd5b602086015b84811015620028fe5780358352918301918301620028e5565b509695505050505050565b5f6001600160401b038211156200292457620029246200276e565b50601f01601f191660200190565b5f82601f83011262002942575f80fd5b813562002953620028b88262002909565b81815284602083860101111562002968575f80fd5b816020850160208301375f918101602001919091529392505050565b5f6020828403121562002995575f80fd5b81356001600160401b0380821115620029ac575f80fd5b908301906101408286031215620029c1575f80fd5b620029cb62002782565b620029d68362002841565b8152620029e66020840162002863565b6020820152620029f96040840162002863565b604082015262002a0c6060840162002863565b606082015260808301358281111562002a23575f80fd5b62002a318782860162002895565b60808301525060a08301358281111562002a49575f80fd5b62002a578782860162002895565b60a08301525060c083013560c082015260e083013560e082015261010062002a8181850162002863565b90820152610120838101358381111562002a99575f80fd5b62002aa78882870162002932565b918301919091525095945050505050565b5f5b8381101562002ad457818101518382015260200162002aba565b50505f910152565b5f815180845262002af581602086016020860162002ab8565b601f01601f19169290920160200192915050565b6020815262002b246020820183516001600160801b03169052565b5f602083015162002b4060408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010062002bc7818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a06101808086018290529192509062002c116101c086018462002adc565b90860151858203601f19018387015290925062002687838262002adc565b5f6020828403121562002c40575f80fd5b813562000c6a816200284e565b5f806040838503121562002c5f575f80fd5b82356001600160401b0381111562002c75575f80fd5b83016101a0818603121562002c88575f80fd5b946020939093013593505050565b801515811462000ac5575f80fd5b5f805f6060848603121562002cb7575f80fd5b833562002cc4816200282c565b925060208401359150604084013562002cdd8162002c96565b809150509250925092565b5f806040838503121562002cfa575f80fd5b823562002d07816200284e565b915060208301356001600160401b0381111562002d22575f80fd5b62002d308582860162002932565b9150509250929050565b5f806040838503121562002d4c575f80fd5b82359150602083013562002d60816200284e565b809150509250929050565b5f8083601f84011262002d7c575f80fd5b5081356001600160401b0381111562002d93575f80fd5b60208301915083602082850101111562002dab575f80fd5b9250929050565b5f806020838503121562002dc4575f80fd5b82356001600160401b0381111562002dda575f80fd5b62002de88582860162002d6b565b90969095509350505050565b6001600160401b03851681526001600160a01b03841660208201526080604082018190525f9062002e289083018562002adc565b828103606084015262002e3c818562002adc565b979650505050505050565b5f806040838503121562002e59575f80fd5b82359150602083013562002d608162002c96565b5f8083601f84011262002e7e575f80fd5b5081356001600160401b0381111562002e95575f80fd5b6020830191508360208260051b850101111562002dab575f80fd5b5f805f805f805f8060a0898b03121562002ec8575f80fd5b883562002ed5816200284e565b9750602089013562002ee7816200284e565b965060408901356001600160401b038082111562002f03575f80fd5b62002f118c838d0162002e6d565b909850965060608b013591508082111562002f2a575f80fd5b62002f388c838d0162002e6d565b909650945060808b013591508082111562002f51575f80fd5b5062002f608b828c0162002d6b565b999c989b5096995094979396929594505050565b5f806040838503121562002f86575f80fd5b823562002f93816200284e565b9150602083013562002d60816200284e565b5f805f805f8060a0878903121562002fbb575f80fd5b863562002fc8816200284e565b9550602087013562002fda816200284e565b9450604087013593506060870135925060808701356001600160401b0381111562003003575f80fd5b6200301189828a0162002d6b565b979a9699509497509295939492505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115620005c557634e487b7160e01b5f52601160045260245ffd5b80516001600160801b0381168114620009d1575f80fd5b8051620009d1816200284e565b8051620009d1816200282c565b5f82601f83011262003098575f80fd5b8151620030a9620028b88262002909565b818152846020838601011115620030be575f80fd5b62001db782602083016020870162002ab8565b5f8060408385031215620030e3575f80fd5b8251915060208301516001600160401b038082111562003101575f80fd5b908401906101a0828703121562003116575f80fd5b62003120620027ae565b6200312b8362003057565b81526200313b602084016200306e565b60208201526200314e604084016200307b565b604082015262003161606084016200307b565b606082015262003174608084016200306e565b60808201526200318760a084016200306e565b60a08201526200319a60c084016200306e565b60c0820152620031ad60e084016200306e565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015183811115620031e7575f80fd5b620031f58982870162003088565b82840152505061018080840151838111156200320f575f80fd5b6200321d8982870162003088565b8284015250508093505050509250929050565b5f815180845260208085019450602084015f5b83811015620032615781518752958201959082019060010162003243565b509495945050505050565b6001600160401b03861681526001600160a01b0385811660208301528416604082015260a0606082018190525f90620032a89083018562003230565b8281036080840152620032bc818562003230565b98975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f808335601e1984360301811262003376575f80fd5b8301803591506001600160401b0382111562003390575f80fd5b60200191503681900382131562002dab575f80fd5b5f8085851115620033b4575f80fd5b83861115620033c1575f80fd5b5050820193919092039150565b5f60208284031215620033df575f80fd5b81356001600160401b03811115620033f5575f80fd5b62001db78482850162002932565b5f82601f83011262003413575f80fd5b8151602062003426620028b88362002870565b8083825260208201915060208460051b87010193508684111562003448575f80fd5b602086015b84811015620028fe57805183529183019183016200344d565b5f805f805f60a086880312156200347b575f80fd5b85516001600160401b038082111562003492575f80fd5b908701906080828a031215620034a6575f80fd5b620034b0620027d4565b8251620034bd816200282c565b81526020830151620034cf816200284e565b6020820152604083015182811115620034e6575f80fd5b620034f48b82860162003088565b6040830152506060830151828111156200350c575f80fd5b6200351a8b82860162003088565b606083015250965062003530602089016200306e565b955062003540604089016200306e565b9450606088015191508082111562003556575f80fd5b6200356489838a0162003403565b935060808801519150808211156200357a575f80fd5b50620035898882890162003403565b9150509295509295909350565b6001600160a01b038581168252841660208201526080604082018190525f90620035c39083018562003230565b828103606084015262002e3c818562003230565b5f805f805f60a08688031215620035ec575f80fd5b85356001600160401b038082111562003603575f80fd5b908701906080828a03121562003617575f80fd5b62003621620027d4565b82356200362e816200282c565b8152602083013562003640816200284e565b602082015260408301358281111562003657575f80fd5b620036658b82860162002932565b6040830152506060830135828111156200367d575f80fd5b6200368b8b82860162002932565b6060830152509650620036a16020890162002863565b9550620036b16040890162002863565b94506060880135915080821115620036c7575f80fd5b620036d589838a0162002895565b93506080880135915080821115620036eb575f80fd5b50620035898882890162002895565b600181811c908216806200370f57607f821691505b6020821081036200372e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121562003745575f80fd5b815162000c6a8162002c96565b5f6020828403121562003763575f80fd5b81516001600160401b0381111562003779575f80fd5b62001db78482850162003088565b60a080825286516001600160401b03169082015260208601516001600160a01b031660c08201526040860151608060e08301525f90620037cc61012084018262002adc565b90506060880151609f1984830301610100850152620037ec828262002adc565b9150506200380560208401886001600160a01b03169052565b6001600160a01b0386166040840152828103606084015262003828818662003230565b90508281036080840152620032bc818562003230565b602081525f62000c6a602083018462002adc565b5f6020828403121562003863575f80fd5b5051919050565b5f606082840312156200387b575f80fd5b604051606081018181106001600160401b0382111715620038a057620038a06200276e565b604052825181526020830151620038b7816200284e565b60208201526040830151620038cc816200282c565b60408201529392505050565b6001600160a01b0385811682528416602082015260a0604082018190525f90620039059083018562003230565b828103606084015262003919818562003230565b83810360809094019390935250505f8152602001949350505050565b6001600160a01b03841681526060602082018190525f906200395a9083018562003230565b828103604084015262002687818562003230565b5f602082840312156200397f575f80fd5b815162000c6a816200284e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b0387811682528681166020830152851660408201526001600160401b038416606082015260c0608082018190525f9062003a1b9083018562002adc565b82810360a084015262003a2f818562002adc565b9998505050505050505050565b6001600160a01b03831681526040602082018190525f9062000c679083018462002adc565b601f8211156200137057805f5260205f20601f840160051c8101602085101562003a885750805b601f840160051c820191505b8181101562003aa9575f815560010162003a94565b5050505050565b81516001600160401b0381111562003acc5762003acc6200276e565b62003ae48162003add8454620036fa565b8462003a61565b602080601f83116001811462003b1a575f841562003b025750858301515b5f19600386901b1c1916600185901b17855562003b74565b5f85815260208120601f198616915b8281101562003b4a5788860151825594840194600190910190840162003b29565b508582101562003b6857878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f62003b90604083018562002adc565b828103602084015262003ba4818562002adc565b95945050505050565b5f825162003bc081846020870162002ab8565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ba16509e7570dfe3f082a305760ac815a19b24a35621effccf96b2da504ccb7a64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000004" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010096": { + "storage": {}, + "code": "0x6080604052600436106102bf575f3560e01c806370a082311161016f5780639ab24eb0116100d8578063bb86ef9311610092578063dd62ed3e1161006d578063dd62ed3e1461088c578063e30c3978146108ab578063f1127ed8146108c8578063f2fde38b14610911575f80fd5b8063bb86ef931461082f578063c3cda5201461084e578063d505accf1461086d575f80fd5b80639ab24eb0146107755780639dc29fac14610794578063a457c2d7146107b3578063a86f9d9e146107d2578063a9059cbb146107f1578063b8f2e0c514610810575f80fd5b80638456cb59116101295780638456cb59146106e75780638da5cb5b146106fb5780638e539e8c1461070f57806395d89b411461072e5780639711715a14610742578063981b24d014610756575f80fd5b806370a082311461062c578063715018a61461066157806379ba5097146106755780637cf8ed0d146106895780637e474634146106a95780637ecebe00146106c8575f80fd5b80633a46b1a81161022b5780634ee2cd7e116101e5578063587cde1e116101c0578063587cde1e146105815780635c19a95c146105b95780635c975abb146105d85780636fcfff45146105f8575f80fd5b80634ee2cd7e1461053b5780634f1ef2861461055a57806352d1902d1461056d575f80fd5b80633a46b1a8146104955780633ab76e9f146104b45780633eb6b8cf146104d35780633f4ba83a146104f257806340c10f191461050657806349d1260514610525575f80fd5b80632e74eb2d1161027c5780632e74eb2d146103be578063313ce567146103df5780633644e5151461040b5780633659cfe61461041f57806337fbe1121461043e5780633950935114610476575f80fd5b806306fdde03146102c3578063095ea7b3146102ed5780630ae745481461031c57806318160ddd1461033c57806323b872dd1461035b57806326afaadd1461037a575b5f80fd5b3480156102ce575f80fd5b506102d7610930565b6040516102e49190613924565b60405180910390f35b3480156102f8575f80fd5b5061030c61030736600461396a565b61094b565b60405190151581526020016102e4565b348015610327575f80fd5b5060fb5461030c90600160a01b900460ff1681565b348015610347575f80fd5b5061012f545b6040519081526020016102e4565b348015610366575f80fd5b5061030c610375366004613994565b610964565b348015610385575f80fd5b5061039f61022a5461022b546001600160a01b0390911691565b604080516001600160a01b0390931683526020830191909152016102e4565b3480156103c9575f80fd5b506103dd6103d83660046139d2565b610989565b005b3480156103ea575f80fd5b5061022a54600160a01b900460ff1660405160ff90911681526020016102e4565b348015610416575f80fd5b5061034d6109b4565b34801561042a575f80fd5b506103dd6104393660046139d2565b6109bd565b348015610449575f80fd5b5061022c5461045e906001600160a01b031681565b6040516001600160a01b0390911681526020016102e4565b348015610481575f80fd5b5061030c61049036600461396a565b610aa3565b3480156104a0575f80fd5b5061034d6104af36600461396a565b610ac4565b3480156104bf575f80fd5b5060975461045e906001600160a01b031681565b3480156104de575f80fd5b5061045e6104ed3660046139fc565b610b36565b3480156104fd575f80fd5b506103dd610b4a565b348015610511575f80fd5b506103dd61052036600461396a565b610bc9565b348015610530575f80fd5b5061034d61022b5481565b348015610546575f80fd5b5061034d61055536600461396a565b610d13565b6103dd610568366004613aca565b610d6c565b348015610578575f80fd5b5061034d610e37565b34801561058c575f80fd5b5061045e61059b3660046139d2565b6001600160a01b039081165f9081526101f860205260409020541690565b3480156105c4575f80fd5b506103dd6105d33660046139d2565b610ee8565b3480156105e3575f80fd5b5061030c60c954610100900460ff1660021490565b348015610603575f80fd5b506106176106123660046139d2565b610ef2565b60405163ffffffff90911681526020016102e4565b348015610637575f80fd5b5061034d6106463660046139d2565b6001600160a01b03165f90815261012d602052604090205490565b34801561066c575f80fd5b506103dd610f14565b348015610680575f80fd5b506103dd610f25565b348015610694575f80fd5b5061022a5461045e906001600160a01b031681565b3480156106b4575f80fd5b5060fb5461045e906001600160a01b031681565b3480156106d3575f80fd5b5061034d6106e23660046139d2565b610f9c565b3480156106f2575f80fd5b506103dd610fba565b348015610706575f80fd5b5061045e61102b565b34801561071a575f80fd5b5061034d610729366004613b2a565b61103e565b348015610739575f80fd5b506102d761109a565b34801561074d575f80fd5b506103dd6110ac565b348015610761575f80fd5b5061034d610770366004613b2a565b611107565b348015610780575f80fd5b5061034d61078f3660046139d2565b611128565b34801561079f575f80fd5b506103dd6107ae36600461396a565b6111ad565b3480156107be575f80fd5b5061030c6107cd36600461396a565b611348565b3480156107dd575f80fd5b5061045e6107ec366004613b41565b6113cd565b3480156107fc575f80fd5b5061030c61080b36600461396a565b6113d9565b34801561081b575f80fd5b506103dd61082a366004613b6b565b6113e6565b34801561083a575f80fd5b506103dd610849366004613bc3565b61157f565b348015610859575f80fd5b506103dd610868366004613c72565b6116f1565b348015610878575f80fd5b506103dd610887366004613cc8565b611826565b348015610897575f80fd5b5061034d6108a6366004613d31565b611987565b3480156108b6575f80fd5b506065546001600160a01b031661045e565b3480156108d3575f80fd5b506108e76108e2366004613d68565b6119b2565b60408051825163ffffffff1681526020928301516001600160e01b031692810192909252016102e4565b34801561091c575f80fd5b506103dd61092b3660046139d2565b611a34565b606061094661093d611a9a565b61022b54611b2b565b905090565b5f33610958818585611b5f565b60019150505b92915050565b5f33610971858285611c83565b61097c858585611cfb565b60019150505b9392505050565b610991611eb7565b61022c80546001600160a01b0319166001600160a01b0392909216919091179055565b5f610946611f16565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000010096163003610a0e5760405162461bcd60e51b8152600401610a0590613d9c565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000100966001600160a01b0316610a565f80516020614124833981519152546001600160a01b031690565b6001600160a01b031614610a7c5760405162461bcd60e51b8152600401610a0590613de8565b610a8581611f91565b604080515f80825260208201909252610aa091839190611f99565b50565b5f33610958818585610ab58383611987565b610abf9190613e48565b611b5f565b5f438210610b145760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610a05565b6001600160a01b0383165f9081526101f9602052604090206109829083612108565b5f610b428484846121f8565b949350505050565b610b5e60c954610100900460ff1660021490565b610b7b5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610bc733611f91565b565b6002610bd36122e6565b60ff1603610bf45760405163dfc60d8560e01b815260040160405180910390fd5b610bfe600261231f565b610c1260c954610100900460ff1660021490565b15610c305760405163bae6e2a960e01b815260040160405180910390fd5b610c38612361565b15610c565760405163b19aa30f60e01b815260040160405180910390fd5b60fb546001600160a01b03163303610cb15760fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a3610cfb565b610cca6a195c98cc8c17dd985d5b1d60aa1b60016113cd565b6001600160a01b0316336001600160a01b031614610cfb576040516361fad54f60e11b815260040160405180910390fd5b610d05828261238a565b610d0f600161231f565b5050565b6001600160a01b0382165f90815261015f6020526040812081908190610d3a908590612394565b9150915081610d61576001600160a01b0385165f90815261012d6020526040902054610d63565b805b95945050505050565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000010096163003610db45760405162461bcd60e51b8152600401610a0590613d9c565b7f00000000000000000000000001670010000000000000000000000000000100966001600160a01b0316610dfc5f80516020614124833981519152546001600160a01b031690565b6001600160a01b031614610e225760405162461bcd60e51b8152600401610a0590613de8565b610e2b82611f91565b610d0f82826001611f99565b5f306001600160a01b037f00000000000000000000000001670010000000000000000000000000000100961614610ed65760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a05565b505f8051602061412483398151915290565b610aa03382612484565b6001600160a01b0381165f9081526101f9602052604081205461095e906124ff565b610f1c611eb7565b610bc75f612567565b60655433906001600160a01b03168114610f935760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610a05565b610aa081612567565b6001600160a01b0381165f9081526101c5602052604081205461095e565b610fce60c954610100900460ff1660021490565b15610fec5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610bb6565b5f6109466033546001600160a01b031690565b5f43821061108e5760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610a05565b61095e6101fa83612108565b60606109466110a7612580565b612590565b6110b461102b565b6001600160a01b0316336001600160a01b0316141580156110e1575061022c546001600160a01b03163314155b156110ff57604051630b1d89d360e41b815260040160405180910390fd5b610aa06125b9565b5f805f61111684610160612394565b91509150816109825761012f54610b42565b6001600160a01b0381165f9081526101f96020526040812054801561119b576001600160a01b0383165f9081526101f96020526040902061116a600183613e5b565b8154811061117a5761117a613e6e565b5f9182526020909120015464010000000090046001600160e01b031661119d565b5f5b6001600160e01b03169392505050565b60026111b76122e6565b60ff16036111d85760405163dfc60d8560e01b815260040160405180910390fd5b6111e2600261231f565b6111f660c954610100900460ff1660021490565b156112145760405163bae6e2a960e01b815260040160405180910390fd5b61121c612361565b156112f457336001600160a01b0383161461124a576040516361fad54f60e11b815260040160405180910390fd5b60fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a360fb546040516340c10f1960e01b81526001600160a01b03848116600483015260248201849052909116906340c10f19906044015f604051808303815f87803b1580156112d9575f80fd5b505af11580156112eb573d5f803e3d5ffd5b5050505061133e565b61130d6a195c98cc8c17dd985d5b1d60aa1b60016113cd565b6001600160a01b0316336001600160a01b03161461133e57604051630d85cccf60e11b815260040160405180910390fd5b610d058282612612565b5f33816113558286611987565b9050838110156113b55760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610a05565b6113c28286868403611b5f565b506001949350505050565b5f6109824684846121f8565b5f33610958818585611cfb565b60026113f06122e6565b60ff16036114115760405163dfc60d8560e01b815260040160405180910390fd5b61141b600261231f565b61142f60c954610100900460ff1660021490565b1561144d5760405163bae6e2a960e01b815260040160405180910390fd5b6a195c98cc8c17dd985d5b1d60aa1b61146461102b565b6001600160a01b0316336001600160a01b0316141580156114a1575061148b8160016113cd565b6001600160a01b0316336001600160a01b031614155b156114bf57604051630d85cccf60e11b815260040160405180910390fd5b60fb546001600160a01b0384811691161480156114ee575060fb60149054906101000a900460ff161515821515145b1561150c5760405163b253fdfd60e01b815260040160405180910390fd5b60fb80546001600160a01b0385166001600160a81b03199091168117600160a01b851515908102919091179092556040805191825260208201929092527fa6b6f959792843a48d9d03d13595f2de7c86ae0ce12ef0fa759dd911b205e565910160405180910390a150610d0f600161231f565b5f54610100900460ff161580801561159d57505f54600160ff909116105b806115b65750303b1580156115b657505f5460ff166001145b6116195760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a05565b5f805460ff19166001179055801561163a575f805461ff0019166101001790555b6116468686858561261c565b611650888861266c565b61165a82846126cb565b6116626126fb565b61166a6126fb565b61167382612721565b61022a805461022b87905560ff8616600160a01b026001600160a81b03199091166001600160a01b0389161717905580156116e7575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b834211156117415760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610a05565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b0388169181019190915260608101869052608081018590525f906117ba906117b29060a0016040516020818303038152906040528051906020012061276a565b8585856127b6565b90506117c5816127dc565b86146118135760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610a05565b61181d8188612484565b50505050505050565b834211156118765760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610a05565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886118a48c6127dc565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6118fe8261276a565b90505f61190d828787876127b6565b9050896001600160a01b0316816001600160a01b0316146119705760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610a05565b61197b8a8a8a611b5f565b50505050505050505050565b6001600160a01b039182165f90815261012e6020908152604080832093909416825291909152205490565b604080518082019091525f80825260208201526001600160a01b0383165f9081526101f960205260409020805463ffffffff84169081106119f5576119f5613e6e565b5f9182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b611a3c611eb7565b606580546001600160a01b0319166001600160a01b038316908117909155611a6261102b565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60606101308054611aaa90613e82565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad690613e82565b8015611b215780601f10611af857610100808354040283529160200191611b21565b820191905f5260205f20905b815481529060010190602001808311611b0457829003601f168201915b5050505050905090565b606082611b3783612804565b604051602001611b48929190613eb4565b604051602081830303815290604052905092915050565b6001600160a01b038316611bc15760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a05565b6001600160a01b038216611c225760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a05565b6001600160a01b038381165f81815261012e602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f611c8e8484611987565b90505f198114611cf55781811015611ce85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a05565b611cf58484848403611b5f565b50505050565b6001600160a01b038316611d5f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a05565b6001600160a01b038216611dc15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a05565b611dcc838383612894565b6001600160a01b0383165f90815261012d602052604090205481811015611e445760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610a05565b6001600160a01b038085165f81815261012d602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611ea49086815260200190565b60405180910390a3611cf58484846128fa565b33611ec061102b565b6001600160a01b031614610bc75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a05565b5f6109467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611f456101915490565b610192546040805160208101859052908101839052606081018290524660808201523060a08201525f9060c0016040516020818303038152906040528051906020012090509392505050565b610aa0611eb7565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611fd157611fcc83612905565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561202b575060408051601f3d908101601f1916820190925261202891810190613f14565b60015b61208e5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610a05565b5f8051602061412483398151915281146120fc5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610a05565b50611fcc8383836129a0565b81545f908181600581111561215f575f612121846129c4565b61212b9085613e5b565b5f88815260209020909150869082015463ffffffff16111561214f5780915061215d565b61215a816001613e48565b92505b505b808210156121aa575f6121728383612aa8565b5f88815260209020909150869082015463ffffffff161115612196578091506121a4565b6121a1816001613e48565b92505b5061215f565b80156121e3576121cc866121bf600184613e5b565b5f91825260209091200190565b5464010000000090046001600160e01b03166121e5565b5f5b6001600160e01b03169695505050505050565b6097545f906001600160a01b031661222357604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801561227a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061229e9190613f2b565b9050811580156122b557506001600160a01b038116155b1561098257604051632b0d65db60e01b815267ffffffffffffffff8516600482015260248101849052604401610a05565b5f4660010361231557507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361234d57807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b60fb545f906001600160a01b03161580159061094657505060fb54600160a01b900460ff161590565b610d0f8282612ac2565b5f805f84116123de5760405162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b6044820152606401610a05565b6123e6612acc565b8411156124355760405162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e742069640000006044820152606401610a05565b5f6124408486612ad7565b84549091508103612457575f80925092505061247d565b600184600101828154811061246e5761246e613e6e565b905f5260205f20015492509250505b9250929050565b6001600160a01b038281165f8181526101f860208181526040808420805461012d845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611cf5828483612b70565b5f63ffffffff8211156125635760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610a05565b5090565b606580546001600160a01b0319169055610aa081612cac565b60606101318054611aaa90613e82565b6060816040516020016125a39190613f46565b6040516020818303038152906040529050919050565b5f6125c961016280546001019055565b5f6125d2612acc565b90507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb678160405161260591815260200190565b60405180910390a1919050565b610d0f8282612cfd565b6001600160a01b0384161580612630575082155b8061263a57504683145b8061264457508151155b8061264e57508051155b15611cf55760405163c118d2f360e01b815260040160405180910390fd5b5f54610100900460ff166126925760405162461bcd60e51b8152600401610a0590613f6b565b61269b82612d07565b6001600160a01b0381166126c2576040516375cabfef60e11b815260040160405180910390fd5b610d0f81612d37565b5f54610100900460ff166126f15760405162461bcd60e51b8152600401610a0590613f6b565b610d0f8282612da8565b5f54610100900460ff16610bc75760405162461bcd60e51b8152600401610a0590613f6b565b5f54610100900460ff166127475760405162461bcd60e51b8152600401610a0590613f6b565b610aa081604051806040016040528060018152602001603160f81b815250612de9565b5f61095e612776611f16565b8360405161190160f01b602082015260228101839052604281018290525f9060620160405160208183030381529060405280519060200120905092915050565b5f805f6127c587878787612e2b565b915091506127d281612ee8565b5095945050505050565b6001600160a01b0381165f9081526101c5602052604090208054600181018255905b50919050565b60605f61281083613031565b60010190505f8167ffffffffffffffff81111561282f5761282f613a43565b6040519080825280601f01601f191660200182016040528015612859576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461286357509392505050565b306001600160a01b038316036128bd57604051630183150560e21b815260040160405180910390fd5b6128d160c954610100900460ff1660021490565b156128ef5760405163bae6e2a960e01b815260040160405180910390fd5b611fcc838383613108565b611fcc838383613150565b6001600160a01b0381163b6129725760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610a05565b5f8051602061412483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6129a983613182565b5f825111806129b55750805b15611fcc57611cf583836131c1565b5f815f036129d357505f919050565b5f60016129df846131e6565b901c6001901b905060018184816129f8576129f8613fb6565b048201901c90506001818481612a1057612a10613fb6565b048201901c90506001818481612a2857612a28613fb6565b048201901c90506001818481612a4057612a40613fb6565b048201901c90506001818481612a5857612a58613fb6565b048201901c90506001818481612a7057612a70613fb6565b048201901c90506001818481612a8857612a88613fb6565b048201901c905061098281828581612aa257612aa2613fb6565b04613279565b5f612ab66002848418613fca565b61098290848416613e48565b610d0f828261328e565b5f6109466101625490565b81545f908103612ae857505f61095e565b82545f905b80821015612b32575f612b008383612aa8565b5f8781526020902090915085908201541115612b1e57809150612b2c565b612b29816001613e48565b92505b50612aed565b5f82118015612b4f575083612b4c866121bf600186613e5b565b54145b15612b6857612b5f600183613e5b565b9250505061095e565b50905061095e565b816001600160a01b0316836001600160a01b031614158015612b9157505f81115b15611fcc576001600160a01b03831615612c1f576001600160a01b0383165f9081526101f9602052604081208190612bcc9061331a85613325565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612c14929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611fcc576001600160a01b0382165f9081526101f9602052604081208190612c559061347585613325565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612c9d929190918252602082015260400190565b60405180910390a25050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610d0f8282613480565b612d256001600160a01b03821615612d1f5781612567565b33612567565b5060c9805461ff001916610100179055565b5f54610100900460ff16612d5d5760405162461bcd60e51b8152600401610a0590613f6b565b67ffffffffffffffff461115612d865760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f54610100900460ff16612dce5760405162461bcd60e51b8152600401610a0590613f6b565b610130612ddb8382614034565b50610131611fcc8282614034565b5f54610100900460ff16612e0f5760405162461bcd60e51b8152600401610a0590613f6b565b8151602092830120815191909201206101919190915561019255565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e6057505f90506003612edf565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612eb1573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612ed9575f60019250925050612edf565b91505f90505b94509492505050565b5f816004811115612efb57612efb6140f4565b03612f035750565b6001816004811115612f1757612f176140f4565b03612f645760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610a05565b6002816004811115612f7857612f786140f4565b03612fc55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610a05565b6003816004811115612fd957612fd96140f4565b03610aa05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610a05565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061306f5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061309b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106130b957662386f26fc10000830492506010015b6305f5e10083106130d1576305f5e100830492506008015b61271083106130e557612710830492506004015b606483106130f7576064830492506002015b600a831061095e5760010192915050565b6001600160a01b0383166131275761311f82613499565b611fcc6134cd565b6001600160a01b03821661313e5761311f83613499565b61314783613499565b611fcc82613499565b6001600160a01b038381165f9081526101f86020526040808220548584168352912054611fcc92918216911683612b70565b61318b81612905565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606109828383604051806060016040528060278152602001614144602791396134dd565b5f80608083901c156131fa57608092831c92015b604083901c1561320c57604092831c92015b602083901c1561321e57602092831c92015b601083901c1561323057601092831c92015b600883901c1561324257600892831c92015b600483901c1561325457600492831c92015b600283901c1561326657600292831c92015b600183901c1561095e5760010192915050565b5f8183106132875781610982565b5090919050565b6132988282613551565b61012f546001600160e01b03101561330b5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610a05565b611cf56101fa61347583613325565b5f6109828284613e5b565b82545f90819081811561337157613341876121bf600185613e5b565b60408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152613385565b604080518082019091525f80825260208201525b905080602001516001600160e01b031693506133a584868863ffffffff16565b92505f821180156133bc5750805163ffffffff1643145b15613401576133ca83613624565b6133d9886121bf600186613e5b565b80546001600160e01b03929092166401000000000263ffffffff90921691909117905561346b565b866040518060400160405280613416436124ff565b63ffffffff16815260200161342a86613624565b6001600160e01b0390811690915282546001810184555f938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b5f6109828284613e48565b61348a828261368c565b611cf56101fa61331a83613325565b6001600160a01b0381165f90815261015f6020908152604080832061012d90925290912054610aa091906137d2565b6137d2565b610bc76101606134c861012f5490565b60605f80856001600160a01b0316856040516134f99190614108565b5f60405180830381855af49150503d805f8114613531576040519150601f19603f3d011682016040523d82523d5f602084013e613536565b606091505b50915091506135478683838761381a565b9695505050505050565b6001600160a01b0382166135a75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a05565b6135b25f8383612894565b8061012f5f8282546135c49190613e48565b90915550506001600160a01b0382165f81815261012d60209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610d0f5f83836128fa565b5f6001600160e01b038211156125635760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610a05565b6001600160a01b0382166136ec5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a05565b6136f7825f83612894565b6001600160a01b0382165f90815261012d60205260409020548181101561376b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a05565b6001600160a01b0383165f81815261012d60209081526040808320868603905561012f80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611fcc835f846128fa565b5f6137db612acc565b9050806137e784613892565b1015611fcc578254600180820185555f858152602080822090930193909355938401805494850181558252902090910155565b606083156138885782515f03613881576001600160a01b0385163b6138815760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a05565b5081610b42565b610b4283836138d8565b80545f9081036138a357505f919050565b815482906138b390600190613e5b565b815481106138c3576138c3613e6e565b905f5260205f2001549050919050565b919050565b8151156138e85781518083602001fd5b8060405162461bcd60e51b8152600401610a059190613924565b5f5b8381101561391c578181015183820152602001613904565b50505f910152565b602081525f8251806020840152613942816040850160208701613902565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610aa0575f80fd5b5f806040838503121561397b575f80fd5b823561398681613956565b946020939093013593505050565b5f805f606084860312156139a6575f80fd5b83356139b181613956565b925060208401356139c181613956565b929592945050506040919091013590565b5f602082840312156139e2575f80fd5b813561098281613956565b803580151581146138d3575f80fd5b5f805f60608486031215613a0e575f80fd5b833567ffffffffffffffff81168114613a25575f80fd5b925060208401359150613a3a604085016139ed565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff80841115613a7157613a71613a43565b604051601f8501601f19908116603f01168101908282118183101715613a9957613a99613a43565b81604052809350858152868686011115613ab1575f80fd5b858560208301375f602087830101525050509392505050565b5f8060408385031215613adb575f80fd5b8235613ae681613956565b9150602083013567ffffffffffffffff811115613b01575f80fd5b8301601f81018513613b11575f80fd5b613b2085823560208401613a57565b9150509250929050565b5f60208284031215613b3a575f80fd5b5035919050565b5f8060408385031215613b52575f80fd5b82359150613b62602084016139ed565b90509250929050565b5f8060408385031215613b7c575f80fd5b8235613b8781613956565b9150613b62602084016139ed565b803560ff811681146138d3575f80fd5b5f82601f830112613bb4575f80fd5b61098283833560208501613a57565b5f805f805f805f60e0888a031215613bd9575f80fd5b8735613be481613956565b96506020880135613bf481613956565b95506040880135613c0481613956565b945060608801359350613c1960808901613b95565b925060a088013567ffffffffffffffff80821115613c35575f80fd5b613c418b838c01613ba5565b935060c08a0135915080821115613c56575f80fd5b50613c638a828b01613ba5565b91505092959891949750929550565b5f805f805f8060c08789031215613c87575f80fd5b8635613c9281613956565b95506020870135945060408701359350613cae60608801613b95565b92506080870135915060a087013590509295509295509295565b5f805f805f805f60e0888a031215613cde575f80fd5b8735613ce981613956565b96506020880135613cf981613956565b95506040880135945060608801359350613d1560808901613b95565b925060a0880135915060c0880135905092959891949750929550565b5f8060408385031215613d42575f80fd5b8235613d4d81613956565b91506020830135613d5d81613956565b809150509250929050565b5f8060408385031215613d79575f80fd5b8235613d8481613956565b9150602083013563ffffffff81168114613d5d575f80fd5b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561095e5761095e613e34565b8181038181111561095e5761095e613e34565b634e487b7160e01b5f52603260045260245ffd5b600181811c90821680613e9657607f821691505b6020821081036127fe57634e487b7160e01b5f52602260045260245ffd5b670213934b233b2b2160c51b81525f8351613ed6816008850160208801613902565b634051c55b60df1b6008918401918201528351613efa81600d840160208801613902565b602960f81b600d9290910191820152600e01949350505050565b5f60208284031215613f24575f80fd5b5051919050565b5f60208284031215613f3b575f80fd5b815161098281613956565b5f8251613f57818460208701613902565b610b9d60f21b920191825250600201919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b5f52601260045260245ffd5b5f82613fe457634e487b7160e01b5f52601260045260245ffd5b500490565b601f821115611fcc57805f5260205f20601f840160051c8101602085101561400e5750805b601f840160051c820191505b8181101561402d575f815560010161401a565b5050505050565b815167ffffffffffffffff81111561404e5761404e613a43565b6140628161405c8454613e82565b84613fe9565b602080601f831160018114614095575f841561407e5750858301515b5f19600386901b1c1916600185901b1785556140ec565b5f85815260208120601f198616915b828110156140c3578886015182559484019460019091019084016140a4565b50858210156140e057878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b634e487b7160e01b5f52602160045260245ffd5b5f8251614119818460208701613902565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207e373db0be4a6e756668501d4c4e0826cd14a846b891fa07cb5482cc0b477bdd64736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010097": { + "storage": {}, + "code": "0x6080604052600436106101e6575f3560e01c806367e828bf116101085780639dc29fac1161009d578063c87b56dd1161006d578063c87b56dd1461055b578063e30c39781461057a578063e985e9c514610597578063ef8c4ae6146105df578063f2fde38b146105fe575f80fd5b80639dc29fac146104df578063a22cb465146104fe578063a86f9d9e1461051d578063b88d4fde1461053c575f80fd5b80637cf8ed0d116100d85780637cf8ed0d1461047a5780638456cb591461049a5780638da5cb5b146104ae57806395d89b41146104cb575f80fd5b806367e828bf146103ef57806370a0823114610433578063715018a61461045257806379ba509714610466575f80fd5b80633f4ba83a1161017e5780634f1ef2861161014e5780634f1ef2861461038957806352d1902d1461039c5780635c975abb146103b05780636352211e146103d0575f80fd5b80633f4ba83a1461031357806340c10f191461032757806342842e0e1461034657806349d1260514610365575f80fd5b806323b872dd116101b957806323b872dd146102975780633659cfe6146102b65780633ab76e9f146102d55780633eb6b8cf146102f4575f80fd5b806301ffc9a7146101ea57806306fdde031461021e578063081812fc1461023f578063095ea7b314610276575b5f80fd5b3480156101f5575f80fd5b50610209610204366004612468565b61061d565b60405190151581526020015b60405180910390f35b348015610229575f80fd5b5061023261066e565b60405161021591906124d0565b34801561024a575f80fd5b5061025e6102593660046124e2565b610689565b6040516001600160a01b039091168152602001610215565b348015610281575f80fd5b5061029561029036600461250d565b6106af565b005b3480156102a2575f80fd5b506102956102b1366004612537565b6107c8565b3480156102c1575f80fd5b506102956102d0366004612575565b6107f9565b3480156102e0575f80fd5b5060975461025e906001600160a01b031681565b3480156102ff575f80fd5b5061025e61030e3660046125a4565b6108d6565b34801561031e575f80fd5b506102956108ec565b348015610332575f80fd5b5061029561034136600461250d565b61096b565b348015610351575f80fd5b50610295610360366004612537565b610a37565b348015610370575f80fd5b5061037b6101605481565b604051908152602001610215565b610295610397366004612688565b610a51565b3480156103a7575f80fd5b5061037b610b1c565b3480156103bb575f80fd5b5061020960c954610100900460ff1660021490565b3480156103db575f80fd5b5061025e6103ea3660046124e2565b610bcd565b3480156103fa575f80fd5b5061041461015f54610160546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610215565b34801561043e575f80fd5b5061037b61044d366004612575565b610c2d565b34801561045d575f80fd5b50610295610cb2565b348015610471575f80fd5b50610295610cc3565b348015610485575f80fd5b5061015f5461025e906001600160a01b031681565b3480156104a5575f80fd5b50610295610d3a565b3480156104b9575f80fd5b506033546001600160a01b031661025e565b3480156104d6575f80fd5b50610232610dab565b3480156104ea575f80fd5b506102956104f936600461250d565b610dbd565b348015610509575f80fd5b506102956105183660046126d5565b610eb3565b348015610528575f80fd5b5061025e610537366004612708565b610ebe565b348015610547575f80fd5b50610295610556366004612729565b610eca565b348015610566575f80fd5b506102326105753660046124e2565b610f02565b348015610585575f80fd5b506065546001600160a01b031661025e565b3480156105a2575f80fd5b506102096105b1366004612791565b6001600160a01b039182165f9081526101326020908152604080832093909416825291909152205460ff1690565b3480156105ea575f80fd5b506102956105f93660046127c8565b610f52565b348015610609575f80fd5b50610295610618366004612575565b61109d565b5f6001600160e01b031982166380ac58cd60e01b148061064d57506001600160e01b03198216635b5e139f60e01b145b8061066857506301ffc9a760e01b6001600160e01b03198316145b92915050565b606061068461067b61110e565b6101605461119f565b905090565b5f610693826111d3565b505f90815261013160205260409020546001600160a01b031690565b5f6106b982610bcd565b9050806001600160a01b0316836001600160a01b03160361072b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610747575061074781336105b1565b6107b95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610722565b6107c38383611232565b505050565b6107d233826112a0565b6107ee5760405162461bcd60e51b815260040161072290612866565b6107c383838361131e565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000100971630036108415760405162461bcd60e51b8152600401610722906128b3565b7f00000000000000000000000001670010000000000000000000000000000100976001600160a01b03166108895f80516020612d94833981519152546001600160a01b031690565b6001600160a01b0316146108af5760405162461bcd60e51b8152600401610722906128ff565b6108b881611490565b604080515f808252602082019092526108d391839190611498565b50565b5f6108e2848484611602565b90505b9392505050565b61090060c954610100900460ff1660021490565b61091d5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a161096933611490565b565b60026109756116f0565b60ff16036109965760405163dfc60d8560e01b815260040160405180910390fd5b6109a06002611729565b6109b460c954610100900460ff1660021490565b156109d25760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b6109ed816001610ebe565b6001600160a01b0316336001600160a01b031614610a1e57604051630d85cccf60e11b815260040160405180910390fd5b610a28838361176b565b50610a336001611729565b5050565b6107c383838360405180602001604052805f815250610eca565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000010097163003610a995760405162461bcd60e51b8152600401610722906128b3565b7f00000000000000000000000001670010000000000000000000000000000100976001600160a01b0316610ae15f80516020612d94833981519152546001600160a01b031690565b6001600160a01b031614610b075760405162461bcd60e51b8152600401610722906128ff565b610b1082611490565b610a3382826001611498565b5f306001600160a01b037f00000000000000000000000001670010000000000000000000000000000100971614610bbb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610722565b505f80516020612d9483398151915290565b5f81815261012f60205260408120546001600160a01b0316806106685760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610722565b5f6001600160a01b038216610c965760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610722565b506001600160a01b03165f908152610130602052604090205490565b610cba611784565b6109695f6117de565b60655433906001600160a01b03168114610d315760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610722565b6108d3816117de565b610d4e60c954610100900460ff1660021490565b15610d6c5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610958565b6060610684610db86117f7565b611807565b6002610dc76116f0565b60ff1603610de85760405163dfc60d8560e01b815260040160405180910390fd5b610df26002611729565b610e0660c954610100900460ff1660021490565b15610e245760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b610e3f816001610ebe565b6001600160a01b0316336001600160a01b031614610e7057604051630d85cccf60e11b815260040160405180910390fd5b826001600160a01b0316610e8383610bcd565b6001600160a01b031614610eaa5760405163358bf3d960e01b815260040160405180910390fd5b610a288261181a565b610a333383836118bc565b5f6108e5468484611602565b610ed433836112a0565b610ef05760405162461bcd60e51b815260040161072290612866565b610efc8484848461198a565b50505050565b61015f5461016054606091610f22916001600160a01b03909116906119bd565b610f2b836119ed565b604051602001610f3c92919061294b565b6040516020818303038152906040529050919050565b5f54610100900460ff1615808015610f7057505f54600160ff909116105b80610f895750303b158015610f8957505f5460ff166001145b610fec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610722565b5f805460ff19166001179055801561100d575f805461ff0019166101001790555b61101985858585611a7d565b6110238787611acd565b61102d8284611b2c565b61015f80546001600160a01b0319166001600160a01b0387161790556101608490558015611094575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6110a5611784565b606580546001600160a01b0383166001600160a01b031990911681179091556110d66033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b606061012d805461111e90612979565b80601f016020809104026020016040519081016040528092919081815260200182805461114a90612979565b80156111955780601f1061116c57610100808354040283529160200191611195565b820191905f5260205f20905b81548152906001019060200180831161117857829003601f168201915b5050505050905090565b6060826111ab836119ed565b6040516020016111bc9291906129b1565b604051602081830303815290604052905092915050565b5f81815261012f60205260409020546001600160a01b03166108d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610722565b5f8181526101316020526040902080546001600160a01b0319166001600160a01b038416908117909155819061126782610bcd565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b5f806112ab83610bcd565b9050806001600160a01b0316846001600160a01b031614806112f257506001600160a01b038082165f908152610132602090815260408083209388168352929052205460ff165b806113165750836001600160a01b031661130b84610689565b6001600160a01b0316145b949350505050565b826001600160a01b031661133182610bcd565b6001600160a01b0316146113575760405162461bcd60e51b815260040161072290612a11565b6001600160a01b0382166113b95760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610722565b6113c68383836001611b5c565b826001600160a01b03166113d982610bcd565b6001600160a01b0316146113ff5760405162461bcd60e51b815260040161072290612a11565b5f8181526101316020908152604080832080546001600160a01b03199081169091556001600160a01b03878116808652610130855283862080545f190190559087168086528386208054600101905586865261012f90945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6108d3611784565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156114cb576107c383611bb7565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611525575060408051601f3d908101601f1916820190925261152291810190612a56565b60015b6115885760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610722565b5f80516020612d9483398151915281146115f65760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610722565b506107c3838383611c52565b6097545f906001600160a01b031661162d57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611684573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a89190612a6d565b9050811580156116bf57506001600160a01b038116155b156108e557604051632b0d65db60e01b815267ffffffffffffffff8516600482015260248101849052604401610722565b5f4660010361171f57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361175757807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b610a33828260405180602001604052805f815250611c76565b6033546001600160a01b031633146109695760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610722565b606580546001600160a01b03191690556108d381611ca8565b606061012e805461111e90612979565b606081604051602001610f3c9190612a88565b5f61182482610bcd565b9050611833815f846001611b5c565b61183c82610bcd565b5f8381526101316020908152604080832080546001600160a01b03199081169091556001600160a01b038516808552610130845282852080545f1901905587855261012f909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b816001600160a01b0316836001600160a01b03160361191d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610722565b6001600160a01b038381165f8181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61199584848461131e565b6119a184848484611cf9565b610efc5760405162461bcd60e51b815260040161072290612aad565b60606119d3836001600160a01b03166014611df6565b6119dc836119ed565b6040516020016111bc929190612aff565b60605f6119f983611f8c565b60010190505f8167ffffffffffffffff811115611a1857611a186125eb565b6040519080825280601f01601f191660200182016040528015611a42576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611a4c57509392505050565b6001600160a01b0384161580611a91575082155b80611a9b57504683145b80611aa557508151155b80611aaf57508051155b15610efc5760405163c118d2f360e01b815260040160405180910390fd5b5f54610100900460ff16611af35760405162461bcd60e51b815260040161072290612b6e565b611afc82612063565b6001600160a01b038116611b23576040516375cabfef60e11b815260040160405180910390fd5b610a3381612093565b5f54610100900460ff16611b525760405162461bcd60e51b815260040161072290612b6e565b610a338282612104565b306001600160a01b03841603611b8557604051630183150560e21b815260040160405180910390fd5b611b9960c954610100900460ff1660021490565b15610efc5760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0381163b611c245760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610722565b5f80516020612d9483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611c5b83612145565b5f82511180611c675750805b156107c357610efc8383612184565b611c8083836121a9565b611c8c5f848484611cf9565b6107c35760405162461bcd60e51b815260040161072290612aad565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f6001600160a01b0384163b15611deb57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611d3c903390899088908890600401612bb9565b6020604051808303815f875af1925050508015611d76575060408051601f3d908101601f19168201909252611d7391810190612beb565b60015b611dd1573d808015611da3576040519150601f19603f3d011682016040523d82523d5f602084013e611da8565b606091505b5080515f03611dc95760405162461bcd60e51b815260040161072290612aad565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611316565b506001949350505050565b60605f611e04836002612c1a565b611e0f906002612c31565b67ffffffffffffffff811115611e2757611e276125eb565b6040519080825280601f01601f191660200182016040528015611e51576020820181803683370190505b509050600360fc1b815f81518110611e6b57611e6b612c44565b60200101906001600160f81b03191690815f1a905350600f60fb1b81600181518110611e9957611e99612c44565b60200101906001600160f81b03191690815f1a9053505f611ebb846002612c1a565b611ec6906001612c31565b90505b6001811115611f3d576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611efa57611efa612c44565b1a60f81b828281518110611f1057611f10612c44565b60200101906001600160f81b03191690815f1a90535060049490941c93611f3681612c58565b9050611ec9565b5083156108e55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610722565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611fca5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611ff6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061201457662386f26fc10000830492506010015b6305f5e100831061202c576305f5e100830492506008015b612710831061204057612710830492506004015b60648310612052576064830492506002015b600a83106106685760010192915050565b6120816001600160a01b0382161561207b57816117de565b336117de565b5060c9805461ff001916610100179055565b5f54610100900460ff166120b95760405162461bcd60e51b815260040161072290612b6e565b67ffffffffffffffff4611156120e25760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f54610100900460ff1661212a5760405162461bcd60e51b815260040161072290612b6e565b61012d6121378382612cb8565b5061012e6107c38282612cb8565b61214e81611bb7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606108e58383604051806060016040528060278152602001612db460279139612342565b6001600160a01b0382166121ff5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610722565b5f81815261012f60205260409020546001600160a01b0316156122645760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610722565b6122715f83836001611b5c565b5f81815261012f60205260409020546001600160a01b0316156122d65760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610722565b6001600160a01b0382165f818152610130602090815260408083208054600101905584835261012f90915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60605f80856001600160a01b03168560405161235e9190612d78565b5f60405180830381855af49150503d805f8114612396576040519150601f19603f3d011682016040523d82523d5f602084013e61239b565b606091505b50915091506123ac868383876123b6565b9695505050505050565b606083156124245782515f0361241d576001600160a01b0385163b61241d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610722565b5081611316565b61131683838151156124395781518083602001fd5b8060405162461bcd60e51b815260040161072291906124d0565b6001600160e01b0319811681146108d3575f80fd5b5f60208284031215612478575f80fd5b81356108e581612453565b5f5b8381101561249d578181015183820152602001612485565b50505f910152565b5f81518084526124bc816020860160208601612483565b601f01601f19169290920160200192915050565b602081525f6108e560208301846124a5565b5f602082840312156124f2575f80fd5b5035919050565b6001600160a01b03811681146108d3575f80fd5b5f806040838503121561251e575f80fd5b8235612529816124f9565b946020939093013593505050565b5f805f60608486031215612549575f80fd5b8335612554816124f9565b92506020840135612564816124f9565b929592945050506040919091013590565b5f60208284031215612585575f80fd5b81356108e5816124f9565b8035801515811461259f575f80fd5b919050565b5f805f606084860312156125b6575f80fd5b833567ffffffffffffffff811681146125cd575f80fd5b9250602084013591506125e260408501612590565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f83011261260e575f80fd5b813567ffffffffffffffff80821115612629576126296125eb565b604051601f8301601f19908116603f01168101908282118183101715612651576126516125eb565b81604052838152866020858801011115612669575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215612699575f80fd5b82356126a4816124f9565b9150602083013567ffffffffffffffff8111156126bf575f80fd5b6126cb858286016125ff565b9150509250929050565b5f80604083850312156126e6575f80fd5b82356126f1816124f9565b91506126ff60208401612590565b90509250929050565b5f8060408385031215612719575f80fd5b823591506126ff60208401612590565b5f805f806080858703121561273c575f80fd5b8435612747816124f9565b93506020850135612757816124f9565b925060408501359150606085013567ffffffffffffffff811115612779575f80fd5b612785878288016125ff565b91505092959194509250565b5f80604083850312156127a2575f80fd5b82356127ad816124f9565b915060208301356127bd816124f9565b809150509250929050565b5f805f805f8060c087890312156127dd575f80fd5b86356127e8816124f9565b955060208701356127f8816124f9565b94506040870135612808816124f9565b935060608701359250608087013567ffffffffffffffff8082111561282b575f80fd5b6128378a838b016125ff565b935060a089013591508082111561284c575f80fd5b5061285989828a016125ff565b9150509295509295509295565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f835161295c818460208801612483565b835190830190612970818360208801612483565b01949350505050565b600181811c9082168061298d57607f821691505b6020821081036129ab57634e487b7160e01b5f52602260045260245ffd5b50919050565b670213934b233b2b2160c51b81525f83516129d3816008850160208801612483565b634051c55b60df1b60089184019182015283516129f781600d840160208801612483565b602960f81b600d9290910191820152600e01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b5f60208284031215612a66575f80fd5b5051919050565b5f60208284031215612a7d575f80fd5b81516108e5816124f9565b5f8251612a99818460208701612483565b610b9d60f21b920191825250600201919050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6832ba3432b932bab69d60b91b81525f8351612b22816009850160208801612483565b600160fe1b6009918401918201528351612b4381600a840160208801612483565b712f746f6b656e5552493f75696e743235363d60701b600a9290910191820152601c01949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906123ac908301846124a5565b5f60208284031215612bfb575f80fd5b81516108e581612453565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761066857610668612c06565b8082018082111561066857610668612c06565b634e487b7160e01b5f52603260045260245ffd5b5f81612c6657612c66612c06565b505f190190565b601f8211156107c357805f5260205f20601f840160051c81016020851015612c925750805b601f840160051c820191505b81811015612cb1575f8155600101612c9e565b5050505050565b815167ffffffffffffffff811115612cd257612cd26125eb565b612ce681612ce08454612979565b84612c6d565b602080601f831160018114612d19575f8415612d025750858301515b5f19600386901b1c1916600185901b178555612d70565b5f85815260208120601f198616915b82811015612d4757888601518255948401946001909101908401612d28565b5085821015612d6457878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8251612d89818460208701612483565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c4486d9ca4840f96f11ee225b65f721fee7c79fc3710037edf9cc01522aac1a664736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010098": { + "storage": {}, + "code": "0x6080604052600436106101c4575f3560e01c8063715018a6116100f2578063a86f9d9e11610092578063ef8c4ae611610062578063ef8c4ae61461050a578063f242432a14610529578063f2fde38b14610548578063f5298aca14610567575f80fd5b8063a86f9d9e14610467578063d81d0a1514610486578063e30c3978146104a5578063e985e9c5146104c2575f80fd5b80638456cb59116100cd5780638456cb59146104035780638da5cb5b1461041757806395d89b4114610434578063a22cb46514610448575f80fd5b8063715018a6146103bb57806379ba5097146103cf5780637cf8ed0d146103e3575f80fd5b80633ab76e9f116101685780634e1273f4116101385780634e1273f4146103485780634f1ef2861461037457806352d1902d146103875780635c975abb1461039b575f80fd5b80633ab76e9f146102c85780633eb6b8cf146102ff5780633f4ba83a1461031e57806349d1260514610332575f80fd5b80630e89341c116101a35780630e89341c1461024a578063156e29f6146102695780632eb2c2d61461028a5780633659cfe6146102a9575f80fd5b8062fdd58e146101c857806301ffc9a7146101fa57806306fdde0314610229575b5f80fd5b3480156101d3575f80fd5b506101e76101e23660046127b0565b610586565b6040519081526020015b60405180910390f35b348015610205575f80fd5b506102196102143660046127ef565b610620565b60405190151581526020016101f1565b348015610234575f80fd5b5061023d61066f565b6040516101f19190612857565b348015610255575f80fd5b5061023d610264366004612869565b61070c565b348015610274575f80fd5b50610288610283366004612880565b61079f565b005b348015610295575f80fd5b506102886102a43660046129f6565b61087d565b3480156102b4575f80fd5b506102886102c3366004612a9c565b6108c9565b3480156102d3575f80fd5b506097546102e7906001600160a01b031681565b6040516001600160a01b0390911681526020016101f1565b34801561030a575f80fd5b506102e7610319366004612acb565b6109a6565b348015610329575f80fd5b506102886109bc565b34801561033d575f80fd5b506101e76101605481565b348015610353575f80fd5b50610367610362366004612b11565b610a3b565b6040516101f19190612c11565b610288610382366004612c23565b610b5a565b348015610392575f80fd5b506101e7610c29565b3480156103a6575f80fd5b5061021960c954610100900460ff1660021490565b3480156103c6575f80fd5b50610288610cdb565b3480156103da575f80fd5b50610288610cec565b3480156103ee575f80fd5b5061015f546102e7906001600160a01b031681565b34801561040e575f80fd5b50610288610d63565b348015610422575f80fd5b506033546001600160a01b03166102e7565b34801561043f575f80fd5b5061023d610dd4565b348015610453575f80fd5b50610288610462366004612c65565b610e68565b348015610472575f80fd5b506102e7610481366004612c98565b610e73565b348015610491575f80fd5b506102886104a0366004612cb9565b610e7f565b3480156104b0575f80fd5b506065546001600160a01b03166102e7565b3480156104cd575f80fd5b506102196104dc366004612d29565b6001600160a01b039182165f90815261012e6020908152604080832093909416825291909152205460ff1690565b348015610515575f80fd5b50610288610524366004612d60565b610f4d565b348015610534575f80fd5b50610288610543366004612dfd565b6110f2565b348015610553575f80fd5b50610288610562366004612a9c565b611137565b348015610572575f80fd5b50610288610581366004612880565b6111a8565b5f6001600160a01b0383166105f55760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b505f81815261012d602090815260408083206001600160a01b03861684529091529020545b92915050565b5f6001600160e01b03198216636cdb3d1360e11b148061065057506001600160e01b031982166303a24d0760e21b145b8061061a57506301ffc9a760e01b6001600160e01b031983161461061a565b6060610707610162805461068290612e60565b80601f01602080910402602001604051908101604052809291908181526020018280546106ae90612e60565b80156106f95780601f106106d0576101008083540402835291602001916106f9565b820191905f5260205f20905b8154815290600101906020018083116106dc57829003601f168201915b505050505061016054611267565b905090565b606061012f805461071c90612e60565b80601f016020809104026020016040519081016040528092919081815260200182805461074890612e60565b80156107935780601f1061076a57610100808354040283529160200191610793565b820191905f5260205f20905b81548152906001019060200180831161077657829003601f168201915b50505050509050919050565b60026107a961129b565b60ff16036107ca5760405163dfc60d8560e01b815260040160405180910390fd5b6107d460026112d4565b6107e860c954610100900460ff1660021490565b156108065760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b610822816001610e73565b6001600160a01b0316336001600160a01b03161461085357604051630d85cccf60e11b815260040160405180910390fd5b61086d84848460405180602001604052805f815250611316565b5061087860016112d4565b505050565b6001600160a01b038516331480610899575061089985336104dc565b6108b55760405162461bcd60e51b81526004016105ec90612e98565b6108c285858585856113f3565b5050505050565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000100981630036109115760405162461bcd60e51b81526004016105ec90612ee6565b7f00000000000000000000000001670010000000000000000000000000000100986001600160a01b03166109595f8051602061355a833981519152546001600160a01b031690565b6001600160a01b03161461097f5760405162461bcd60e51b81526004016105ec90612f32565b61098881611596565b604080515f808252602082019092526109a39183919061159e565b50565b5f6109b2848484611708565b90505b9392505050565b6109d060c954610100900460ff1660021490565b6109ed5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610a3933611596565b565b60608151835114610aa05760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016105ec565b5f83516001600160401b03811115610aba57610aba6128b2565b604051908082528060200260200182016040528015610ae3578160200160208202803683370190505b5090505f5b8451811015610b5257610b2d858281518110610b0657610b06612f7e565b6020026020010151858381518110610b2057610b20612f7e565b6020026020010151610586565b828281518110610b3f57610b3f612f7e565b6020908102919091010152600101610ae8565b509392505050565b6001600160a01b037f0000000000000000000000000167001000000000000000000000000000010098163003610ba25760405162461bcd60e51b81526004016105ec90612ee6565b7f00000000000000000000000001670010000000000000000000000000000100986001600160a01b0316610bea5f8051602061355a833981519152546001600160a01b031690565b6001600160a01b031614610c105760405162461bcd60e51b81526004016105ec90612f32565b610c1982611596565b610c258282600161159e565b5050565b5f306001600160a01b037f00000000000000000000000001670010000000000000000000000000000100981614610cc85760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016105ec565b505f8051602061355a8339815191525b90565b610ce36117f4565b610a395f61184e565b60655433906001600160a01b03168114610d5a5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105ec565b6109a38161184e565b610d7760c954610100900460ff1660021490565b15610d955760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610a28565b60606107076101618054610de790612e60565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1390612e60565b8015610e5e5780601f10610e3557610100808354040283529160200191610e5e565b820191905f5260205f20905b815481529060010190602001808311610e4157829003601f168201915b5050505050611867565b610c25338383611890565b5f6109b5468484611708565b6002610e8961129b565b60ff1603610eaa5760405163dfc60d8560e01b815260040160405180910390fd5b610eb460026112d4565b610ec860c954610100900460ff1660021490565b15610ee65760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b610f02816001610e73565b6001600160a01b0316336001600160a01b031614610f3357604051630d85cccf60e11b815260040160405180910390fd5b61086d84848460405180602001604052805f815250611970565b5f54610100900460ff1615808015610f6b57505f54600160ff909116105b80610f845750303b158015610f8457505f5460ff166001145b610fe75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105ec565b5f805460ff191660011790558015611008575f805461ff0019166101001790555b61104a858560405180604001604052806003815260200162666f6f60e81b81525060405180604001604052806003815260200162666f6f60e81b815250611ab8565b6110548787611b0e565b6110666110618686611b6d565b611b9d565b61015f80546001600160a01b0319166001600160a01b0387161790556101608490556101616110958482612fd6565b506101626110a38382612fd6565b5080156110e9575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6001600160a01b03851633148061110e575061110e85336104dc565b61112a5760405162461bcd60e51b81526004016105ec90612e98565b6108c28585858585611bcc565b61113f6117f4565b606580546001600160a01b0383166001600160a01b031990911681179091556111706033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60026111b261129b565b60ff16036111d35760405163dfc60d8560e01b815260040160405180910390fd5b6111dd60026112d4565b6111f160c954610100900460ff1660021490565b1561120f5760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b61122b816001610e73565b6001600160a01b0316336001600160a01b03161461125c57604051630d85cccf60e11b815260040160405180910390fd5b61086d848484611d06565b60608261127383611e95565b604051602001611284929190613091565b604051602081830303815290604052905092915050565b5f466001036112ca57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361130257807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b6001600160a01b03841661133c5760405162461bcd60e51b81526004016105ec906130f1565b335f61134785611f24565b90505f61135385611f24565b9050611363835f89858589611f6d565b5f86815261012d602090815260408083206001600160a01b038b16845290915281208054879290611395908490613146565b909155505060408051878152602081018790526001600160a01b03808a16925f92918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46110e9835f89898989611fc8565b81518351146114145760405162461bcd60e51b81526004016105ec90613159565b6001600160a01b03841661143a5760405162461bcd60e51b81526004016105ec906131a1565b33611449818787878787611f6d565b5f5b8451811015611528575f85828151811061146757611467612f7e565b602002602001015190505f85838151811061148457611484612f7e565b6020908102919091018101515f84815261012d835260408082206001600160a01b038e1683529093529190912054909150818110156114d55760405162461bcd60e51b81526004016105ec906131e6565b5f83815261012d602090815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290611514908490613146565b90915550506001909301925061144b915050565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051611578929190613230565b60405180910390a461158e818787878787612122565b505050505050565b6109a36117f4565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156115d157610878836121dc565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561162b575060408051601f3d908101601f191682019092526116289181019061325d565b60015b61168e5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016105ec565b5f8051602061355a83398151915281146116fc5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016105ec565b50610878838383612277565b6097545f906001600160a01b031661173357604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611789573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ad9190613274565b9050811580156117c457506001600160a01b038116155b156109b557604051632b0d65db60e01b81526001600160401b0385166004820152602481018490526044016105ec565b6033546001600160a01b03163314610a395760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105ec565b606580546001600160a01b03191690556109a38161229b565b60608160405160200161187a919061328f565b6040516020818303038152906040529050919050565b816001600160a01b0316836001600160a01b0316036119035760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016105ec565b6001600160a01b038381165f81815261012e6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166119965760405162461bcd60e51b81526004016105ec906130f1565b81518351146119b75760405162461bcd60e51b81526004016105ec90613159565b336119c6815f87878787611f6d565b5f5b8451811015611a52578381815181106119e3576119e3612f7e565b602002602001015161012d5f878481518110611a0157611a01612f7e565b602002602001015181526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f828254611a459190613146565b90915550506001016119c8565b50846001600160a01b03165f6001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051611aa2929190613230565b60405180910390a46108c2815f87878787612122565b6001600160a01b0384161580611acc575082155b80611ad657504683145b80611ae057508151155b80611aea57508051155b15611b085760405163c118d2f360e01b815260040160405180910390fd5b50505050565b5f54610100900460ff16611b345760405162461bcd60e51b81526004016105ec906132b4565b611b3d826122ec565b6001600160a01b038116611b64576040516375cabfef60e11b815260040160405180910390fd5b610c258161231c565b6060611b83836001600160a01b0316601461238c565b611b8c83611e95565b6040516020016112849291906132ff565b5f54610100900460ff16611bc35760405162461bcd60e51b81526004016105ec906132b4565b6109a381612521565b6001600160a01b038416611bf25760405162461bcd60e51b81526004016105ec906131a1565b335f611bfd85611f24565b90505f611c0985611f24565b9050611c19838989858589611f6d565b5f86815261012d602090815260408083206001600160a01b038c16845290915290205485811015611c5c5760405162461bcd60e51b81526004016105ec906131e6565b5f87815261012d602090815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290611c9b908490613146565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611cfb848a8a8a8a8a611fc8565b505050505050505050565b6001600160a01b038316611d685760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b60648201526084016105ec565b335f611d7384611f24565b90505f611d7f84611f24565b9050611d9d83875f858560405180602001604052805f815250611f6d565b5f85815261012d602090815260408083206001600160a01b038a16845290915290205484811015611e1c5760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b60648201526084016105ec565b5f86815261012d602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a460408051602081019091525f90526110e9565b60605f611ea183612550565b60010190505f816001600160401b03811115611ebf57611ebf6128b2565b6040519080825280601f01601f191660200182016040528015611ee9576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611ef357509392505050565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110611f5c57611f5c612f7e565b602090810291909101015292915050565b306001600160a01b03851603611f9657604051630183150560e21b815260040160405180910390fd5b611faa60c954610100900460ff1660021490565b1561158e5760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0384163b1561158e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e619061200c908990899088908890889060040161336e565b6020604051808303815f875af1925050508015612046575060408051601f3d908101601f19168201909252612043918101906133b2565b60015b6120f2576120526133cd565b806308c379a00361208b57506120666133e5565b80612071575061208d565b8060405162461bcd60e51b81526004016105ec9190612857565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016105ec565b6001600160e01b0319811663f23a6e6160e01b146110e95760405162461bcd60e51b81526004016105ec9061346d565b6001600160a01b0384163b1561158e5760405163bc197c8160e01b81526001600160a01b0385169063bc197c819061216690899089908890889088906004016134b5565b6020604051808303815f875af19250505080156121a0575060408051601f3d908101601f1916820190925261219d918101906133b2565b60015b6121ac576120526133cd565b6001600160e01b0319811663bc197c8160e01b146110e95760405162461bcd60e51b81526004016105ec9061346d565b6001600160a01b0381163b6122495760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016105ec565b5f8051602061355a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61228083612627565b5f8251118061228c5750805b1561087857611b088383612666565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61230a6001600160a01b03821615612304578161184e565b3361184e565b5060c9805461ff001916610100179055565b5f54610100900460ff166123425760405162461bcd60e51b81526004016105ec906132b4565b6001600160401b0346111561236a5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60605f61239a836002613512565b6123a5906002613146565b6001600160401b038111156123bc576123bc6128b2565b6040519080825280601f01601f1916602001820160405280156123e6576020820181803683370190505b509050600360fc1b815f8151811061240057612400612f7e565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061242e5761242e612f7e565b60200101906001600160f81b03191690815f1a9053505f612450846002613512565b61245b906001613146565b90505b60018111156124d2576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061248f5761248f612f7e565b1a60f81b8282815181106124a5576124a5612f7e565b60200101906001600160f81b03191690815f1a90535060049490941c936124cb81613529565b905061245e565b5083156109b55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105ec565b5f54610100900460ff166125475760405162461bcd60e51b81526004016105ec906132b4565b6109a38161268b565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061258e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106125ba576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106125d857662386f26fc10000830492506010015b6305f5e10083106125f0576305f5e100830492506008015b612710831061260457612710830492506004015b60648310612616576064830492506002015b600a831061061a5760010192915050565b612630816121dc565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606109b5838360405180606001604052806027815260200161357a60279139612698565b61012f610c258282612fd6565b60605f80856001600160a01b0316856040516126b4919061353e565b5f60405180830381855af49150503d805f81146126ec576040519150601f19603f3d011682016040523d82523d5f602084013e6126f1565b606091505b50915091506127028683838761270c565b9695505050505050565b6060831561277a5782515f03612773576001600160a01b0385163b6127735760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ec565b5081612784565b612784838361278c565b949350505050565b8151156120715781518083602001fd5b6001600160a01b03811681146109a3575f80fd5b5f80604083850312156127c1575f80fd5b82356127cc8161279c565b946020939093013593505050565b6001600160e01b0319811681146109a3575f80fd5b5f602082840312156127ff575f80fd5b81356109b5816127da565b5f5b8381101561282457818101518382015260200161280c565b50505f910152565b5f815180845261284381602086016020860161280a565b601f01601f19169290920160200192915050565b602081525f6109b5602083018461282c565b5f60208284031215612879575f80fd5b5035919050565b5f805f60608486031215612892575f80fd5b833561289d8161279c565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b03811182821017156128eb576128eb6128b2565b6040525050565b5f6001600160401b0382111561290a5761290a6128b2565b5060051b60200190565b5f82601f830112612923575f80fd5b81356020612930826128f2565b60405161293d82826128c6565b80915083815260208101915060208460051b870101935086841115612960575f80fd5b602086015b8481101561297c5780358352918301918301612965565b509695505050505050565b5f82601f830112612996575f80fd5b81356001600160401b038111156129af576129af6128b2565b6040516129c6601f8301601f1916602001826128c6565b8181528460208386010111156129da575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215612a0a575f80fd5b8535612a158161279c565b94506020860135612a258161279c565b935060408601356001600160401b0380821115612a40575f80fd5b612a4c89838a01612914565b94506060880135915080821115612a61575f80fd5b612a6d89838a01612914565b93506080880135915080821115612a82575f80fd5b50612a8f88828901612987565b9150509295509295909350565b5f60208284031215612aac575f80fd5b81356109b58161279c565b80358015158114612ac6575f80fd5b919050565b5f805f60608486031215612add575f80fd5b83356001600160401b0381168114612af3575f80fd5b925060208401359150612b0860408501612ab7565b90509250925092565b5f8060408385031215612b22575f80fd5b82356001600160401b0380821115612b38575f80fd5b818501915085601f830112612b4b575f80fd5b81356020612b58826128f2565b604051612b6582826128c6565b83815260059390931b8501820192828101915089841115612b84575f80fd5b948201945b83861015612bab578535612b9c8161279c565b82529482019490820190612b89565b96505086013592505080821115612bc0575f80fd5b50612bcd85828601612914565b9150509250929050565b5f815180845260208085019450602084015f5b83811015612c0657815187529582019590820190600101612bea565b509495945050505050565b602081525f6109b56020830184612bd7565b5f8060408385031215612c34575f80fd5b8235612c3f8161279c565b915060208301356001600160401b03811115612c59575f80fd5b612bcd85828601612987565b5f8060408385031215612c76575f80fd5b8235612c818161279c565b9150612c8f60208401612ab7565b90509250929050565b5f8060408385031215612ca9575f80fd5b82359150612c8f60208401612ab7565b5f805f60608486031215612ccb575f80fd5b8335612cd68161279c565b925060208401356001600160401b0380821115612cf1575f80fd5b612cfd87838801612914565b93506040860135915080821115612d12575f80fd5b50612d1f86828701612914565b9150509250925092565b5f8060408385031215612d3a575f80fd5b8235612d458161279c565b91506020830135612d558161279c565b809150509250929050565b5f805f805f8060c08789031215612d75575f80fd5b8635612d808161279c565b95506020870135612d908161279c565b94506040870135612da08161279c565b93506060870135925060808701356001600160401b0380821115612dc2575f80fd5b612dce8a838b01612987565b935060a0890135915080821115612de3575f80fd5b50612df089828a01612987565b9150509295509295509295565b5f805f805f60a08688031215612e11575f80fd5b8535612e1c8161279c565b94506020860135612e2c8161279c565b9350604086013592506060860135915060808601356001600160401b03811115612e54575f80fd5b612a8f88828901612987565b600181811c90821680612e7457607f821691505b602082108103612e9257634e487b7160e01b5f52602260045260245ffd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52603260045260245ffd5b601f82111561087857805f5260205f20601f840160051c81016020851015612fb75750805b601f840160051c820191505b818110156108c2575f8155600101612fc3565b81516001600160401b03811115612fef57612fef6128b2565b61300381612ffd8454612e60565b84612f92565b602080601f831160018114613036575f841561301f5750858301515b5f19600386901b1c1916600185901b17855561158e565b5f85815260208120601f198616915b8281101561306457888601518255948401946001909101908401613045565b508582101561308157878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b670213934b233b2b2160c51b81525f83516130b381600885016020880161280a565b634051c55b60df1b60089184019182015283516130d781600d84016020880161280a565b602960f81b600d9290910191820152600e01949350505050565b60208082526021908201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736040820152607360f81b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561061a5761061a613132565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081525f6132426040830185612bd7565b82810360208401526132548185612bd7565b95945050505050565b5f6020828403121561326d575f80fd5b5051919050565b5f60208284031215613284575f80fd5b81516109b58161279c565b5f82516132a081846020870161280a565b610b9d60f21b920191825250600201919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6832ba3432b932bab69d60b91b81525f835161332281600985016020880161280a565b600160fe1b600991840191820152835161334381600a84016020880161280a565b712f746f6b656e5552493f75696e743235363d60701b600a9290910191820152601c01949350505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f906133a79083018461282c565b979650505050505050565b5f602082840312156133c2575f80fd5b81516109b5816127da565b5f60033d1115610cd85760045f803e505f5160e01c90565b5f60443d10156133f25790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561342157505050505090565b82850191508151818111156134395750505050505090565b843d87010160208285010111156134535750505050505090565b613462602082860101876128c6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a0604082018190525f906134e090830186612bd7565b82810360608401526134f28186612bd7565b90508281036080840152613506818561282c565b98975050505050505050565b808202811582820484141761061a5761061a613132565b5f8161353757613537613132565b505f190190565b5f825161354f81846020870161280a565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220bd3fdb4c6dc0647e883a48f490bd9cea420ea3e74a0fb4881a0592a16dd7031d64736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x60806040526004361061017b575f3560e01c8063715018a6116100cd5780639b527cfa11610087578063e30c397811610062578063e30c397814610479578063f09a401614610496578063f2fde38b146104b5578063fe9fbb80146104d4575f80fd5b80639b527cfa146103fd578063a86f9d9e1461041c578063dfc8ff1d1461043b575f80fd5b8063715018a61461036657806379ba50971461037a5780638456cb591461038e5780638da5cb5b146103a2578063910af6ed146103bf57806391f3f74b146103de575f80fd5b80633eb6b8cf116101385780634f90a674116101135780634f90a674146102e657806352d1902d146103135780635c975abb1461032757806366ca2bc014610347575f80fd5b80633eb6b8cf146102a05780633f4ba83a146102bf5780634f1ef286146102d3575f80fd5b80632d1fb3891461017f57806332676bc6146101a0578063355bcc3d146101d45780633659cfe61461022b5780633ab76e9f1461024a5780633ced0e0814610281575b5f80fd5b34801561018a575f80fd5b5061019e6101993660046135b4565b610502565b005b3480156101ab575f80fd5b506101bf6101ba3660046135e7565b6105a8565b60405190151581526020015b60405180910390f35b3480156101df575f80fd5b506102136101ee366004613627565b60fb60209081525f92835260408084209091529082529020546001600160401b031681565b6040516001600160401b0390911681526020016101cb565b348015610236575f80fd5b5061019e610245366004613641565b6105be565b348015610255575f80fd5b50609754610269906001600160a01b031681565b6040516001600160a01b0390911681526020016101cb565b34801561028c575f80fd5b506101bf61029b36600461365c565b6106a4565b3480156102ab575f80fd5b506102696102ba36600461369d565b6106eb565b3480156102ca575f80fd5b5061019e610701565b61019e6102e13660046137ad565b610780565b3480156102f1575f80fd5b5061030561030036600461365c565b61084f565b6040519081526020016101cb565b34801561031e575f80fd5b50610305610895565b348015610332575f80fd5b506101bf60c954610100900460ff1660021490565b348015610352575f80fd5b506103056103613660046137f9565b610946565b348015610371575f80fd5b5061019e610952565b348015610385575f80fd5b5061019e610963565b348015610399575f80fd5b5061019e6109da565b3480156103ad575f80fd5b506033546001600160a01b0316610269565b3480156103ca575f80fd5b5061019e6103d9366004613810565b610a4b565b3480156103e9575f80fd5b506103056103f83660046138a4565b610ce4565b348015610408575f80fd5b506103056104173660046138e0565b610d4f565b348015610427575f80fd5b50610269610436366004613910565b610d7b565b348015610446575f80fd5b5061045a6104553660046138e0565b610d87565b604080516001600160401b0390931683526020830191909152016101cb565b348015610484575f80fd5b506065546001600160a01b0316610269565b3480156104a1575f80fd5b5061019e6104b0366004613931565b610e1b565b3480156104c0575f80fd5b5061019e6104cf366004613641565b610f2a565b3480156104df575f80fd5b506101bf6104ee366004613641565b60fc6020525f908152604090205460ff1681565b61050a610f9b565b6001600160a01b0382165f90815260fc602052604090205481151560ff90911615150361054a576040516398f26f4560e01b815260040160405180910390fd5b6001600160a01b0382165f81815260fc6020908152604091829020805460ff191685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b5f6105b38383610ff5565b151590505b92915050565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000000000516300361060f5760405162461bcd60e51b815260040161060690613968565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000000056001600160a01b03166106575f80516020613fc7833981519152546001600160a01b031690565b6001600160a01b03161461067d5760405162461bcd60e51b8152600401610606906139b4565b61068681611057565b604080515f808252602082019092526106a19183919061105f565b50565b5f818082036106c657604051630426d36960e31b815260040160405180910390fd5b5f6106d2878787610d4f565b9050836106df3083610ff5565b14979650505050505050565b5f6106f78484846111c9565b90505b9392505050565b61071560c954610100900460ff1660021490565b6107325760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a161077e336112b5565b565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000000051630036107c85760405162461bcd60e51b815260040161060690613968565b7f00000000000000000000000001670010000000000000000000000000000000056001600160a01b03166108105f80516020613fc7833981519152546001600160a01b031690565b6001600160a01b0316146108365760405162461bcd60e51b8152600401610606906139b4565b61083f82611057565b61084b8282600161105f565b5050565b335f90815260fc602052604081205460ff1661087e57604051631f67751f60e01b815260040160405180910390fd5b61088a858585856112ce565b90505b949350505050565b5f306001600160a01b037f000000000000000000000000016700100000000000000000000000000000000516146109345760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610606565b505f80516020613fc783398151915290565b5f6105b83383846113b0565b61095a610f9b565b61077e5f611489565b60655433906001600160a01b031681146109d15760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610606565b6106a181611489565b6109ee60c954610100900460ff1660021490565b15610a0c5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161076d565b836001600160a01b038116610a73576040516327e0ab1560e21b815260040160405180910390fd5b835f819003610a9557604051630426d36960e31b815260040160405180910390fd5b5f610aa284860186613aaf565b905080515f03610ac557604051630b92daef60e21b815260040160405180910390fd5b878787805f610ae6856d7369676e616c5f7365727669636560901b836106eb565b9050610b206040805160c0810182525f80825260208201819052918101829052906060820190815260200160608152602001606081525090565b5f5b8751811015610c9f57878181518110610b3d57610b3d613bed565b602002602001015191505f610b568888888887896114a2565b90505f60018a51610b679190613c15565b831490508015610ba35783516001600160401b03164614610b9b576040516338bf822760e21b815260040160405180910390fd5b309450610c02565b83516001600160401b03161580610bc3575083516001600160401b031646145b15610be157604051637556223560e11b815260040160405180910390fd5b8351610bff906d7369676e616c5f7365727669636560901b5f6106eb565b94505b5f80856080015151119050610c1f858b8760200151868587611541565b5f81610c4b577fc6cdc4f2acf13acb10f410085b821f7b7113b303e9a4799023f928317396aaf5610c6d565b7f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da1695b9050610c7e8b828860200151610d4f565b985085604001519750855f01519a5086995050505050806001019050610b22565b50821580610cb65750610cb23085610ff5565b8314155b15610cd45760405163738afa0560e01b815260040160405180910390fd5b5050505050505050505050505050565b6040516514d251d3905360d21b60208201526001600160c01b031960c085901b1660268201526bffffffffffffffffffffffff19606084901b16602e820152604281018290525f906062015b6040516020818303038152906040528051906020012090509392505050565b604080516001600160401b03808616602083015291810184905290821660608201525f90608001610d30565b5f6106fa4684846111c9565b5f80826001600160401b03165f03610dc3576001600160401b038086165f90815260fb6020908152604080832088845290915290205416610dc5565b825b91506001600160401b03821615610e13575f610de2868685610d4f565b9050610dee3082610ff5565b91505f829003610e115760405163738afa0560e01b815260040160405180910390fd5b505b935093915050565b5f54610100900460ff1615808015610e3957505f54600160ff909116105b80610e525750303b158015610e5257505f5460ff166001145b610eb55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610606565b5f805460ff191660011790558015610ed6575f805461ff0019166101001790555b610ee08383611653565b8015610f25575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b610f32610f9b565b606580546001600160a01b0383166001600160a01b03199091168117909155610f636033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6033546001600160a01b0316331461077e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610606565b5f826001600160a01b03811661101e576040516327e0ab1560e21b815260040160405180910390fd5b825f81900361104057604051630426d36960e31b815260040160405180910390fd5b5f61104c468787610ce4565b549695505050505050565b6106a1610f9b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561109257610f25836116b2565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156110ec575060408051601f3d908101601f191682019092526110e991810190613c28565b60015b61114f5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610606565b5f80516020613fc783398151915281146111bd5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610606565b50610f2583838361174d565b6097545f906001600160a01b03166111f457604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801561124a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061126e9190613c3f565b90508115801561128557506001600160a01b038116155b156106fa57604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610606565b60405163198bb9dd60e11b815260040160405180910390fd5b5f6112da858585610d4f565b90506112e73082846113b0565b506001600160401b038581165f90815260fb6020908152604080832088845290915290205481851691161015611351576001600160401b038581165f90815260fb602090815260408083208884529091529020805467ffffffffffffffff19169185169190911790555b83836001600160401b0316866001600160401b03167fde247c825b1fb2d7ff9e0e771cba6f9e757ad04479fcdc135d88ae91fd50b37d85856040516113a0929190918252602082015260400190565b60405180910390a4949350505050565b5f836001600160a01b0381166113d9576040516327e0ab1560e21b815260040160405180910390fd5b835f8190036113fb57604051630426d36960e31b815260040160405180910390fd5b835f81900361141d57604051630426d36960e31b815260040160405180910390fd5b611428468888610ce4565b858155604080516001600160a01b038a16815260208101899052908101829052606081018790529094507f0ad2d108660a211f47bf7fb43a0443cae181624995d3d42b88ee6879d200e9739060800160405180910390a15050509392505050565b606580546001600160a01b03191690556106a181611777565b5f856001600160a01b0381166114cb576040516327e0ab1560e21b815260040160405180910390fd5b855f8190036114ed57604051630426d36960e31b815260040160405180910390fd5b855f81900361150f57604051630426d36960e31b815260040160405180910390fd5b6115338660400151866115238d8d8d610ce4565b8a8a608001518b60a001516117c8565b9a9950505050505050505050565b5f60038760600151600381111561155a5761155a613c5a565b148061157b575060028760600151600381111561157957611579613c5a565b145b90508080156115875750825b8015611591575081155b156115c8576115c6867f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169878a604001516112ce565b505b5f6003886060015160038111156115e1576115e1613c5a565b1480611602575060018860600151600381111561160057611600613c5a565b145b905080801561161657508380611616575082155b1561164957611647877fc6cdc4f2acf13acb10f410085b821f7b7113b303e9a4799023f928317396aaf588886112ce565b505b5050505050505050565b5f54610100900460ff166116795760405162461bcd60e51b815260040161060690613c6e565b611682826118d5565b6001600160a01b0381166116a9576040516375cabfef60e11b815260040160405180910390fd5b61084b81611905565b6001600160a01b0381163b61171f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610606565b5f80516020613fc783398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61175683611975565b5f825111806117625750805b15610f255761177183836119b4565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f82515f14611870576040516bffffffffffffffffffffffff19606088901b1660208201525f9061180c90603401604051602081830303815290604052858a6119d9565b905080515f0361182f57604051630414cd5b60e31b815260040160405180910390fd5b5f611839826119fb565b905061185e8160028151811061185157611851613bed565b6020026020010151611a0e565b61186790613cb9565b92505050611873565b50855b5f6118aa8660405160200161188a91815260200190565b60408051601f198184030181529190526118a387611b2e565b8585611b41565b9050806118ca57604051638d9a4db360e01b815260040160405180910390fd5b509695505050505050565b6118f36001600160a01b038216156118ed5781611489565b33611489565b5060c9805461ff001916610100179055565b5f54610100900460ff1661192b5760405162461bcd60e51b815260040161060690613c6e565b6001600160401b034611156119535760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b61197e816116b2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606106fa8383604051806060016040528060278152602001613fe760279139611b64565b60605f6119e585611bce565b90506119f2818585611c00565b95945050505050565b60606105b8611a098361246d565b6124be565b60605f805f611a1c856126db565b919450925090505f816001811115611a3657611a36613c5a565b14611aa95760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610606565b611ab38284613cdf565b855114611b1f5760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b6064820152608401610606565b6119f285602001518484612d82565b60606105b8611b3c83612e12565b612f2d565b5f80611b4c86611bce565b9050611b5a81868686612f85565b9695505050505050565b60605f80856001600160a01b031685604051611b809190613d14565b5f60405180830381855af49150503d805f8114611bb8576040519150601f19603f3d011682016040523d82523d5f602084013e611bbd565b606091505b5091509150611b5a86838387612fab565b60608180519060200120604051602001611bea91815260200190565b6040516020818303038152906040529050919050565b60605f845111611c4a5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b6044820152606401610606565b5f611c5484613023565b90505f611c608661310d565b90505f84604051602001611c7691815260200190565b60405160208183030381529060405290505f805b8451811015612416575f858281518110611ca657611ca6613bed565b602002602001015190508451831115611d185760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b6064820152608401610606565b825f03611db65780518051602091820120604051611d6592611d3f92910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b611db15760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610606565b611eac565b805151602011611e3c5780518051602091820120604051611de092611d3f92910190815260200190565b611db15760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b6064820152608401610606565b805184516020808701919091208251919092012014611eac5760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b6064820152608401610606565b611eb860106001613cdf565b816020015151036120505784518303611fea57611ee5816020015160108151811061185157611851613bed565b96505f875111611f5d5760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610606565b60018651611f6b9190613c15565b8214611fdf5760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610606565b5050505050506106fa565b5f858481518110611ffd57611ffd613bed565b602001015160f81c60f81b60f81c90505f82602001518260ff168151811061202757612027613bed565b6020026020010151905061203a8161316e565b9550612047600186613cdf565b9450505061240d565b6002816020015151036123b4575f61206782613192565b90505f815f8151811061207c5761207c613bed565b016020015160f81c90505f612092600283613d43565b61209d906002613d64565b90505f6120ad848360ff166131b5565b90505f6120ba8a896131b5565b90505f6120c783836131ea565b90508083511461213f5760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610606565b60ff851660021480612154575060ff85166003145b156122f457808251146121cf5760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610606565b6121e9876020015160018151811061185157611851613bed565b9c505f8d51116122615760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610606565b60018c5161226f9190613c15565b88146122e35760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610606565b5050505050505050505050506106fa565b60ff85161580612307575060ff85166001145b1561234657612333876020015160018151811061232657612326613bed565b602002602001015161316e565b995061233f818a613cdf565b98506123a9565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b6064820152608401610606565b50505050505061240d565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b6064820152608401610606565b50600101611c8a565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b6064820152608401610606565b604080518082019091525f80825260208201525f8251116124a05760405162461bcd60e51b815260040161060690613d7d565b50604080518082019091528151815260209182019181019190915290565b60605f805f6124cc856126db565b9194509250905060018160018111156124e7576124e7613c5a565b1461255a5760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610606565b84516125668385613cdf565b146125ce5760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b6064820152608401610606565b604080516020808252610420820190925290816020015b604080518082019091525f80825260208201528152602001906001900390816125e55790505093505f835b86518110156126cf575f806126546040518060400160405280858c5f01516126389190613c15565b8152602001858c6020015161264d9190613cdf565b90526126db565b5091509150604051806040016040528083836126709190613cdf565b8152602001848b602001516126859190613cdf565b81525088858151811061269a5761269a613bed565b60209081029190910101526126b0600185613cdf565b93506126bc8183613cdf565b6126c69084613cdf565b92505050612610565b50845250919392505050565b5f805f80845f0151116127005760405162461bcd60e51b815260040161060690613d7d565b602084015180515f1a607f8111612722575f60015f9450945094505050612d7b565b60b7811161287b575f612736608083613c15565b905080875f0151116127b45760405162461bcd60e51b815260206004820152604e60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a401610606565b6001838101516001600160f81b03191690821415806127e15750600160ff1b6001600160f81b0319821610155b6128695760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a401610606565b506001955093505f9250612d7b915050565b60bf8111612ab4575f61288f60b783613c15565b905080875f0151116129105760405162461bcd60e51b815260206004820152605160248201525f80516020613fa783398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a401610606565b60018301516001600160f81b0319165f8190036129955760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a401610606565b600184015160088302610100031c60378111612a175760405162461bcd60e51b815260206004820152604860248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a401610606565b612a218184613cdf565b895111612a985760405162461bcd60e51b815260206004820152604c60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a401610606565b612aa3836001613cdf565b975095505f9450612d7b9350505050565b60f78111612b53575f612ac860c083613c15565b905080875f015111612b425760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a401610606565b600195509350849250612d7b915050565b5f612b5f60f783613c15565b905080875f015111612bdc5760405162461bcd60e51b815260206004820152604d60248201525f80516020613fa783398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a401610606565b60018301516001600160f81b0319165f819003612c5f5760405162461bcd60e51b815260206004820152604860248201525f80516020613fa783398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a401610606565b600184015160088302610100031c60378111612cdf5760405162461bcd60e51b815260206004820152604660248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a401610606565b612ce98184613cdf565b895111612d5e5760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a401610606565b612d69836001613cdf565b9750955060019450612d7b9350505050565b9193909250565b6060816001600160401b03811115612d9c57612d9c6136d6565b6040519080825280601f01601f191660200182016040528015612dc6576020820181803683370190505b50905081156106fa575f612dda8486613cdf565b9050602082015f5b84811015612dfa578281015182820152602001612de2565b84811115612e08575f858301525b5050509392505050565b60605f82604051602001612e2891815260200190565b60405160208183030381529060405290505f5b6020811015612e7357818181518110612e5657612e56613bed565b01602001516001600160f81b0319165f03612e7357600101612e3b565b612e7e816020613c15565b6001600160401b03811115612e9557612e956136d6565b6040519080825280601f01601f191660200182016040528015612ebf576020820181803683370190505b5092505f5b8351811015612f25578282612ed881613ded565b935081518110612eea57612eea613bed565b602001015160f81c60f81b848281518110612f0757612f07613bed565b60200101906001600160f81b03191690815f1a905350600101612ec4565b505050919050565b606081516001148015612f5957506080825f81518110612f4f57612f4f613bed565b016020015160f81c105b15612f62575090565b612f6e8251608061326d565b82604051602001611bea929190613e05565b919050565b5f61088a84612f95878686611c00565b8051602091820120825192909101919091201490565b606083156130195782515f03613012576001600160a01b0385163b6130125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610606565b508161088d565b61088d8383613412565b8051606090806001600160401b03811115613040576130406136d6565b60405190808252806020026020018201604052801561308557816020015b604080518082019091526060808252602082015281526020019060019003908161305e5790505b5091505f5b818110156131065760405180604001604052808583815181106130af576130af613bed565b602002602001015181526020016130de8684815181106130d1576130d1613bed565b60200260200101516119fb565b8152508382815181106130f3576130f3613bed565b602090810291909101015260010161308a565b5050919050565b606080604051905082518060011b603f8101601f191683016040528083525060208401602083015f5b83811015613163578060011b8201818401515f1a8060041c8253600f811660018301535050600101613136565b509295945050505050565b60606020825f0151106131895761318482611a0e565b6105b8565b6105b88261343c565b60606105b86131b083602001515f8151811061185157611851613bed565b61310d565b6060825182106131d3575060408051602081019091525f81526105b8565b6106fa83838486516131e59190613c15565b613450565b5f8082518451106131fc5782516131ff565b83515b90505b8082108015613256575082828151811061321e5761321e613bed565b602001015160f81c60f81b6001600160f81b03191684838151811061324557613245613bed565b01602001516001600160f81b031916145b1561326657816001019150613202565b5092915050565b606060388310156132d157604080516001808252818301909252906020820181803683370190505090506132a18284613e33565b60f81b815f815181106132b6576132b6613bed565b60200101906001600160f81b03191690815f1a9053506105b8565b5f60015b6132df8186613e4c565b1561330557816132ee81613ded565b92506132fe905061010082613e5f565b90506132d5565b613310826001613cdf565b6001600160401b03811115613327576133276136d6565b6040519080825280601f01601f191660200182016040528015613351576020820181803683370190505b50925061335e8483613e33565b613369906037613e33565b60f81b835f8151811061337e5761337e613bed565b60200101906001600160f81b03191690815f1a905350600190505b81811161340a576101006133ad8284613c15565b6133b990610100613f56565b6133c39087613e4c565b6133cd9190613f61565b60f81b8382815181106133e2576133e2613bed565b60200101906001600160f81b03191690815f1a9053508061340281613ded565b915050613399565b505092915050565b8151156134225781518083602001fd5b8060405162461bcd60e51b81526004016106069190613f74565b60606105b882602001515f845f0151612d82565b60608182601f0110156134965760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610606565b8282840110156134d95760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610606565b818301845110156135205760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610606565b60608215801561353e5760405191505f825260208201604052613588565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561357757805183526020928301920161355f565b5050858452601f01601f1916604052505b50949350505050565b6001600160a01b03811681146106a1575f80fd5b80358015158114612f80575f80fd5b5f80604083850312156135c5575f80fd5b82356135d081613591565b91506135de602084016135a5565b90509250929050565b5f80604083850312156135f8575f80fd5b823561360381613591565b946020939093013593505050565b80356001600160401b0381168114612f80575f80fd5b5f8060408385031215613638575f80fd5b61360383613611565b5f60208284031215613651575f80fd5b81356106fa81613591565b5f805f806080858703121561366f575f80fd5b61367885613611565b93506020850135925061368d60408601613611565b9396929550929360600135925050565b5f805f606084860312156136af575f80fd5b6136b884613611565b9250602084013591506136cd604085016135a5565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b038111828210171561370c5761370c6136d6565b60405290565b604051601f8201601f191681016001600160401b038111828210171561373a5761373a6136d6565b604052919050565b5f82601f830112613751575f80fd5b81356001600160401b0381111561376a5761376a6136d6565b61377d601f8201601f1916602001613712565b818152846020838601011115613791575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156137be575f80fd5b82356137c981613591565b915060208301356001600160401b038111156137e3575f80fd5b6137ef85828601613742565b9150509250929050565b5f60208284031215613809575f80fd5b5035919050565b5f805f805f60808688031215613824575f80fd5b61382d86613611565b9450602086013561383d81613591565b93506040860135925060608601356001600160401b038082111561385f575f80fd5b818801915088601f830112613872575f80fd5b813581811115613880575f80fd5b896020828501011115613891575f80fd5b9699959850939650602001949392505050565b5f805f606084860312156138b6575f80fd5b6138bf84613611565b925060208401356138cf81613591565b929592945050506040919091013590565b5f805f606084860312156138f2575f80fd5b6138fb84613611565b9250602084013591506136cd60408501613611565b5f8060408385031215613921575f80fd5b823591506135de602084016135a5565b5f8060408385031215613942575f80fd5b823561394d81613591565b9150602083013561395d81613591565b809150509250929050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f6001600160401b03821115613a1857613a186136d6565b5060051b60200190565b803560048110612f80575f80fd5b5f82601f830112613a3f575f80fd5b81356020613a54613a4f83613a00565b613712565b82815260059290921b84018101918181019086841115613a72575f80fd5b8286015b848110156118ca5780356001600160401b03811115613a93575f80fd5b613aa18986838b0101613742565b845250918301918301613a76565b5f6020808385031215613ac0575f80fd5b82356001600160401b0380821115613ad6575f80fd5b818501915085601f830112613ae9575f80fd5b8135613af7613a4f82613a00565b81815260059190911b83018401908481019088831115613b15575f80fd5b8585015b83811015613be057803585811115613b2f575f80fd5b860160c0818c03601f19011215613b44575f80fd5b613b4c6136ea565b613b57898301613611565b81526040613b66818401613611565b8a8301526060808401358284015260809150613b83828501613a22565b9083015260a08381013589811115613b99575f80fd5b613ba78f8d83880101613a30565b838501525060c0840135915088821115613bbf575f80fd5b613bcd8e8c84870101613a30565b9083015250845250918601918601613b19565b5098975050505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156105b8576105b8613c01565b5f60208284031215613c38575f80fd5b5051919050565b5f60208284031215613c4f575f80fd5b81516106fa81613591565b634e487b7160e01b5f52602160045260245ffd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b80516020808301519190811015613cd9575f198160200360031b1b821691505b50919050565b808201808211156105b8576105b8613c01565b5f5b83811015613d0c578181015183820152602001613cf4565b50505f910152565b5f8251613d25818460208701613cf2565b9190910192915050565b634e487b7160e01b5f52601260045260245ffd5b5f60ff831680613d5557613d55613d2f565b8060ff84160691505092915050565b60ff82811682821603908111156105b8576105b8613c01565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b5f60018201613dfe57613dfe613c01565b5060010190565b5f8351613e16818460208801613cf2565b835190830190613e2a818360208801613cf2565b01949350505050565b60ff81811683821601908111156105b8576105b8613c01565b5f82613e5a57613e5a613d2f565b500490565b80820281158282048414176105b8576105b8613c01565b600181815b80851115613eb057815f1904821115613e9657613e96613c01565b80851615613ea357918102915b93841c9390800290613e7b565b509250929050565b5f82613ec6575060016105b8565b81613ed257505f6105b8565b8160018114613ee85760028114613ef257613f0e565b60019150506105b8565b60ff841115613f0357613f03613c01565b50506001821b6105b8565b5060208310610133831016604e8410600b8410161715613f31575081810a6105b8565b613f3b8383613e76565b805f1904821115613f4e57613f4e613c01565b029392505050565b5f6106fa8383613eb8565b5f82613f6f57613f6f613d2f565b500690565b602081525f8251806020840152613f92816040850160208701613cf2565b601f01601f1916919091016040019291505056fe524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220086245f267c0f9365ffe3853d097cbfffb98727240039a42f202338e33d37bc464736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000000006", + "0xe3ad9bc7a782493ccba4f8a469cc3f9e8fb5647c2076401c8a7c4945a999c777": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000000005" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000005c8da51fd337936ed0c49480e7a5ad7bcec2217a" + }, + "code": "0x6080604052600436106101c5575f3560e01c80638551f41e116100f2578063c3f909d411610092578063f2fde38b11610062578063f2fde38b1461051f578063f535bd561461053e578063f940e3851461055e578063ff4d18151461057d575f80fd5b8063c3f909d414610490578063da69d3db146104cd578063dac5df78146104ec578063e30c397814610502575f80fd5b80638da5cb5b116100cd5780638da5cb5b146104105780639ee512f21461042d578063a7e022d114610452578063a86f9d9e14610471575f80fd5b80638551f41e146103985780638ae5449c146103c45780638aff87b2146103ea575f80fd5b80634f1ef28611610168578063715018a611610138578063715018a61461034957806379ba50971461035d5780637f07c947146103715780638456cb5914610384575f80fd5b80634f1ef286146102e357806352d1902d146102f65780635950f9f11461030a5780635c975abb14610329575f80fd5b80633659cfe6116101a35780633659cfe6146102585780633ab76e9f146102795780633eb6b8cf146102b05780633f4ba83a146102cf575f80fd5b806323ac7136146101c95780632f980473146101fb57806333d5ac9b14610219575b5f80fd5b3480156101d4575f80fd5b506101e86101e3366004612242565b61059c565b6040519081526020015b60405180910390f35b348015610206575f80fd5b505f5b60405190151581526020016101f2565b348015610224575f80fd5b5061012f5461024090600160401b90046001600160401b031681565b6040516001600160401b0390911681526020016101f2565b348015610263575f80fd5b50610277610272366004612271565b6105f9565b005b348015610284575f80fd5b50609754610298906001600160a01b031681565b6040516001600160a01b0390911681526020016101f2565b3480156102bb575f80fd5b506102986102ca366004612299565b6106df565b3480156102da575f80fd5b506102776106f5565b6102776102f1366004612374565b610774565b348015610301575f80fd5b506101e8610843565b348015610315575f80fd5b506102776103243660046123c0565b6108f4565b348015610334575f80fd5b5061020960c954610100900460ff1660021490565b348015610354575f80fd5b50610277610ab0565b348015610368575f80fd5b50610277610ac1565b61027761037f366004612419565b610b38565b34801561038f575f80fd5b50610277610dcf565b3480156103a3575f80fd5b506101e86103b2366004612484565b61012d6020525f908152604090205481565b3480156103cf575f80fd5b506103d8600581565b60405160ff90911681526020016101f2565b3480156103f5575f80fd5b5060fb5461024090600160401b90046001600160401b031681565b34801561041b575f80fd5b506033546001600160a01b0316610298565b348015610438575f80fd5b5061029871777735367b36bc9b61c50022d9d0700db4ec81565b34801561045d575f80fd5b506101e861046c3660046124b3565b610e40565b34801561047c575f80fd5b5061029861048b3660046124e6565b610e71565b34801561049b575f80fd5b5060408051808201825263039387008082526008602092830190815283519182525160ff1691810191909152016101f2565b3480156104d8575f80fd5b506102776104e7366004612514565b610e86565b3480156104f7575f80fd5b506101e861012e5481565b34801561050d575f80fd5b506065546001600160a01b0316610298565b34801561052a575f80fd5b50610277610539366004612271565b61118d565b348015610549575f80fd5b5061012f54610240906001600160401b031681565b348015610569575f80fd5b50610277610578366004612559565b6111fe565b348015610588575f80fd5b5060fb54610240906001600160401b031681565b5f43826001600160401b0316106105b457505f919050565b436105c183610100612599565b6001600160401b0316106105dd57506001600160401b03164090565b506001600160401b03165f90815261012d602052604090205490565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000001000116300361064a5760405162461bcd60e51b8152600401610641906125c0565b60405180910390fd5b7f00000000000000000000000001670010000000000000000000000000000100016001600160a01b03166106925f805160206128e9833981519152546001600160a01b031690565b6001600160a01b0316146106b85760405162461bcd60e51b81526004016106419061260c565b6106c1816113b9565b604080515f808252602082019092526106dc918391906113c1565b50565b5f6106eb84848461152b565b90505b9392505050565b61070960c954610100900460ff1660021490565b6107265760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610772336113b9565b565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000100011630036107bc5760405162461bcd60e51b8152600401610641906125c0565b7f00000000000000000000000001670010000000000000000000000000000100016001600160a01b03166108045f805160206128e9833981519152546001600160a01b031690565b6001600160a01b03161461082a5760405162461bcd60e51b81526004016106419061260c565b610833826113b9565b61083f828260016113c1565b5050565b5f306001600160a01b037f000000000000000000000000016700100000000000000000000000000001000116146108e25760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610641565b505f805160206128e983398151915290565b5f54610100900460ff161580801561091257505f54600160ff909116105b8061092b5750303b15801561092b57505f5460ff166001145b61098e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610641565b5f805460ff1916600117905580156109af575f805461ff0019166101001790555b6109ba858585611617565b6001461115806109d057506001600160401b0346115b156109ee576040516306cffa2760e01b815260040160405180910390fd5b4315610a395743600103610a20575f610a08600143612658565b5f81815261012d602052604090209040905550610a39565b604051635a0f9e4160e11b815260040160405180910390fd5b61012f805467ffffffffffffffff19166001600160401b038416179055610a5f436116a8565b5061012e558015610aa9575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610ab8611738565b6107725f611792565b60655433906001600160a01b03168114610b2f5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610641565b6106dc81611792565b610b4c60c954610100900460ff1660021490565b15610b6a5760405163bae6e2a960e01b815260040160405180910390fd5b6562726964676560d01b610b7f816001610e71565b6001600160a01b0316336001600160a01b031614610bb057604051630d85cccf60e11b815260040160405180910390fd5b5f80610bbe8486018661266b565b60fb5491935091506001600160401b03808416600160401b9092041614610bf8576040516339985e7960e11b815260040160405180910390fd5b5f336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c599190612687565b60fb5460408201519192506001600160401b039182169116141580610c9f57506033546001600160a01b03166001600160a01b031681602001516001600160a01b031614155b15610cbd57604051632efb161b60e21b815260040160405180910390fd5b5f306001600160a01b031683604051610cd6919061270f565b5f604051808303815f865af19150503d805f8114610d0f576040519150601f19603f3d011682016040523d82523d5f602084013e610d14565b606091505b5050905080610d3657604051630103c9e160e11b815260040160405180910390fd5b610d3f8361272a565b60fb80546001600160e01b03199290921691600160401b90046001600160401b0316906008610d6d83612761565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167f3c5c4a24a5f3333977c7d675661b0611a16f3c611b9ea63c0be82f4ffa9174c560405160405180910390a350505050505050565b610de360c954610100900460ff1660021490565b15610e015760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610761565b5f610e69610e6260408051808201909152630393870081526008602082015290565b84846117ab565b509392505050565b5f610e7d46848461152b565b90505b92915050565b6002610e906118df565b60ff1603610eb15760405163dfc60d8560e01b815260040160405180910390fd5b610ebb6002611918565b831580610ec6575082155b80610ed857506001600160401b038216155b80610ef3575043600114158015610ef3575063ffffffff8116155b15610f115760405163053fd54760e01b815260040160405180910390fd5b3371777735367b36bc9b61c50022d9d0700db4ec14610f4357604051636494e9f760e01b815260040160405180910390fd5b5f1943015f80610f52836116a8565b915091508161012e5414610f795760405163d719258d60e01b815260040160405180910390fd5b5f610f9860408051808201909152630393870081526008602082015290565b90505f610fa68288886117ab565b61012f805467ffffffffffffffff19166001600160401b03929092169190911790559050488114610fea576040516336d54d4f60e11b815260040160405180910390fd5b61012f5461100a90600590600160401b90046001600160401b0316612599565b6001600160401b0316876001600160401b031611156111165761103e6d7369676e616c5f7365727669636560901b5f610e71565b60fb546040516313e4299d60e21b81526001600160401b0391821660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da16960248201529089166044820152606481018a90526001600160a01b039190911690634f90a674906084016020604051808303815f875af11580156110c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e99190612786565b5061012f80546fffffffffffffffff00000000000000001916600160401b6001600160401b038a16021790555b5f85815261012d602090815260409182902087409081905561012e86905561012f5483519182526001600160401b0316918101919091527f41c3f410f5c8ac36bb46b1dccef0de0f964087c9e688795fa02ecfa2c20b3fe4910160405180910390a150505050506111876001611918565b50505050565b611195611738565b606580546001600160a01b0383166001600160a01b031990911681179091556111c66033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b693bb4ba34323930bbb2b960b11b61121e6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561125b5750611245816001610e71565b6001600160a01b0316336001600160a01b031614155b1561127957604051630d85cccf60e11b815260040160405180910390fd5b60026112836118df565b60ff16036112a45760405163dfc60d8560e01b815260040160405180910390fd5b6112ae6002611918565b6112c260c954610100900460ff1660021490565b156112e05760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0382166113075760405163053fd54760e01b815260040160405180910390fd5b6001600160a01b03831661132d576113286001600160a01b0383164761195a565b6113aa565b6040516370a0823160e01b81523060048201526113aa9083906001600160a01b038616906370a0823190602401602060405180830381865afa158015611375573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113999190612786565b6001600160a01b0386169190611965565b6113b46001611918565b505050565b6106dc611738565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156113f4576113b4836119b7565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561144e575060408051601f3d908101601f1916820190925261144b91810190612786565b60015b6114b15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610641565b5f805160206128e9833981519152811461151f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610641565b506113b4838383611a52565b6097545f906001600160a01b031661155657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa1580156115ac573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d0919061279d565b9050811580156115e757506001600160a01b038116155b156106ee57604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610641565b5f54610100900460ff1661163d5760405162461bcd60e51b8152600401610641906127b8565b6116478383611a76565b6001600160401b0381161580611665575046816001600160401b0316145b156116835760405163f49a838160e01b815260040160405180910390fd5b60fb805467ffffffffffffffff19166001600160401b03929092169190911790555050565b5f806116b261220e565b5f5b60ff811080156116c75750806001018510155b156116f8575f198186030180408360ff830661010081106116ea576116ea612817565b6020020152506001016116b4565b5046611fe08201526120008120925083408161171560ff8761282b565b610100811061172657611726612817565b60200201526120009020919391925050565b6033546001600160a01b031633146107725760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610641565b606580546001600160a01b03191690556106dc81611ad5565b61012f545f9081906001600160401b0316156118cb5761012f545f906117e19063ffffffff8616906001600160401b031661283e565b61012f549091505f90600160401b90046001600160401b03161580159061181e575061012f546001600160401b03600160401b9091048116908716115b1561184d5761012f5461184190600160401b90046001600160401b031687612851565b6001600160401b031690505b80156118855786515f906118679063ffffffff1683612871565b9050808311611877576001611881565b6118818184612658565b9250505b611896826001600160401b03611b26565b92506118c6836001600160401b0316885f015163ffffffff16896020015160ff166118c19190612871565b611b3a565b935050505b815f036118d757600191505b935093915050565b5f4660010361190e57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361194657807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b61083f82825a611b83565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526113b4908490611be7565b6001600160a01b0381163b611a245760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610641565b5f805160206128e983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611a5b83611cb8565b5f82511180611a675750805b156113b4576111878383611cf7565b5f54610100900460ff16611a9c5760405162461bcd60e51b8152600401610641906127b8565b611aa582611d1c565b6001600160a01b038116611acc576040516375cabfef60e11b815260040160405180910390fd5b61083f81611d4c565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f818311611b345782610e7d565b50919050565b5f815f03611b5b57604051636296f1b960e11b815260040160405180910390fd5b81670de0b6b3a7640000611b6f8585611dbc565b611b799190612888565b610e7d9190612888565b6001600160a01b038316611baa57604051634c67134d60e11b815260040160405180910390fd5b5f611bc68483856040805180602001604052805f815250611e0b565b5090508061118757604051634c67134d60e11b815260040160405180910390fd5b5f611c3b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e909092919063ffffffff16565b8051909150156113b45780806020019051810190611c59919061289b565b6113b45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610641565b611cc1816119b7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610e7d838360405180606001604052806027815260200161290960279139611e9e565b611d3a6001600160a01b03821615611d345781611792565b33611792565b5060c9805461ff001916610100179055565b5f54610100900460ff16611d725760405162461bcd60e51b8152600401610641906127b8565b6001600160401b03461115611d9a5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f8082611dd1670de0b6b3a764000086612871565b611ddb9190612888565b9050680755bf798b4a1bf1e4811115611dfa5750680755bf798b4a1bf1e45b611e0381611f12565b949350505050565b5f60605f805f8661ffff166001600160401b03811115611e2d57611e2d6122d8565b6040519080825280601f01601f191660200182016040528015611e57576020820181803683370190505b5090505f808751602089018b8e8ef191503d925086831115611e77578692505b828152825f602083013e90999098509650505050505050565b60606106eb84845f8561209a565b60605f80856001600160a01b031685604051611eba919061270f565b5f60405180830381855af49150503d805f8114611ef2576040519150601f19603f3d011682016040523d82523d5f602084013e611ef7565b606091505b5091509150611f0886838387612171565b9695505050505050565b5f680248ce36a70cb26b3e198213611f2b57505f919050565b680755bf798b4a1bf1e58212611f5457604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b0591505f60606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060824710156120fb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610641565b5f80866001600160a01b03168587604051612116919061270f565b5f6040518083038185875af1925050503d805f8114612150576040519150601f19603f3d011682016040523d82523d5f602084013e612155565b606091505b509150915061216687838387612171565b979650505050505050565b606083156121df5782515f036121d8576001600160a01b0385163b6121d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610641565b5081611e03565b611e0383838151156121f45781518083602001fd5b8060405162461bcd60e51b815260040161064191906128b6565b604051806120000160405280610100906020820280368337509192915050565b6001600160401b03811681146106dc575f80fd5b5f60208284031215612252575f80fd5b81356106ee8161222e565b6001600160a01b03811681146106dc575f80fd5b5f60208284031215612281575f80fd5b81356106ee8161225d565b80151581146106dc575f80fd5b5f805f606084860312156122ab575f80fd5b83356122b68161222e565b92506020840135915060408401356122cd8161228c565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122fb575f80fd5b81356001600160401b0380821115612315576123156122d8565b604051601f8301601f19908116603f0116810190828211818310171561233d5761233d6122d8565b81604052838152866020858801011115612355575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215612385575f80fd5b82356123908161225d565b915060208301356001600160401b038111156123aa575f80fd5b6123b6858286016122ec565b9150509250929050565b5f805f80608085870312156123d3575f80fd5b84356123de8161225d565b935060208501356123ee8161225d565b925060408501356123fe8161222e565b9150606085013561240e8161222e565b939692955090935050565b5f806020838503121561242a575f80fd5b82356001600160401b0380821115612440575f80fd5b818501915085601f830112612453575f80fd5b813581811115612461575f80fd5b866020828501011115612472575f80fd5b60209290920196919550909350505050565b5f60208284031215612494575f80fd5b5035919050565b803563ffffffff811681146124ae575f80fd5b919050565b5f80604083850312156124c4575f80fd5b82356124cf8161222e565b91506124dd6020840161249b565b90509250929050565b5f80604083850312156124f7575f80fd5b8235915060208301356125098161228c565b809150509250929050565b5f805f8060808587031215612527575f80fd5b843593506020850135925060408501356125408161222e565b915061254e6060860161249b565b905092959194509250565b5f806040838503121561256a575f80fd5b82356125758161225d565b915060208301356125098161225d565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b038181168382160190808211156125b9576125b9612585565b5092915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b81810381811115610e8057610e80612585565b5f806040838503121561267c575f80fd5b82356123908161222e565b5f60608284031215612697575f80fd5b604051606081018181106001600160401b03821117156126b9576126b96122d8565b6040528251815260208301516126ce8161225d565b602082015260408301516126e18161222e565b60408201529392505050565b5f5b838110156127075781810151838201526020016126ef565b50505f910152565b5f82516127208184602087016126ed565b9190910192915050565b805160208201516001600160e01b031980821692919060048310156127595780818460040360031b1b83161693505b505050919050565b5f6001600160401b0380831681810361277c5761277c612585565b6001019392505050565b5f60208284031215612796575f80fd5b5051919050565b5f602082840312156127ad575f80fd5b81516106ee8161225d565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f8261283957612839612803565b500690565b80820180821115610e8057610e80612585565b6001600160401b038281168282160390808211156125b9576125b9612585565b8082028115828204841417610e8057610e80612585565b5f8261289657612896612803565b500490565b5f602082840312156128ab575f80fd5b81516106ee8161228c565b602081525f82518060208401526128d48160408501602087016126ed565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206294eebd0a1e2295f6326946d26a923ca45bc11d39d90a34f97088d8a49b0b1e64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000005c8da51fd337936ed0c49480e7a5ad7bcec2217a", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670010000000000000000000000000000010002", + "0x00000000000000000000000000000000000000000000000000000000000000fb": "0x0000000000000000000000000000000000000000000000000000000000007e7e", + "0x000000000000000000000000000000000000000000000000000000000000012f": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000012e": "0xf167b245aa70c0a5e2f44cd65a94f2b1c5c9e8c8ab059940e4bf1c47d7a39557", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000010001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74" + }, + "code": "0x6080604052600436106100fa575f3560e01c80635c975abb116100925780638da5cb5b116100625780638da5cb5b14610299578063a86f9d9e146102b6578063d8f4648f146102d5578063e30c3978146102f4578063f2fde38b14610311575f80fd5b80635c975abb1461022d578063715018a61461025d57806379ba5097146102715780638456cb5914610285575f80fd5b80633eb6b8cf116100cd5780633eb6b8cf146101c55780633f4ba83a146101e45780634f1ef286146101f857806352d1902d1461020b575f80fd5b806319ab453c146100fe57806328f713cc1461011f5780633659cfe6146101875780633ab76e9f146101a6575b5f80fd5b348015610109575f80fd5b5061011d610118366004610f4b565b610330565b005b34801561012a575f80fd5b5061016a610139366004610f82565b67ffffffffffffffff919091165f90815260fb6020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610192575f80fd5b5061011d6101a1366004610f4b565b610442565b3480156101b1575f80fd5b5060975461016a906001600160a01b031681565b3480156101d0575f80fd5b5061016a6101df366004610fb9565b61051f565b3480156101ef575f80fd5b5061011d610535565b61011d610206366004611006565b6105b4565b348015610216575f80fd5b5061021f61067f565b60405190815260200161017e565b348015610238575f80fd5b5061024d60c954610100900460ff1660021490565b604051901515815260200161017e565b348015610268575f80fd5b5061011d610730565b34801561027c575f80fd5b5061011d610741565b348015610290575f80fd5b5061011d6107b8565b3480156102a4575f80fd5b506033546001600160a01b031661016a565b3480156102c1575f80fd5b5061016a6102d03660046110c4565b610829565b3480156102e0575f80fd5b5061011d6102ef3660046110ee565b610835565b3480156102ff575f80fd5b506065546001600160a01b031661016a565b34801561031c575f80fd5b5061011d61032b366004610f4b565b610913565b5f54610100900460ff161580801561034e57505f54600160ff909116105b806103675750303b15801561036757505f5460ff166001145b6103cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156103f0575f805461ff0019166101001790555b6103f982610984565b801561043e575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b037f000000000000000000000000016700100000000000000000000000000001000216300361048a5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670010000000000000000000000000000100026001600160a01b03166104d25f80516020611265833981519152546001600160a01b031690565b6001600160a01b0316146104f85760405162461bcd60e51b81526004016103c690611177565b610501816109b4565b604080515f8082526020820190925261051c918391906109bc565b50565b5f61052b848484610b2b565b90505b9392505050565b61054960c954610100900460ff1660021490565b6105665760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a16105b233610c19565b565b6001600160a01b037f00000000000000000000000001670010000000000000000000000000000100021630036105fc5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670010000000000000000000000000000100026001600160a01b03166106445f80516020611265833981519152546001600160a01b031690565b6001600160a01b03161461066a5760405162461bcd60e51b81526004016103c690611177565b610673826109b4565b61043e828260016109bc565b5f306001600160a01b037f0000000000000000000000000167001000000000000000000000000000010002161461071e5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016103c6565b505f8051602061126583398151915290565b610738610c31565b6105b25f610c8b565b60655433906001600160a01b031681146107af5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103c6565b61051c81610c8b565b6107cc60c954610100900460ff1660021490565b156107ea5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016105a1565b5f61052e468484610b2b565b61083d610c31565b67ffffffffffffffff83165f90815260fb602090815260408083208584529091529020546001600160a01b0390811690821681900361088f576040516327b026fb60e21b815260040160405180910390fd5b67ffffffffffffffff84165f81815260fb6020908152604080832087845282529182902080546001600160a01b0319166001600160a01b038781169182179092558351908152908516918101919091528592917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b61091b610c31565b606580546001600160a01b0383166001600160a01b0319909116811790915561094c6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6109a26001600160a01b0382161561099c5781610c8b565b33610c8b565b5060c9805461ff001916610100179055565b61051c610c31565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109f4576109ef83610ca4565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4e575060408051601f3d908101601f19168201909252610a4b918101906111c3565b60015b610ab15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016103c6565b5f805160206112658339815191528114610b1f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016103c6565b506109ef838383610d3f565b6097545f906001600160a01b0316610b5657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015610bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd191906111da565b905081158015610be857506001600160a01b038116155b1561052e57604051632b0d65db60e01b815267ffffffffffffffff85166004820152602481018490526044016103c6565b60405162580a9560e71b815260040160405180910390fd5b6033546001600160a01b031633146105b25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c6565b606580546001600160a01b031916905561051c81610d69565b6001600160a01b0381163b610d115760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016103c6565b5f8051602061126583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610d4883610dba565b5f82511180610d545750805b156109ef57610d638383610df9565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610dc381610ca4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061052e83836040518060600160405280602781526020016112856027913960605f80856001600160a01b031685604051610e359190611217565b5f60405180830381855af49150503d805f8114610e6d576040519150601f19603f3d011682016040523d82523d5f602084013e610e72565b606091505b5091509150610e8386838387610e8d565b9695505050505050565b60608315610efb5782515f03610ef4576001600160a01b0385163b610ef45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c6565b5081610f05565b610f058383610f0d565b949350505050565b815115610f1d5781518083602001fd5b8060405162461bcd60e51b81526004016103c69190611232565b6001600160a01b038116811461051c575f80fd5b5f60208284031215610f5b575f80fd5b813561052e81610f37565b803567ffffffffffffffff81168114610f7d575f80fd5b919050565b5f8060408385031215610f93575f80fd5b610f9c83610f66565b946020939093013593505050565b80358015158114610f7d575f80fd5b5f805f60608486031215610fcb575f80fd5b610fd484610f66565b925060208401359150610fe960408501610faa565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611017575f80fd5b823561102281610f37565b9150602083013567ffffffffffffffff8082111561103e575f80fd5b818501915085601f830112611051575f80fd5b81358181111561106357611063610ff2565b604051601f8201601f19908116603f0116810190838211818310171561108b5761108b610ff2565b816040528281528860208487010111156110a3575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156110d5575f80fd5b823591506110e560208401610faa565b90509250929050565b5f805f60608486031215611100575f80fd5b61110984610f66565b925060208401359150604084013561112081610f37565b809150509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f602082840312156111d3575f80fd5b5051919050565b5f602082840312156111ea575f80fd5b815161052e81610f37565b5f5b8381101561120f5781810151838201526020016111f7565b50505f910152565b5f82516112288184602087016111f5565b9190910192915050565b602081525f82518060208401526112508160408501602087016111f5565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220cc98ce1f870c6bb16d1d5f2f7fbcc9dcf424754d8f8ecafbdf9491cb4cfd521764736f6c63430008180033", + "balance": "0x0" + }, + "0x1670010000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000ab707cb80e7de7c75d815b1a653433f3eec44c74", + "0xd8268ac552cc4e7bd87f3f4b36d055f134549289cc2d68715bd581a06ffb2631": "0x0000000000000000000000001670010000000000000000000000000000010001", + "0xc64d73fae391b0ac595df47d373c227e7f86156e3d98ea2db53384d097ed1368": "0x0000000000000000000000001670010000000000000000000000000000000001", + "0x30e0422248fc90822e500074357003173b9f5edac82e6cc3679f5f9b5ae0843a": "0x0000000000000000000000001670010000000000000000000000000000000005", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167001000000000000000000000000000010002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167001000000000000000000000000000010099": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000002710000", + "0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x215be5d23550ceb1beff54fb579a765903ba2ccc85b6f79bcf9bda4e8cb86034": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6d1035fce6503985ab075a4ff3f7ce2e57cd5a9c5e6a0589dccacfea7bcb0af4": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2a95ee547cef07a2fff0a68144824a0d9ded35ed87da118a53e1cda4aca8b944": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x7fcecd2a720442e9bc0cf1a8a6976f9fbddf6b996dc0d78af7e94dadf360d579": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x18bbf5fcf8fe870ecff419c4677497c08b2e6a5431bb94541d06c9da3f308e55": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6e3431b4e42570cb9e3d926eb26f9e54de2df536ae0741ae16350d17a6c16ddc": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xdb302bf24b1ad5f23949da8e6b05747dc699499a995361a7bf40ec7204696d6f": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xa1d47ef1a6916dfbe65888f77739da164feb3a9a6afc95ee57e8b3e85ea5e955": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x454340b1295f9ff1c0fb9192166d0215d33f84dc5f2dc3f3e5732a4b557186bf": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6a3bb1dada7c82a99b4a02d16da3fda07cb31d8887b9b99ec829ab67fd7a817e": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2fe2844d12634f5dce1e2be5be96b2ea1c573f8f25171997e2f4bd943dd32f92": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x3836a017087644fbf6925ae1aca14201ce898a35434d9dea9ebd03cea44e049a": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1c7a29f5a750951acb14fdf82a876085914eb17f15a162b054a3d2f8c92e2451": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x271927a243b678b7a071f19b4051ef93b16e397066e3fdef5bba26527e34a1a1": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x4663d660b5d810c9ab2f6dc64af7ff84ebae28a72342391622649a7fe87c93d4": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x352c3281a58937f04ef7cc7b88f3456b6ffd47f52a321c253dc083fb53a3a114": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6d5faa5f4e671e6fe47b0eab51c62f8cebf354e21e8fdccf8cdfc0293dd341a3": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x673de83553dc3a2c0f59aa7193de392a4530feb73b9d6cd4fcef68802b8195c1": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x8b6a7148182c39c1ca0b052292befa83d09344947c23e47b300314fa8c2b8f7d": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xed4a23b4a030ee0d64ef69b276dee81d493e5efca01c0fa514e0c38f882af152": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x45124dfaa1716b8d229f646ff926377e17b887c2b2eab6a87ab0348ee1689eac": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x40f9c2870c16301e8614e56453fc5b838c4a153eb0b18c4c050efbf4f786518a": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xbd55c9294669a294e0c8fd07e2c07738e95be0123b62b752d782fe317f25ca97": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x52c0eeeba21034a69ad7cfa70f75c6fd127acd4084a4da80f30cc7540bdf990b": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x843a9befd317bdcee99c42a3adf6d00b789224beda1485c7f6e7bf327755328e": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xea09b20615ffad342fb450741e59ea6ba180fa93b8701b31fa639ef9ff50d2b0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x39cd5e5ec54ce41a5f5b2c13ce7133998dfef654caacfb44d5c517700c217d36": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xd46a4409ebc9fc47afedecdadc89dbc0d6f46be6bdb49fd822d5143daedc83f0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x5735d6fad3ea4f2328a1557ff1be7570df3d4c2630b448c1b7fe2781d018beb0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x509c640066f1872118ec768fcb985c7bf4476690788ac7e112ab072ca82ab219": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xf9982658df503b792c55f860aefa42588712c9069523324d4b9ce4d9a10e2e9c": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x87d11160035f8424b7163a397fc780b278af3de5a6caa2cb71bb2b46825ce159": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1dde801acf032acf4b3151b5edb82e0e4d872a54d9efbf3809d75efcbfa2bf8f": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x01aad34cdf9f8f5fca811e2fab1411b08778be71f547894fa0d9fafa5c1f60b2": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x65cee0cf3d643c3f3402a40ddebed72cec3dd6bac66974bff967dc0ef9e2faed": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xaf6cadccd3f046eeb282ec0b08e44adbe45784a23f41d76b096ccb8e7f238e2b": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2589e1958c4e4f4a5f777b0b92a3170cc21771a8d3580331a71232f8624f7628": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1f27de92fedf410197c8a09d0f2f03372d92b75c9889a6a61cf491395877fbcf": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c8063395093511161006e578063395093511461011f57806370a082311461013257806395d89b411461015a578063a457c2d714610162578063a9059cbb14610175578063dd62ed3e14610188575f80fd5b806306fdde03146100aa578063095ea7b3146100c857806318160ddd146100eb57806323b872dd146100fd578063313ce56714610110575b5f80fd5b6100b261019b565b6040516100bf919061068a565b60405180910390f35b6100db6100d63660046106f1565b61022b565b60405190151581526020016100bf565b6002545b6040519081526020016100bf565b6100db61010b366004610719565b610244565b604051601281526020016100bf565b6100db61012d3660046106f1565b610267565b6100ef610140366004610752565b6001600160a01b03165f9081526020819052604090205490565b6100b2610288565b6100db6101703660046106f1565b610297565b6100db6101833660046106f1565b610316565b6100ef610196366004610772565b610323565b6060600380546101aa906107a3565b80601f01602080910402602001604051908101604052809291908181526020018280546101d6906107a3565b80156102215780601f106101f857610100808354040283529160200191610221565b820191905f5260205f20905b81548152906001019060200180831161020457829003601f168201915b5050505050905090565b5f3361023881858561034d565b60019150505b92915050565b5f33610251858285610470565b61025c8585856104e8565b506001949350505050565b5f336102388185856102798383610323565b61028391906107db565b61034d565b6060600480546101aa906107a3565b5f33816102a48286610323565b9050838110156103095760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b61025c828686840361034d565b5f336102388185856104e8565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103af5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610300565b6001600160a01b0382166104105760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610300565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f61047b8484610323565b90505f1981146104e257818110156104d55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610300565b6104e2848484840361034d565b50505050565b6001600160a01b03831661054c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610300565b6001600160a01b0382166105ae5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610300565b6001600160a01b0383165f90815260208190526040902054818110156106255760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610300565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104e2565b5f602080835283518060208501525f5b818110156106b65785810183015185820160400152820161069a565b505f604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146106ec575f80fd5b919050565b5f8060408385031215610702575f80fd5b61070b836106d6565b946020939093013593505050565b5f805f6060848603121561072b575f80fd5b610734846106d6565b9250610742602085016106d6565b9150604084013590509250925092565b5f60208284031215610762575f80fd5b61076b826106d6565b9392505050565b5f8060408385031215610783575f80fd5b61078c836106d6565b915061079a602084016106d6565b90509250929050565b600181811c908216806107b757607f821691505b6020821081036107d557634e487b7160e01b5f52602260045260245ffd5b50919050565b8082018082111561023e57634e487b7160e01b5f52601160045260245ffdfea26469706673582212207d26eda1fafdb8ea119f090edcd559b9fd9deb2d3bf8c80b33e02459e52c64ef64736f6c63430008180033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/internal_l2b.json b/crates/primitives/res/genesis/taiko/internal_l2b.json new file mode 100644 index 000000000000..ec5327da4f8a --- /dev/null +++ b/crates/primitives/res/genesis/taiko/internal_l2b.json @@ -0,0 +1,339 @@ +{ + "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { + "balance": "0x3782dace9d90000000" + }, + "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { + "balance": "0x3782dace9d90000000" + }, + "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC": { + "balance": "0x3782dace9d90000000" + }, + "0x90F79bf6EB2c4f870365E785982E1f101E93b906": { + "balance": "0x3782dace9d90000000" + }, + "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65": { + "balance": "0x3782dace9d90000000" + }, + "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": { + "balance": "0x3782dace9d90000000" + }, + "0x976EA74026E726554dB657fA54763abd0C3a0aa9": { + "balance": "0x3782dace9d90000000" + }, + "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955": { + "balance": "0x3782dace9d90000000" + }, + "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { + "balance": "0x3782dace9d90000000" + }, + "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720": { + "balance": "0x3782dace9d90000000" + }, + "0xBcd4042DE499D14e55001CcbB24a551F3b954096": { + "balance": "0x3782dace9d90000000" + }, + "0x71bE63f3384f5fb98995898A86B02Fb2426c5788": { + "balance": "0x3782dace9d90000000" + }, + "0xFABB0ac9d68B0B445fB7357272Ff202C5651694a": { + "balance": "0x3782dace9d90000000" + }, + "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec": { + "balance": "0x3782dace9d90000000" + }, + "0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097": { + "balance": "0x3782dace9d90000000" + }, + "0xcd3B766CCDd6AE721141F452C550Ca635964ce71": { + "balance": "0x3782dace9d90000000" + }, + "0x2546BcD3c84621e976D8185a91A922aE77ECEc30": { + "balance": "0x3782dace9d90000000" + }, + "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E": { + "balance": "0x3782dace9d90000000" + }, + "0xdD2FD4581271e230360230F9337D5c0430Bf44C0": { + "balance": "0x3782dace9d90000000" + }, + "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199": { + "balance": "0x3782dace9d90000000" + }, + "0x7D86687F980A56b832e9378952B738b614A99dc6": { + "balance": "0x3782dace9d90000000" + }, + "0x11e8F3eA3C6FcF12EcfF2722d75CEFC539c51a1C": { + "balance": "0x3782dace9d90000000" + }, + "0x9eAF5590f2c84912A08de97FA28d0529361Deb9E": { + "balance": "0x3782dace9d90000000" + }, + "0x1003ff39d25F2Ab16dBCc18EcE05a9B6154f65F4": { + "balance": "0x3782dace9d90000000" + }, + "0x4779d18931B35540F84b0cd0e9633855B84df7b8": { + "balance": "0x3782dace9d90000000" + }, + "0x1c87Bb9234aeC6aDc580EaE6C8B59558A4502220": { + "balance": "0x3782dace9d90000000" + }, + "0x0d803cdeEe5990f22C2a8DF10A695D2312dA26CC": { + "balance": "0x3782dace9d90000000" + }, + "0xAb707cb80e7de7C75d815B1A653433F3EEc44c74": { + "balance": "0x3782dace9d90000000" + }, + "0xe8B1ff302A740fD2C6e76B620d45508dAEc2DDFf": { + "balance": "0x3782dace9d90000000" + }, + "0xa0EC9eE47802CeB56eb58ce80F3E41630B771b04": { + "balance": "0x3782dace9d90000000" + }, + "0x042a63149117602129B6922ecFe3111168C2C323": { + "balance": "0x3782dace9d90000000" + }, + "0xA1196426b41627ae75Ea7f7409E074BE97367da2": { + "balance": "0x3782dace9d90000000" + }, + "0xE74cEf90b6CF1a77FEfAd731713e6f53e575C183": { + "balance": "0x3782dace9d90000000" + }, + "0x7Df8Efa6d6F1CB5C4f36315e0AcB82b02Ae8BA40": { + "balance": "0x3782dace9d90000000" + }, + "0x9E126C57330FA71556628e0aabd6B6B6783d99fA": { + "balance": "0x3782dace9d90000000" + }, + "0xcBDc0F9a4C38f1e010bD3B6e43598A55D1868c23": { + "balance": "0x3782dace9d90000000" + }, + "0xBc5BdceE96b1BC47822C74e6f64186fbA7d686be": { + "balance": "0x3782dace9d90000000" + }, + "0x0536896a5e38BbD59F3F369FF3682677965aBD19": { + "balance": "0x3782dace9d90000000" + }, + "0xFE0f143FcAD5B561b1eD2AC960278A2F23559Ef9": { + "balance": "0x3782dace9d90000000" + }, + "0x98D08079928FcCB30598c6C6382ABfd7dbFaA1cD": { + "balance": "0x3782dace9d90000000" + }, + "0x0167002000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x6080604052600436106100fa575f3560e01c80635c975abb116100925780638da5cb5b116100625780638da5cb5b14610299578063a86f9d9e146102b6578063d8f4648f146102d5578063e30c3978146102f4578063f2fde38b14610311575f80fd5b80635c975abb1461022d578063715018a61461025d57806379ba5097146102715780638456cb5914610285575f80fd5b80633eb6b8cf116100cd5780633eb6b8cf146101c55780633f4ba83a146101e45780634f1ef286146101f857806352d1902d1461020b575f80fd5b806319ab453c146100fe57806328f713cc1461011f5780633659cfe6146101875780633ab76e9f146101a6575b5f80fd5b348015610109575f80fd5b5061011d610118366004610f4b565b610330565b005b34801561012a575f80fd5b5061016a610139366004610f82565b67ffffffffffffffff919091165f90815260fb6020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610192575f80fd5b5061011d6101a1366004610f4b565b610442565b3480156101b1575f80fd5b5060975461016a906001600160a01b031681565b3480156101d0575f80fd5b5061016a6101df366004610fb9565b61051f565b3480156101ef575f80fd5b5061011d610535565b61011d610206366004611006565b6105b4565b348015610216575f80fd5b5061021f61067f565b60405190815260200161017e565b348015610238575f80fd5b5061024d60c954610100900460ff1660021490565b604051901515815260200161017e565b348015610268575f80fd5b5061011d610730565b34801561027c575f80fd5b5061011d610741565b348015610290575f80fd5b5061011d6107b8565b3480156102a4575f80fd5b506033546001600160a01b031661016a565b3480156102c1575f80fd5b5061016a6102d03660046110c4565b610829565b3480156102e0575f80fd5b5061011d6102ef3660046110ee565b610835565b3480156102ff575f80fd5b506065546001600160a01b031661016a565b34801561031c575f80fd5b5061011d61032b366004610f4b565b610913565b5f54610100900460ff161580801561034e57505f54600160ff909116105b806103675750303b15801561036757505f5460ff166001145b6103cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156103f0575f805461ff0019166101001790555b6103f982610984565b801561043e575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000616300361048a5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670020000000000000000000000000000000066001600160a01b03166104d25f80516020611265833981519152546001600160a01b031690565b6001600160a01b0316146104f85760405162461bcd60e51b81526004016103c690611177565b610501816109b4565b604080515f8082526020820190925261051c918391906109bc565b50565b5f61052b848484610b2b565b90505b9392505050565b61054960c954610100900460ff1660021490565b6105665760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a16105b233610c19565b565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000000061630036105fc5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670020000000000000000000000000000000066001600160a01b03166106445f80516020611265833981519152546001600160a01b031690565b6001600160a01b03161461066a5760405162461bcd60e51b81526004016103c690611177565b610673826109b4565b61043e828260016109bc565b5f306001600160a01b037f0000000000000000000000000167002000000000000000000000000000000006161461071e5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016103c6565b505f8051602061126583398151915290565b610738610c31565b6105b25f610c8b565b60655433906001600160a01b031681146107af5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103c6565b61051c81610c8b565b6107cc60c954610100900460ff1660021490565b156107ea5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016105a1565b5f61052e468484610b2b565b61083d610c31565b67ffffffffffffffff83165f90815260fb602090815260408083208584529091529020546001600160a01b0390811690821681900361088f576040516327b026fb60e21b815260040160405180910390fd5b67ffffffffffffffff84165f81815260fb6020908152604080832087845282529182902080546001600160a01b0319166001600160a01b038781169182179092558351908152908516918101919091528592917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b61091b610c31565b606580546001600160a01b0383166001600160a01b0319909116811790915561094c6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6109a26001600160a01b0382161561099c5781610c8b565b33610c8b565b5060c9805461ff001916610100179055565b61051c610c31565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109f4576109ef83610ca4565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4e575060408051601f3d908101601f19168201909252610a4b918101906111c3565b60015b610ab15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016103c6565b5f805160206112658339815191528114610b1f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016103c6565b506109ef838383610d3f565b6097545f906001600160a01b0316610b5657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015610bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd191906111da565b905081158015610be857506001600160a01b038116155b1561052e57604051632b0d65db60e01b815267ffffffffffffffff85166004820152602481018490526044016103c6565b60405162580a9560e71b815260040160405180910390fd5b6033546001600160a01b031633146105b25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c6565b606580546001600160a01b031916905561051c81610d69565b6001600160a01b0381163b610d115760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016103c6565b5f8051602061126583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610d4883610dba565b5f82511180610d545750805b156109ef57610d638383610df9565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610dc381610ca4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061052e83836040518060600160405280602781526020016112856027913960605f80856001600160a01b031685604051610e359190611217565b5f60405180830381855af49150503d805f8114610e6d576040519150601f19603f3d011682016040523d82523d5f602084013e610e72565b606091505b5091509150610e8386838387610e8d565b9695505050505050565b60608315610efb5782515f03610ef4576001600160a01b0385163b610ef45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c6565b5081610f05565b610f058383610f0d565b949350505050565b815115610f1d5781518083602001fd5b8060405162461bcd60e51b81526004016103c69190611232565b6001600160a01b038116811461051c575f80fd5b5f60208284031215610f5b575f80fd5b813561052e81610f37565b803567ffffffffffffffff81168114610f7d575f80fd5b919050565b5f8060408385031215610f93575f80fd5b610f9c83610f66565b946020939093013593505050565b80358015158114610f7d575f80fd5b5f805f60608486031215610fcb575f80fd5b610fd484610f66565b925060208401359150610fe960408501610faa565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611017575f80fd5b823561102281610f37565b9150602083013567ffffffffffffffff8082111561103e575f80fd5b818501915085601f830112611051575f80fd5b81358181111561106357611063610ff2565b604051601f8201601f19908116603f0116810190838211818310171561108b5761108b610ff2565b816040528281528860208487010111156110a3575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156110d5575f80fd5b823591506110e560208401610faa565b90509250929050565b5f805f60608486031215611100575f80fd5b61110984610f66565b925060208401359150604084013561112081610f37565b809150509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f602082840312156111d3575f80fd5b5051919050565b5f602082840312156111ea575f80fd5b815161052e81610f37565b5f5b8381101561120f5781810151838201526020016111f7565b50505f910152565b5f82516112288184602087016111f5565b9190910192915050565b602081525f82518060208401526112508160408501602087016111f5565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220cc98ce1f870c6bb16d1d5f2f7fbcc9dcf424754d8f8ecafbdf9491cb4cfd521764736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x1f6e8365b88965465679d131196095b3fe883fdeef8915a26d29cc80b5f57057": "0x0000000000000000000000001670020000000000000000000000000000000001", + "0x0a87a91d9f9742da2223c4d7ea323675defd4b6d878704dfb528468917dd7a9f": "0x0000000000000000000000001670020000000000000000000000000000000002", + "0x5c77c4c9bda7d7357953d00d5467a266bbf8a8e5374fe1eff42e9d30c6943054": "0x0000000000000000000000001670020000000000000000000000000000000003", + "0x63e5ffdf4c63931cdc18ccbe3f3ebca577ee9db6108b67086c0d098399f355c2": "0x0000000000000000000000001670020000000000000000000000000000000004", + "0x3bd77107e0102c8f1a54b812ae852bf834e4d7d2e163cd6ad85e7fb146b8946b": "0x0000000000000000000000001670020000000000000000000000000000000005", + "0xeb65558d30a30fdaf6ae0b122d4f7aa1aed26bbd4b5edca1d270c0296c859470": "0x0000000000000000000000000167002000000000000000000000000000010096", + "0xcd245fd144e9bd59b0e5c99ce9e407ab75ef654d032e6d2b4224a9dd9bfba6be": "0x0000000000000000000000000167002000000000000000000000000000010097", + "0xe4837dd39c893816c7a5c63deb4bba91722c5f6088e3c198b8e24fb37a9591a3": "0x0000000000000000000000000167002000000000000000000000000000010098", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000006" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x6080604052600436106101e9575f3560e01c8063715018a611610108578063b916a0be1161009d578063d8beb5c31161006d578063d8beb5c314610611578063e30c397814610640578063eefbf17e1461065d578063f09a401614610694578063f2fde38b146106b3575f80fd5b8063b916a0be1461056b578063d0496d6a1461058a578063d1aaa5df146105d2578063d6ba38b2146105f2575f80fd5b80638da5cb5b116100d85780638da5cb5b146104d25780638e3881a9146104ef5780639939a2dc1461052d578063a86f9d9e1461054c575f80fd5b8063715018a61461046d5780637844845b1461048157806379ba5097146104aa5780638456cb59146104be575f80fd5b806348548f251161017e5780635c975abb1161014e5780635c975abb1461039f5780636be4eb55146103bf5780636c334e2e146103de5780636edbad04146103ff575f80fd5b806348548f251461033a5780634f1ef2861461035957806352d1902d1461036c57806357209f4814610380575f80fd5b80633ab76e9f116101b95780633ab76e9f146102955780633c6cf473146102cc5780633eb6b8cf146103075780633f4ba83a14610326575f80fd5b806316b205c1146101f4578063302ac39914610215578063324c058e146102475780633659cfe614610276575f80fd5b366101f057005b5f80fd5b3480156101ff575f80fd5b5061021361020e366004612db9565b6106d2565b005b348015610220575f80fd5b5061023461022f366004613075565b610c03565b6040519081526020015b60405180910390f35b348015610252575f80fd5b50610266610261366004612db9565b610c32565b604051901515815260200161023e565b348015610281575f80fd5b506102136102903660046130a6565b610ca7565b3480156102a0575f80fd5b506097546102b4906001600160a01b031681565b6040516001600160a01b03909116815260200161023e565b3480156102d7575f80fd5b506102fa6102e63660046130c1565b60fc6020525f908152604090205460ff1681565b60405161023e91906130ec565b348015610312575f80fd5b506102b461032136600461311f565b610d8d565b348015610331575f80fd5b50610213610d99565b348015610345575f80fd5b5061021361035436600461315c565b610e18565b6102136103673660046131cf565b610f4f565b348015610377575f80fd5b5061023461101e565b34801561038b575f80fd5b5061021361039a36600461321b565b6110d0565b3480156103aa575f80fd5b5061026660c954610100900460ff1660021490565b3480156103ca575f80fd5b506102666103d9366004612db9565b611229565b6103f16103ec366004613252565b61128a565b60405161023e9291906133f4565b34801561040a575f80fd5b506104466104193660046130c1565b6101006020525f90815260409020546001600160401b03811690600160401b90046001600160a01b031682565b604080516001600160401b0390931683526001600160a01b0390911660208301520161023e565b348015610478575f80fd5b50610213611591565b34801561048c575f80fd5b506104956115a2565b6040805192835260208301919091520161023e565b3480156104b5575f80fd5b50610213611634565b3480156104c9575f80fd5b506102136116ab565b3480156104dd575f80fd5b506033546001600160a01b03166102b4565b3480156104fa575f80fd5b5061050e61050936600461340c565b61171c565b6040805192151583526001600160a01b0390911660208301520161023e565b348015610538575f80fd5b50610266610547366004613252565b611748565b348015610557575f80fd5b506102b4610566366004613425565b611816565b348015610576575f80fd5b50610213610585366004613448565b611822565b348015610595575f80fd5b5061059e6119cf565b60408051825181526020808401516001600160a01b031690820152918101516001600160401b03169082015260600161023e565b3480156105dd575f80fd5b506102346105ec3660046130c1565b60031890565b3480156105fd575f80fd5b5061021361060c366004612db9565b611a23565b34801561061c575f80fd5b5061026661062b3660046130a6565b60ff60208190525f9182526040909120541681565b34801561064b575f80fd5b506065546001600160a01b03166102b4565b348015610668575f80fd5b5060fb5461067c906001600160801b031681565b6040516001600160801b03909116815260200161023e565b34801561069f575f80fd5b506102136106ae36600461348b565b611e10565b3480156106be575f80fd5b506102136106cd3660046130a6565b611f1e565b60026106dc611f8f565b60ff16036106fd5760405163dfc60d8560e01b815260040160405180910390fd5b6107076002611fc8565b61071b60c954610100900460ff1660021490565b156107395760405163bae6e2a960e01b815260040160405180910390fd5b610749608084016060850161340c565b46816001600160401b03161461077257604051631c6c777560e31b815260040160405180910390fd5b5f61077f61022f866134b7565b90505f8082815260fc602052604090205460ff1660048111156107a4576107a46130d8565b146107c257604051630cfafbf960e01b815260040160405180910390fd5b5f6107de6d7369676e616c5f7365727669636560901b5f611816565b5f83815261010060205260408120549192506001600160401b039091169081151590806108096115a2565b91509150826108e05761082e858761082760608e0160408f0161340c565b8c8c61200a565b61084b57604051635ea5ecc760e01b815260040160405180910390fd5b42935081156108e0576040518060400160405280856001600160401b031681526020018b61014001355f146108805733610890565b61089060c08d0160a08e016130a6565b6001600160a01b039081169091525f88815261010060209081526040909120835181549490920151909216600160401b026001600160e01b03199093166001600160401b03909116179190911790555b811580159061090d57505f8681526101006020526040902054600160401b90046001600160a01b03163314155b1561091757908101905b61092a6001600160401b038516836134d6565b4210610b90576101408a0135158015610964575061094e60c08b0160a08c016130a6565b6001600160a01b0316336001600160a01b031614155b15610982576040516372b6e1c360e11b815260040160405180910390fd5b5f8681526101006020526040812080546001600160e01b0319169055806109af60e08d0160c08e016130a6565b6001600160a01b031614806109db5750306109d060e08d0160c08e016130a6565b6001600160a01b0316145b80610a0657506001600160a01b0386166109fb60e08d0160c08e016130a6565b6001600160a01b0316145b80610a3c575060ff5f610a1f60e08e0160c08f016130a6565b6001600160a01b0316815260208101919091526040015f205460ff165b15610a5857506101008a0135610a538760026120c7565b610abd565b5f610a6960c08d0160a08e016130a6565b6001600160a01b0316336001600160a01b031614610a8c578b6101400135610a8e565b5a5b9050610a9b8c898361220b565b15610ab057610aab8860026120c7565b610abb565b610abb8860016120c7565b505b5f80610ad06101008e0160e08f016130a6565b6001600160a01b031614610af457610aef6101008d0160e08e016130a6565b610b04565b610b0460c08d0160a08e016130a6565b90506001600160a01b0381163303610b3d57610b38610b28836101208f01356134d6565b6001600160a01b03831690612362565b610b5f565b610b4c336101208e0135612362565b610b5f6001600160a01b03821683612362565b60405188907fe7d1e1f435233f7a187624ac11afaf32ee0da368cef8a5625be394412f619254905f90a25050610bed565b82610bd457857f3a7420670ebb84feae884388421d5f63bb1f9e073c54c8103e9e2ca7a98346e58b5f604051610bc79291906136a0565b60405180910390a2610bed565b60405163714f083160e11b815260040160405180910390fd5b50505050505050610bfe6001611fc8565b505050565b5f81604051602001610c1591906136c3565b604051602081830303815290604052805190602001209050919050565b5f46610c44606086016040870161340c565b6001600160401b031614610c5957505f610ca0565b610c9d610c776d7369676e616c5f7365727669636560901b5f611816565b610c866105ec61022f886134b7565b610c96608088016060890161340c565b868661200a565b90505b9392505050565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000000001163003610cf85760405162461bcd60e51b8152600401610cef906136f9565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000000016001600160a01b0316610d405f8051602061397f833981519152546001600160a01b031690565b6001600160a01b031614610d665760405162461bcd60e51b8152600401610cef90613745565b610d6f8161236d565b604080515f80825260208201909252610d8a91839190612375565b50565b5f610c9d8484846124df565b610dad60c954610100900460ff1660021490565b610dca5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610e16336125cb565b565b6e6272696467655f7761746368646f6760881b610e3d6033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015610e7a5750610e64816001611816565b6001600160a01b0316336001600160a01b031614155b15610e9857604051630d85cccf60e11b815260040160405180910390fd5b5f82610ea45742610ead565b6001600160401b035b90505f5b84811015610f47575f868683818110610ecc57610ecc613791565b602090810292909201355f8181526101008452604090819020805467ffffffffffffffff19166001600160401b0389161790558051828152891515948101949094529093507f3d7eb9ac1cd3da1c44f39d566b6364f64e5a71bfc4dc99effcbd176c1cafdf1c9201905060405180910390a150600101610eb1565b505050505050565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000000001163003610f975760405162461bcd60e51b8152600401610cef906136f9565b7f00000000000000000000000001670020000000000000000000000000000000016001600160a01b0316610fdf5f8051602061397f833981519152546001600160a01b031690565b6001600160a01b0316146110055760405162461bcd60e51b8152600401610cef90613745565b61100e8261236d565b61101a82826001612375565b5050565b5f306001600160a01b037f000000000000000000000000016700200000000000000000000000000000000116146110bd5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610cef565b505f8051602061397f8339815191525b90565b6e6272696467655f7761746368646f6760881b6110f56033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015611132575061111c816001611816565b6001600160a01b0316336001600160a01b031614155b1561115057604051630d85cccf60e11b815260040160405180910390fd5b600261115a611f8f565b60ff160361117b5760405163dfc60d8560e01b815260040160405180910390fd5b6111856002611fc8565b6001600160a01b0383165f90815260ff602081905260409091205483151591161515036111c5576040516319d893ad60e21b815260040160405180910390fd5b6001600160a01b0383165f81815260ff6020908152604091829020805460ff191686151590811790915591519182527f7113ce15c395851033544a97557341cdc71886964b54ff108a685d359ed4cdf8910160405180910390a2610bfe6001611fc8565b5f4661123b608086016060870161340c565b6001600160401b03161461125057505f610ca0565b610c9d61126e6d7369676e616c5f7365727669636560901b5f611816565b61127a61022f876134b7565b610c96606088016040890161340c565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820181905261018082015260026112fa611f8f565b60ff160361131b5760405163dfc60d8560e01b815260040160405180910390fd5b6113256002611fc8565b61133960c954610100900460ff1660021490565b156113575760405163bae6e2a960e01b815260040160405180910390fd5b5f61136860a08501608086016130a6565b6001600160a01b0316148061139457505f61138960c0850160a086016130a6565b6001600160a01b0316145b156113b257604051633c4f94dd60e11b815260040160405180910390fd5b5f6113c6610509608086016060870161340c565b509050806113e757604051631c6c777560e31b815260040160405180910390fd5b466113f8608086016060870161340c565b6001600160401b03160361141f57604051631c6c777560e31b815260040160405180910390fd5b5f6114346101208601356101008701356134d6565b905034811461145657604051634ac2abdf60e11b815260040160405180910390fd5b61145f856134b7565b60fb80549194506001600160801b03909116905f61147c836137a5565b82546101009290920a6001600160801b03818102199093169183160217909155168352336020840152466001600160401b031660408401526114bd83610c03565b93506114da6d7369676e616c5f7365727669636560901b5f611816565b6001600160a01b03166366ca2bc0856040518263ffffffff1660e01b815260040161150791815260200190565b6020604051808303815f875af1158015611523573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061154791906137ca565b50837f9a4c6dce9e49d66f9d79b5f213b08c30c2bcef51424e23934a80f4865e1f70398460405161157891906137e1565b60405180910390a2505061158c6001611fc8565b915091565b611599612649565b610e165f6126a3565b5f80466001036115b85750610e10916101809150565b46600214806115c75750466004145b806115d25750466005145b806115dd575046602a145b806115e9575046614268145b806115f657504662aa36a7145b156116075750610708916101809150565b617e2c461015801561161b5750617e904611155b1561162c575061012c916101809150565b505f91829150565b60655433906001600160a01b031681146116a25760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610cef565b610d8a816126a3565b6116bf60c954610100900460ff1660021490565b156116dd5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610e05565b5f80611733836562726964676560d01b6001610d8d565b6001600160a01b038116151594909350915050565b5f4661175a606084016040850161340c565b6001600160401b03161461176f57505f919050565b61178a6d7369676e616c5f7365727669636560901b5f611816565b6001600160a01b03166332676bc6306117a561022f866134b7565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa1580156117ec573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061181091906137f3565b92915050565b5f610ca04684846124df565b600261182c611f8f565b60ff160361184d5760405163dfc60d8560e01b815260040160405180910390fd5b6118576002611fc8565b61186b60c954610100900460ff1660021490565b156118895760405163bae6e2a960e01b815260040160405180910390fd5b611899608083016060840161340c565b46816001600160401b0316146118c257604051631c6c777560e31b815260040160405180910390fd5b61014083013515806118d15750815b15611917576118e660c0840160a085016130a6565b6001600160a01b0316336001600160a01b031614611917576040516372b6e1c360e11b815260040160405180910390fd5b5f61192461022f856134b7565b905060015f82815260fc602052604090205460ff16600481111561194a5761194a6130d8565b1461196857604051636e10a9f360e01b815260040160405180910390fd5b61197384825a61220b565b15611988576119838160026120c7565b611999565b8215611999576119998160036120c7565b60405181907f72d1525c4df70aedf1877ec89702311c795a01c082917308a30fb40059da2cc7905f90a2505061101a6001611fc8565b604080516060810182525f80825260208201819052918101919091526119f36126bc565b80519091501580611a05575080515f19145b156110cd57604051635ceed17360e01b815260040160405180910390fd5b6002611a2d611f8f565b60ff1603611a4e5760405163dfc60d8560e01b815260040160405180910390fd5b611a586002611fc8565b611a6c60c954610100900460ff1660021490565b15611a8a5760405163bae6e2a960e01b815260040160405180910390fd5b611a9a606084016040850161340c565b46816001600160401b031614611ac357604051631c6c777560e31b815260040160405180910390fd5b5f611ad061022f866134b7565b90505f8082815260fc602052604090205460ff166004811115611af557611af56130d8565b14611b1357604051630cfafbf960e01b815260040160405180910390fd5b5f81815261010060205260409020546001600160401b031680151580611c4b575f611b4f6d7369676e616c5f7365727669636560901b5f611816565b604051631933b5e360e11b8152306004820152602481018690529091506001600160a01b038216906332676bc690604401602060405180830381865afa158015611b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bbf91906137f3565b611bdc5760405163ab035ad560e01b815260040160405180910390fd5b60038418611bfc8282611bf560808d0160608e0161340c565b8b8b61200a565b611c195760405163f149234f60e01b815260040160405180910390fd5b50505f83815261010060205260409020805467ffffffffffffffff1916426001600160401b0381169190911790915591505b5f611c546115a2565b509050611c6a6001600160401b038416826134d6565b4210611dc0575f8481526101006020908152604080832080546001600160e01b031916905560fc825291829020805460ff19166004179055611ccc91631e37aef160e11b91611cbd918c01908c016130a6565b6001600160a01b0316906127b0565b15611d6957611ceb8430611ce660608c0160408d0161340c565b61283d565b611cfb6040890160208a016130a6565b6001600160a01b0316633c6f5de28961010001358a876040518463ffffffff1660e01b8152600401611d2e92919061380e565b5f604051808303818588803b158015611d45575f80fd5b505af1158015611d57573d5f803e3d5ffd5b5050505050611d64612908565b611d91565b611d91610100890135611d8260a08b0160808c016130a6565b6001600160a01b031690612362565b60405184907fc6fbc1fa0145a394c9c414b2ae7bd634eb50dd888938bcd75692ae427b680fa2905f90a2611e01565b81610bd457837f3a7420670ebb84feae884388421d5f63bb1f9e073c54c8103e9e2ca7a98346e5896001604051611df89291906136a0565b60405180910390a25b5050505050610bfe6001611fc8565b5f54610100900460ff1615808015611e2e57505f54600160ff909116105b80611e475750303b158015611e4757505f5460ff166001145b611eaa5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610cef565b5f805460ff191660011790558015611ecb575f805461ff0019166101001790555b611ed58383612927565b8015610bfe575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b611f26612649565b606580546001600160a01b0383166001600160a01b03199091168117909155611f576033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f46600103611fbe57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b46600103611ff657807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f8084612021866562726964676560d01b5f610d8d565b87868660405160240161203895949392919061382f565b60408051601f198184030181529181526020820180516001600160e01b031663910af6ed60e01b179052519091506001600160a01b0388169061207c908390613865565b5f60405180830381855afa9150503d805f81146120b4576040519150601f19603f3d011682016040523d82523d5f602084013e6120b9565b606091505b509098975050505050505050565b8060048111156120d9576120d96130d8565b5f83815260fc602052604090205460ff1660048111156120fb576120fb6130d8565b03612104575050565b5f82815260fc60205260409020805482919060ff1916600183600481111561212e5761212e6130d8565b0217905550817f6c51882bc2ed67617f77a1e9b9a25d2caad8448647ecb093b357a603b25756348260405161216391906130ec565b60405180910390a2600381600481111561217f5761217f6130d8565b0361101a5761219f6d7369676e616c5f7365727669636560901b5f611816565b60405163019b28af60e61b81526003841860048201526001600160a01b0391909116906366ca2bc0906024016020604051808303815f875af11580156121e7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bfe91906137ca565b5f815f0361222c576040516308c2ad5360e01b815260040160405180910390fd5b3061223d60408601602087016130a6565b6001600160a01b03160361225357612253613880565b6122778361226760408701602088016130a6565b611ce6606088016040890161340c565b6004612287610160860186613894565b9050101580156122be5750637f07c94760e01b6122a8610160860186613894565b6122b1916138d6565b6001600160e01b03191614155b80156122e757506122e76122d860e0860160c087016130a6565b6001600160a01b03163b151590565b156122f357505f61235a565b61235661230660e0860160c087016130a6565b83610100870135604061231d6101608a018a613894565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061298692505050565b5090505b610ca0612908565b61101a82825a612a0b565b610d8a612649565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156123a857610bfe83612a75565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612402575060408051601f3d908101601f191682019092526123ff918101906137ca565b60015b6124655760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610cef565b5f8051602061397f83398151915281146124d35760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610cef565b50610bfe838383612b10565b6097545f906001600160a01b031661250a57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015612560573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125849190613906565b90508115801561259b57506001600160a01b038116155b15610ca057604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610cef565b6c313934b233b2afb830bab9b2b960991b6125ee6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561262b5750612615816001611816565b6001600160a01b0316336001600160a01b031614155b1561101a57604051630d85cccf60e11b815260040160405180910390fd5b6033546001600160a01b03163314610e165760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610cef565b606580546001600160a01b0319169055610d8a81612b34565b604080516060810182525f8082526020820181905291810191909152466001036127745750604080516060810182527fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2b95c81526001600160a01b037fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2ba5c1660208201526001600160401b037fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2bb5c169181019190915290565b506040805160608101825260fd54815260fe546001600160a01b0381166020830152600160a01b90046001600160401b03169181019190915290565b5f6001600160a01b0383163b6127c757505f611810565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015612831575060408051601f3d908101601f1916820190925261282e918101906137f3565b60015b15611810579392505050565b466001036128b357827fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2b95d817fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2ba5d807fe4ece82196de19aabe639620d7f716c433d1348f96ce727c9989a982dbadc2bb5d505050565b604080516060810182528481526001600160a01b0393909316602084018190526001600160401b0392909216920182905260fd9290925560fe80546001600160e01b031916909217600160a01b909102179055565b4660010361291b57610e165f808061283d565b610e165f19808061283d565b5f54610100900460ff1661294d5760405162461bcd60e51b8152600401610cef90613921565b61295682612b85565b6001600160a01b03811661297d576040516375cabfef60e11b815260040160405180910390fd5b61101a81612bb5565b5f60605f805f8661ffff166001600160401b038111156129a8576129a8612e47565b6040519080825280601f01601f1916602001820160405280156129d2576020820181803683370190505b5090505f808751602089018b8e8ef191503d9250868311156129f2578692505b828152825f602083013e90999098509650505050505050565b6001600160a01b038316612a3257604051634c67134d60e11b815260040160405180910390fd5b5f612a4e8483856040805180602001604052805f815250612986565b50905080612a6f57604051634c67134d60e11b815260040160405180910390fd5b50505050565b6001600160a01b0381163b612ae25760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610cef565b5f8051602061397f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612b1983612c25565b5f82511180612b255750805b15610bfe57612a6f8383612c64565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b612ba36001600160a01b03821615612b9d57816126a3565b336126a3565b5060c9805461ff001916610100179055565b5f54610100900460ff16612bdb5760405162461bcd60e51b8152600401610cef90613921565b6001600160401b03461115612c035760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b612c2e81612a75565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610ca0838360405180606001604052806027815260200161399f6027913960605f80856001600160a01b031685604051612ca09190613865565b5f60405180830381855af49150503d805f8114612cd8576040519150601f19603f3d011682016040523d82523d5f602084013e612cdd565b606091505b5091509150612cee86838387612cf8565b9695505050505050565b60608315612d665782515f03612d5f576001600160a01b0385163b612d5f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cef565b5081612d70565b612d708383612d78565b949350505050565b815115612d885781518083602001fd5b8060405162461bcd60e51b8152600401610cef919061396c565b5f6101a08284031215612db3575f80fd5b50919050565b5f805f60408486031215612dcb575f80fd5b83356001600160401b0380821115612de1575f80fd5b612ded87838801612da2565b94506020860135915080821115612e02575f80fd5b818601915086601f830112612e15575f80fd5b813581811115612e23575f80fd5b876020828501011115612e34575f80fd5b6020830194508093505050509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b0381118282101715612e7e57612e7e612e47565b60405290565b80356001600160801b0381168114612e9a575f80fd5b919050565b6001600160a01b0381168114610d8a575f80fd5b8035612e9a81612e9f565b80356001600160401b0381168114612e9a575f80fd5b5f82601f830112612ee3575f80fd5b81356001600160401b0380821115612efd57612efd612e47565b604051601f8301601f19908116603f01168101908282118183101715612f2557612f25612e47565b81604052838152866020858801011115612f3d575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f6101a08284031215612f6d575f80fd5b612f75612e5b565b9050612f8082612e84565b8152612f8e60208301612eb3565b6020820152612f9f60408301612ebe565b6040820152612fb060608301612ebe565b6060820152612fc160808301612eb3565b6080820152612fd260a08301612eb3565b60a0820152612fe360c08301612eb3565b60c0820152612ff460e08301612eb3565b60e0820152610100828101359082015261012080830135908201526101408083013590820152610160808301356001600160401b0380821115613035575f80fd5b61304186838701612ed4565b8385015261018092508285013591508082111561305c575f80fd5b5061306985828601612ed4565b82840152505092915050565b5f60208284031215613085575f80fd5b81356001600160401b0381111561309a575f80fd5b612d7084828501612f5c565b5f602082840312156130b6575f80fd5b8135610ca081612e9f565b5f602082840312156130d1575f80fd5b5035919050565b634e487b7160e01b5f52602160045260245ffd5b602081016005831061310c57634e487b7160e01b5f52602160045260245ffd5b91905290565b8015158114610d8a575f80fd5b5f805f60608486031215613131575f80fd5b61313a84612ebe565b925060208401359150604084013561315181613112565b809150509250925092565b5f805f6040848603121561316e575f80fd5b83356001600160401b0380821115613184575f80fd5b818601915086601f830112613197575f80fd5b8135818111156131a5575f80fd5b8760208260051b85010111156131b9575f80fd5b6020928301955093505084013561315181613112565b5f80604083850312156131e0575f80fd5b82356131eb81612e9f565b915060208301356001600160401b03811115613205575f80fd5b61321185828601612ed4565b9150509250929050565b5f806040838503121561322c575f80fd5b823561323781612e9f565b9150602083013561324781613112565b809150509250929050565b5f60208284031215613262575f80fd5b81356001600160401b03811115613277575f80fd5b612d7084828501612da2565b5f5b8381101561329d578181015183820152602001613285565b50505f910152565b5f81518084526132bc816020860160208601613283565b601f01601f19169290920160200192915050565b80516001600160801b031682525f6101a060208301516132fb60208601826001600160a01b03169052565b50604083015161331660408601826001600160401b03169052565b50606083015161333160608601826001600160401b03169052565b50608083015161334c60808601826001600160a01b03169052565b5060a083015161336760a08601826001600160a01b03169052565b5060c083015161338260c08601826001600160a01b03169052565b5060e083015161339d60e08601826001600160a01b03169052565b50610100838101519085015261012080840151908501526101408084015190850152610160808401518186018390526133d8838701826132a5565b925050506101808084015185830382870152612cee83826132a5565b828152604060208201525f610c9d60408301846132d0565b5f6020828403121561341c575f80fd5b610ca082612ebe565b5f8060408385031215613436575f80fd5b82359150602083013561324781613112565b5f8060408385031215613459575f80fd5b82356001600160401b0381111561346e575f80fd5b61347a85828601612da2565b925050602083013561324781613112565b5f806040838503121561349c575f80fd5b82356134a781612e9f565b9150602083013561324781612e9f565b5f6118103683612f5c565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611810576118106134c2565b5f808335601e198436030181126134fe575f80fd5b83016020810192503590506001600160401b0381111561351c575f80fd5b80360382131561352a575f80fd5b9250929050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f6101a06135778461356a85612e84565b6001600160801b03169052565b61358360208401612eb3565b6001600160a01b0316602085015261359d60408401612ebe565b6001600160401b031660408501526135b760608401612ebe565b6001600160401b031660608501526135d160808401612eb3565b6001600160a01b031660808501526135eb60a08401612eb3565b6001600160a01b031660a085015261360560c08401612eb3565b6001600160a01b031660c085015261361f60e08401612eb3565b6001600160a01b031660e085015261010083810135908501526101208084013590850152610140808401359085015261016061365d818501856134e9565b838388015261366f8488018284613531565b9350505050610180613683818501856134e9565b86840383880152613695848284613531565b979650505050505050565b604081525f6136b26040830185613559565b905082151560208301529392505050565b60408152600d60408201526c5441494b4f5f4d45535341474560981b6060820152608060208201525f610ca060808301846132d0565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52603260045260245ffd5b5f6001600160801b038083168181036137c0576137c06134c2565b6001019392505050565b5f602082840312156137da575f80fd5b5051919050565b602081525f610ca060208301846132d0565b5f60208284031215613803575f80fd5b8151610ca081613112565b604081525f6138206040830185613559565b90508260208301529392505050565b6001600160401b038616815260018060a01b0385166020820152836040820152608060608201525f613695608083018486613531565b5f8251613876818460208701613283565b9190910192915050565b634e487b7160e01b5f52600160045260245ffd5b5f808335601e198436030181126138a9575f80fd5b8301803591506001600160401b038211156138c2575f80fd5b60200191503681900382131561352a575f80fd5b6001600160e01b031981358181169160048510156138fe5780818660040360031b1b83161692505b505092915050565b5f60208284031215613916575f80fd5b8151610ca081612e9f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b602081525f610ca060208301846132a556fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122002e4e1af6a15e5a9ab300edee272e7da12dae8b08e4d11c6e01741b46399a4fe64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x033b25902da0379e68000000" + }, + "0x0167002000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x60806040526004361062000163575f3560e01c8063715018a611620000c2578063a86f9d9e1162000076578063a86f9d9e14620003f8578063caec3e4e146200041c578063e30c3978146200044f578063f09a4016146200046e578063f2fde38b1462000492578063fa233d0c14620004b6575f80fd5b8063715018a6146200034657806379ba5097146200035d5780637f07c94714620003745780638456cb59146200038b5780638da5cb5b14620003a25780639aa8605c14620003c1575f80fd5b80633eb6b8cf116200011a5780633eb6b8cf14620002775780633f4ba83a146200029b5780634f1ef28614620002b257806352d1902d14620002c95780635c975abb14620002e057806367090ccf1462000302575f80fd5b806301ffc9a7146200016757806306fdde0314620001b05780630ecd8be914620001dc5780633659cfe614620002195780633ab76e9f146200023f5780633c6f5de21462000260575b5f80fd5b34801562000173575f80fd5b506200019b6200018536600462002fdc565b6001600160e01b031916631e37aef160e11b1490565b60405190151581526020015b60405180910390f35b348015620001bc575f80fd5b506a195c98cc8c17dd985d5b1d60aa1b5b604051908152602001620001a7565b348015620001e8575f80fd5b5062000200620001fa3660046200301a565b620004dc565b6040516001600160a01b039091168152602001620001a7565b34801562000225575f80fd5b506200023d6200023736600462003071565b62000bb3565b005b3480156200024b575f80fd5b5060975462000200906001600160a01b031681565b6200023d620002713660046200308f565b62000ca5565b34801562000283575f80fd5b506200020062000295366004620030fb565b62000e4d565b348015620002a7575f80fd5b506200023d62000e65565b6200023d620002c336600462003258565b62000ee8565b348015620002d5575f80fd5b50620001cd62000fbf565b348015620002ec575f80fd5b506200019b60c954610100900460ff1660021490565b3480156200030e575f80fd5b506200020062000320366004620032aa565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000352575f80fd5b506200023d62001074565b34801562000369575f80fd5b506200023d62001089565b6200023d62000385366004620032d0565b62001104565b34801562000397575f80fd5b506200023d62001297565b348015620003ae575f80fd5b506033546001600160a01b031662000200565b348015620003cd575f80fd5b50620003e5620003df36600462003071565b6200130b565b604051620001a795949392919062003391565b34801562000404575f80fd5b506200020062000416366004620033ee565b62001470565b34801562000428575f80fd5b506200019b6200043a36600462003071565b61012f6020525f908152604090205460ff1681565b3480156200045b575f80fd5b506065546001600160a01b031662000200565b3480156200047a575f80fd5b506200023d6200048c36600462003414565b6200147e565b3480156200049e575f80fd5b506200023d620004b036600462003071565b62001596565b620004cd620004c736600462003433565b6200160a565b604051620001a791906200346d565b5f6002620004e962001a94565b60ff16036200050b5760405163dfc60d8560e01b815260040160405180910390fd5b62000517600262001ace565b6200052c60c954610100900460ff1660021490565b156200054b5760405163bae6e2a960e01b815260040160405180910390fd5b6200055562001b11565b6001600160a01b03821615806200058c57506001600160a01b038281165f90815261012d6020526040902054600160401b90041615155b15620005ab5760405163dc63f98760e01b815260040160405180910390fd5b6001600160a01b0382165f90815261012f602052604090205460ff1615620005e6576040516375c42fc160e01b815260040160405180910390fd5b6033546001600160a01b03166001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000638573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200065e9190620035a0565b6001600160a01b031614620006865760405163c0507c1760e01b815260040160405180910390fd5b61012e5f620006996020860186620035be565b6001600160401b031681526020019081526020015f205f846020016020810190620006c5919062003071565b6001600160a01b03908116825260208201929092526040015f2054169050801562000a50576001600160a01b038181165f90815261012d60209081526040808320815160a08101835281546001600160401b0381168252600160401b810490961693810193909352600160e01b90940460ff1690820152600183018054929391926060840191906200075790620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200078590620035dc565b8015620007d45780601f10620007aa57610100808354040283529160200191620007d4565b820191905f5260205f20905b815481529060010190602001808311620007b657829003601f168201915b50505050508152602001600282018054620007ef90620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200081d90620035dc565b80156200086c5780601f1062000842576101008083540402835291602001916200086c565b820191905f5260205f20905b8154815290600101906020018083116200084e57829003601f168201915b50505050508152505090508360400160208101906200088c919062003632565b60ff16816040015160ff16141580620008d65750620008af606085018562003650565b604051620008bf9291906200369c565b604051809103902081606001518051906020012014155b80620009135750620008ec608085018562003650565b604051620008fc9291906200369c565b604051809103902081608001518051906020012014155b156200093257604051632f9d1d7b60e11b815260040160405180910390fd5b6001600160a01b0383165f90815261012d6020526040812080546001600160e81b03191681559062000968600183018262002f7c565b62000977600283015f62002f7c565b50506001600160a01b038281165f81815261012f6020526040808220805460ff191660011790555163b8f2e0c560e01b8152928616600484015260248301529063b8f2e0c5906044015f604051808303815f87803b158015620009d8575f80fd5b505af1158015620009eb573d5f803e3d5ffd5b505060405163b8f2e0c560e01b81526001600160a01b038581166004830152600160248301528616925063b8f2e0c591506044015f604051808303815f87803b15801562000a37575f80fd5b505af115801562000a4a573d5f803e3d5ffd5b50505050505b6001600160a01b0382165f90815261012d60205260409020839062000a768282620037c0565b5082905061012e5f62000a8d6020870187620035be565b6001600160401b031681526020019081526020015f205f85602001602081019062000ab9919062003071565b6001600160a01b03166001600160a01b031681526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555082602001602081019062000b10919062003071565b6001600160a01b031662000b286020850185620035be565b6001600160401b03167f031d68e1805917560c34a5f55a7dd91bef98f911190ed02cdbb53caedae6c39d838562000b63606089018962003650565b62000b7260808b018b62003650565b62000b8460608d0160408e0162003632565b60405162000b999796959493929190620038bd565b60405180910390a362000bad600162001ace565b92915050565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000216300362000c075760405162461bcd60e51b815260040162000bfe9062003918565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000000026001600160a01b031662000c515f805160206200468b833981519152546001600160a01b031690565b6001600160a01b03161462000c7a5760405162461bcd60e51b815260040162000bfe9062003964565b62000c858162001b6d565b604080515f8082526020820190925262000ca29183919062001b77565b50565b600262000cb162001a94565b60ff160362000cd35760405163dfc60d8560e01b815260040160405180910390fd5b62000cdf600262001ace565b62000cf460c954610100900460ff1660021490565b1562000d135760405163bae6e2a960e01b815260040160405180910390fd5b62000d1d62001cee565b505f62000d2f61016084018462003650565b62000d3f916004908290620039b0565b81019062000d4e9190620039d9565b90505f808280602001905181019062000d68919062003a71565b9350505091505f62000d908387608001602081019062000d89919062003071565b8462001de5565b905062000dbe61010087013562000dae60a0890160808a0162003071565b6001600160a01b03169062001e91565b62000dd060a087016080880162003071565b6001600160a01b0316857f3dea0f5955b148debf6212261e03bd80eaf8534bee43780452d16637dcc22dd58560200151848660405162000e31939291906001600160a01b039384168152919092166020820152604081019190915260600190565b60405180910390a35050505062000e49600162001ace565b5050565b5f62000e5b84848462001e9e565b90505b9392505050565b62000e7a60c954610100900460ff1660021490565b62000e985760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000ee63362001b6d565b565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000216300362000f335760405162461bcd60e51b815260040162000bfe9062003918565b7f00000000000000000000000001670020000000000000000000000000000000026001600160a01b031662000f7d5f805160206200468b833981519152546001600160a01b031690565b6001600160a01b03161462000fa65760405162461bcd60e51b815260040162000bfe9062003964565b62000fb18262001b6d565b62000e498282600162001b77565b5f306001600160a01b037f00000000000000000000000001670020000000000000000000000000000000021614620010605760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000bfe565b505f805160206200468b8339815191525b90565b6200107e62001b11565b62000ee65f62001f91565b60655433906001600160a01b03168114620010f95760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840162000bfe565b62000ca28162001f91565b60026200111062001a94565b60ff1603620011325760405163dfc60d8560e01b815260040160405180910390fd5b6200113e600262001ace565b6200115360c954610100900460ff1660021490565b15620011725760405163bae6e2a960e01b815260040160405180910390fd5b5f808080620011848587018762003b7d565b93509350935093505f6200119762001fac565b90506001600160a01b0383161580620011b857506001600160a01b03831630145b15620011d75760405163def9481360e01b815260040160405180910390fd5b5f620011e586858562001de5565b9050620011fc6001600160a01b0385163462001e91565b836001600160a01b0316856001600160a01b0316835f01517f75a051823424fc80e92556c41cb0ad977ae1dcb09c68a9c38acab86b11a69f8985604001518a6020015186896040516200127d94939291906001600160401b039490941684526001600160a01b03928316602085015291166040830152606082015260800190565b60405180910390a450505050505062000e49600162001ace565b620012ac60c954610100900460ff1660021490565b15620012cb5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000ed3565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b84046001600160a01b031693600160e01b900460ff169290916200135590620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200138390620035dc565b8015620013d25780601f10620013a857610100808354040283529160200191620013d2565b820191905f5260205f20905b815481529060010190602001808311620013b457829003601f168201915b505050505090806002018054620013e990620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200141790620035dc565b8015620014665780601f106200143c5761010080835404028352916020019162001466565b820191905f5260205f20905b8154815290600101906020018083116200144857829003601f168201915b5050505050905085565b5f62000e5e46848462001e9e565b5f54610100900460ff16158080156200149d57505f54600160ff909116105b80620014b85750303b158015620014b857505f5460ff166001145b6200151d5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000bfe565b5f805460ff1916600117905580156200153f575f805461ff0019166101001790555b6200154b8383620020d1565b801562001591575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b620015a062001b11565b606580546001600160a01b0383166001600160a01b03199091168117909155620015d26033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820192909252610160810182905261018081019190915260026200168062001a94565b60ff1603620016a25760405163dfc60d8560e01b815260040160405180910390fd5b620016ae600262001ace565b620016c360c954610100900460ff1660021490565b15620016e25760405163bae6e2a960e01b815260040160405180910390fd5b81608001355f036200170757604051634299323b60e11b815260040160405180910390fd5b5f6200171a608084016060850162003071565b6001600160a01b03160362001742576040516303f8a7d360e01b815260040160405180910390fd5b61012f5f62001758608085016060860162003071565b6001600160a01b0316815260208101919091526040015f205460ff161562001793576040516375c42fc160e01b815260040160405180910390fd5b5f8080620017ca33620017ad608088016060890162003071565b620017bf6060890160408a0162003071565b886080013562002138565b604080516101a0810182525f808252602080830182905292820181905294975092955090935060608201906200180390890189620035be565b6001600160401b03168152602001336001600160a01b031681526020015f6001600160a01b03168860200160208101906200183f919062003071565b6001600160a01b03160362001855573362001867565b620018676040890160208a0162003071565b6001600160a01b03168152602090810190620018a2906200188b908a018a620035be565b6a195c98cc8c17dd985d5b1d60aa1b5b5f62000e4d565b6001600160a01b03168152602001620018c3610100890160e08a0162003071565b6001600160a01b03168152602001620018e160c08901353462003c7c565b815260c0880135602082015260a08801356040820152606081018690526080016200191161010089018962003650565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920182905250939094525092935091506200196190506562726964676560d01b8262001470565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b81526004016200198f91906200346d565b5f6040518083038185885af1158015620019ab573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620019d5919081019062003cb3565b96509050620019eb606088016040890162003071565b60808701516001600160a01b039182169116827feb8a69f21b7a981e25f90d9f1e2ab7fa5bdbfddbc0ac160344145fc5caa6ddd262001a2e60208c018c620035be565b602089015162001a4560808e0160608f0162003071565b604080516001600160401b0390941684526001600160a01b0392831660208501529116908201526060810188905260800160405180910390a4505050505062001a8f600162001ace565b919050565b5f4660010362001ac457507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010362001afd57807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b6033546001600160a01b0316331462000ee65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000bfe565b62000ca262001b11565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001bad5762001591836200266f565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001c0a575060408051601f3d908101601f1916820190925262001c079181019062003e12565b60015b62001c6f5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000bfe565b5f805160206200468b833981519152811462001ce05760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000bfe565b50620015918383836200270d565b604080516060810182525f808252602082018190529181019190915262001d1f6562726964676560d01b5f62001470565b6001600160a01b0316336001600160a01b03161462001d5157604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001d8e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001db4919062003e2a565b60208101519091506001600160a01b031633146200107157604051632583296b60e01b815260040160405180910390fd5b5f46845f01516001600160401b03160362001e1c5750602083015162001e166001600160a01b03821684846200273d565b62000e5e565b62001e2784620027a2565b6040516340c10f1960e01b81526001600160a01b03858116600483015260248201859052919250908216906340c10f19906044015f604051808303815f87803b15801562001e73575f80fd5b505af115801562001e86573d5f803e3d5ffd5b505050509392505050565b62000e4982825a620027e7565b6097545f906001600160a01b031662001eca57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001f21573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001f479190620035a0565b90508115801562001f5f57506001600160a01b038116155b1562000e5e57604051632b0d65db60e01b81526001600160401b03851660048201526024810184905260440162000bfe565b606580546001600160a01b031916905562000ca2816200284f565b604080516060810182525f808252602082018190529181019190915262001fdd6562726964676560d01b5f62001470565b6001600160a01b0316336001600160a01b0316146200200f57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156200204c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002072919062003e2a565b90505f6200209482604001516200189b6a195c98cc8c17dd985d5b1d60aa1b90565b9050806001600160a01b031682602001516001600160a01b031614620020cd57604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff16620020fa5760405162461bcd60e51b815260040162000bfe9062003e98565b6200210582620028a0565b6001600160a01b0381166200212d576040516375cabfef60e11b815260040160405180910390fd5b62000e4981620028d4565b6040805160a0810182525f80825260208083018290528284018290526060808401819052608084018190526001600160a01b03888116845261012d90925293822054600160401b9004161562002380576001600160a01b038681165f90815261012d6020908152604091829020825160a08101845281546001600160401b0381168252600160401b810490951692810192909252600160e01b90930460ff1691810191909152600182018054919291606084019190620021f890620035dc565b80601f01602080910402602001604051908101604052809291908181526020018280546200222690620035dc565b8015620022755780601f106200224b5761010080835404028352916020019162002275565b820191905f5260205f20905b8154815290600101906020018083116200225757829003601f168201915b505050505081526020016002820180546200229090620035dc565b80601f0160208091040260200160405190810160405280929190818152602001828054620022be90620035dc565b80156200230d5780601f10620022e3576101008083540402835291602001916200230d565b820191905f5260205f20905b815481529060010190602001808311620022ef57829003601f168201915b505050919092525050604051632770a7eb60e21b815233600482015260248101879052919350506001600160a01b03871690639dc29fac906044015f604051808303815f87803b15801562002360575f80fd5b505af115801562002373573d5f803e3d5ffd5b50505050839050620025ef565b5f8690506040518060a00160405280466001600160401b03168152602001886001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620023ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002410919062003ee3565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562002454573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200247d919081019062003f01565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa158015620024be573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052620024e7919081019062003f01565b90526040516370a0823160e01b815230600482015290935087905f906001600160a01b038316906370a0823190602401602060405180830381865afa15801562002533573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062002559919062003e12565b9050620025726001600160a01b03831633308a62002948565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015620025b7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620025dd919062003e12565b620025e9919062003c7c565b93505050505b306001600160a01b0316637f07c9478389888560405160200162002617949392919062003f36565b60408051601f1981840301815290829052620026369160240162003fdb565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505092509450945094915050565b6001600160a01b0381163b620026de5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000bfe565b5f805160206200468b83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b620027188362002982565b5f82511180620027255750805b156200159157620027378383620029c3565b50505050565b6040516001600160a01b0383166024820152604481018290526200159190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620029eb565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b039081168552925290912054168062001a8f5762000bad8262002ac3565b6001600160a01b0383166200280f57604051634c67134d60e11b815260040160405180910390fd5b5f6200282d8483856040805180602001604052805f81525062002cd5565b509050806200273757604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620028c26001600160a01b03821615620028bb578162001f91565b3362001f91565b5060c9805461ff001916610100179055565b5f54610100900460ff16620028fd5760405162461bcd60e51b815260040162000bfe9062003e98565b6001600160401b03461115620029265760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6040516001600160a01b0380851660248301528316604482015260648101829052620027379085906323b872dd60e01b906084016200276a565b6200298d816200266f565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000e5e8383604051806060016040528060278152602001620046ab6027913962002d5f565b5f62002a41826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662002dd99092919063ffffffff16565b80519091501562001591578080602001905181019062002a62919062003fef565b620015915760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000bfe565b5f8062002ad86033546001600160a01b031690565b60975460208501518551604080880151606089015160808a0151925162002b1097966001600160a01b0316959493906024016200400d565b60408051601f198184030181529190526020810180516001600160e01b031663bb86ef9360e01b179052905062002b586c0627269646765645f657263323609c1b5f62001470565b8160405162002b679062002fb8565b62002b749291906200407c565b604051809103905ff08015801562002b8e573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d602090815260409182902087518154928901519389015160ff16600160e01b0260ff60e01b1994909516600160401b026001600160e01b03199093166001600160401b0390911617919091179190911691909117815560608501519193508491600182019062002c129082620040a1565b506080820151600282019062002c299082620040a1565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b0319168885169081179091559151885160608a015160808b0151848c01519451959850929095169516937fb6b427556e8cb0ebf9175da4bc48c64c4f56e44cfaf8c3ab5ebf8e2ea13090799362002cc793919291906200416d565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b0381111562002cfa5762002cfa6200313f565b6040519080825280601f01601f19166020018201604052801562002d25576020820181803683370190505b5090505f808751602089018b8e8ef191503d92508683111562002d46578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b03168560405162002d7d9190620041a9565b5f60405180830381855af49150503d805f811462002db7576040519150601f19603f3d011682016040523d82523d5f602084013e62002dbc565b606091505b509150915062002dcf8683838762002de9565b9695505050505050565b606062000e5b84845f8562002e70565b6060831562002e5c5782515f0362002e54576001600160a01b0385163b62002e545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000bfe565b508162002e68565b62002e68838362002f4f565b949350505050565b60608247101562002ed35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000bfe565b5f80866001600160a01b0316858760405162002ef09190620041a9565b5f6040518083038185875af1925050503d805f811462002f2c576040519150601f19603f3d011682016040523d82523d5f602084013e62002f31565b606091505b509150915062002f448783838762002de9565b979650505050505050565b81511562002f605781518083602001fd5b8060405162461bcd60e51b815260040162000bfe919062003fdb565b50805462002f8a90620035dc565b5f825580601f1062002f9a575050565b601f0160209004905f5260205f209081019062000ca2919062002fc6565b6104c480620041c783390190565b5b80821115620020cd575f815560010162002fc7565b5f6020828403121562002fed575f80fd5b81356001600160e01b03198116811462000e5e575f80fd5b6001600160a01b038116811462000ca2575f80fd5b5f80604083850312156200302c575f80fd5b82356001600160401b0381111562003042575f80fd5b830160a0818603121562003054575f80fd5b91506020830135620030668162003005565b809150509250929050565b5f6020828403121562003082575f80fd5b813562000e5e8162003005565b5f8060408385031215620030a1575f80fd5b82356001600160401b03811115620030b7575f80fd5b83016101a08186031215620030ca575f80fd5b946020939093013593505050565b6001600160401b038116811462000ca2575f80fd5b801515811462000ca2575f80fd5b5f805f606084860312156200310e575f80fd5b83356200311b81620030d8565b92506020840135915060408401356200313481620030ed565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160a081016001600160401b03811182821017156200317857620031786200313f565b60405290565b6040516101a081016001600160401b03811182821017156200317857620031786200313f565b604051601f8201601f191681016001600160401b0381118282101715620031cf57620031cf6200313f565b604052919050565b5f6001600160401b03821115620031f257620031f26200313f565b50601f01601f191660200190565b5f82601f83011262003210575f80fd5b8135620032276200322182620031d7565b620031a4565b8181528460208386010111156200323c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156200326a575f80fd5b8235620032778162003005565b915060208301356001600160401b0381111562003292575f80fd5b620032a08582860162003200565b9150509250929050565b5f8060408385031215620032bc575f80fd5b823591506020830135620030668162003005565b5f8060208385031215620032e2575f80fd5b82356001600160401b0380821115620032f9575f80fd5b818501915085601f8301126200330d575f80fd5b8135818111156200331c575f80fd5b8660208285010111156200332e575f80fd5b60209290920196919550909350505050565b5f5b838110156200335c57818101518382015260200162003342565b50505f910152565b5f81518084526200337d81602086016020860162003340565b601f01601f19169290920160200192915050565b6001600160401b03861681526001600160a01b038516602082015260ff8416604082015260a0606082018190525f90620033ce9083018562003364565b8281036080840152620033e2818562003364565b98975050505050505050565b5f806040838503121562003400575f80fd5b8235915060208301356200306681620030ed565b5f806040838503121562003426575f80fd5b8235620030548162003005565b5f6020828403121562003444575f80fd5b81356001600160401b038111156200345a575f80fd5b8201610120818503121562000e5e575f80fd5b60208152620034886020820183516001600160801b03169052565b5f6020830151620034a460408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e08301516101006200352b818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a061018080860182905291925090620035756101c086018462003364565b90860151858203601f19018387015290925062002dcf838262003364565b805162001a8f8162003005565b5f60208284031215620035b1575f80fd5b815162000e5e8162003005565b5f60208284031215620035cf575f80fd5b813562000e5e81620030d8565b600181811c90821680620035f157607f821691505b6020821081036200361057634e487b7160e01b5f52602260045260245ffd5b50919050565b60ff8116811462000ca2575f80fd5b803562001a8f8162003616565b5f6020828403121562003643575f80fd5b813562000e5e8162003616565b5f808335601e1984360301811262003666575f80fd5b8301803591506001600160401b0382111562003680575f80fd5b60200191503681900382131562003695575f80fd5b9250929050565b818382375f9101908152919050565b601f8211156200159157805f5260205f20601f840160051c81016020851015620036d25750805b601f840160051c820191505b81811015620036f3575f8155600101620036de565b5050505050565b6001600160401b038311156200371457620037146200313f565b6200372c83620037258354620035dc565b83620036ab565b5f601f84116001811462003760575f8515620037485750838201355b5f19600387901b1c1916600186901b178355620036f3565b5f83815260208120601f198716915b828110156200379157868501358255602094850194600190920191016200376f565b5086821015620037ae575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b8135620037cd81620030d8565b6001600160401b03811690508154816001600160401b031982161783556020840135620037fa8162003005565b68010000000000000000600160e01b03604091821b166001600160e01b0319831684178117855590850135620038308162003616565b60ff60e01b8160e01b1660ff60e01b19851662ffffff60e81b85161783171785555050505062003864606083018362003650565b62003874818360018601620036fa565b505062003885608083018362003650565b62002737818360028601620036fa565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b6001600160a01b0388811682528716602082015260a0604082018190525f90620038eb908301878962003895565b82810360608401526200390081868862003895565b91505060ff8316608083015298975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f8085851115620039bf575f80fd5b83861115620039cc575f80fd5b5050820193919092039150565b5f60208284031215620039ea575f80fd5b81356001600160401b0381111562003a00575f80fd5b62002e688482850162003200565b805162001a8f81620030d8565b805162001a8f8162003616565b5f82601f83011262003a38575f80fd5b815162003a496200322182620031d7565b81815284602083860101111562003a5e575f80fd5b62002e6882602083016020870162003340565b5f805f806080858703121562003a85575f80fd5b84516001600160401b038082111562003a9c575f80fd5b9086019060a0828903121562003ab0575f80fd5b62003aba62003153565b825162003ac781620030d8565b8152602083015162003ad98162003005565b602082015262003aec6040840162003a1b565b604082015260608301518281111562003b03575f80fd5b62003b118a82860162003a28565b60608301525060808301518281111562003b29575f80fd5b62003b378a82860162003a28565b608083015250955062003b509150506020860162003593565b925062003b606040860162003593565b6060959095015193969295505050565b803562001a8f8162003005565b5f805f806080858703121562003b91575f80fd5b84356001600160401b038082111562003ba8575f80fd5b9086019060a0828903121562003bbc575f80fd5b62003bc662003153565b823562003bd381620030d8565b8152602083013562003be58162003005565b602082015262003bf86040840162003625565b604082015260608301358281111562003c0f575f80fd5b62003c1d8a82860162003200565b60608301525060808301358281111562003c35575f80fd5b62003c438a82860162003200565b608083015250955062003c5c9150506020860162003b70565b925062003c6c6040860162003b70565b9396929550929360600135925050565b8181038181111562000bad57634e487b7160e01b5f52601160045260245ffd5b80516001600160801b038116811462001a8f575f80fd5b5f806040838503121562003cc5575f80fd5b8251915060208301516001600160401b038082111562003ce3575f80fd5b908401906101a0828703121562003cf8575f80fd5b62003d026200317e565b62003d0d8362003c9c565b815262003d1d6020840162003593565b602082015262003d306040840162003a0e565b604082015262003d436060840162003a0e565b606082015262003d566080840162003593565b608082015262003d6960a0840162003593565b60a082015262003d7c60c0840162003593565b60c082015262003d8f60e0840162003593565b60e0820152610100838101519082015261012080840151908201526101408084015190820152610160808401518381111562003dc9575f80fd5b62003dd78982870162003a28565b828401525050610180808401518381111562003df1575f80fd5b62003dff8982870162003a28565b8284015250508093505050509250929050565b5f6020828403121562003e23575f80fd5b5051919050565b5f6060828403121562003e3b575f80fd5b604051606081018181106001600160401b038211171562003e605762003e606200313f565b60405282518152602083015162003e778162003005565b6020820152604083015162003e8c81620030d8565b60408201529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f6020828403121562003ef4575f80fd5b815162000e5e8162003616565b5f6020828403121562003f12575f80fd5b81516001600160401b0381111562003f28575f80fd5b62002e688482850162003a28565b608081526001600160401b03855116608082015260018060a01b0360208601511660a082015260ff60408601511660c08201525f606086015160a060e084015262003f8661012084018262003364565b90506080870151607f198483030161010085015262003fa6828262003364565b9250505062003fc060208301866001600160a01b03169052565b6001600160a01b039390931660408201526060015292915050565b602081525f62000e5e602083018462003364565b5f6020828403121562004000575f80fd5b815162000e5e81620030ed565b6001600160a01b0388811682528781166020830152861660408201526001600160401b038516606082015260ff8416608082015260e060a082018190525f906200405a9083018562003364565b82810360c08401526200406e818562003364565b9a9950505050505050505050565b6001600160a01b03831681526040602082018190525f9062000e5b9083018462003364565b81516001600160401b03811115620040bd57620040bd6200313f565b620040d581620040ce8454620035dc565b84620036ab565b602080601f8311600181146200410b575f8415620040f35750858301515b5f19600386901b1c1916600185901b17855562004165565b5f85815260208120601f198616915b828110156200413b578886015182559484019460019091019084016200411a565b50858210156200415957878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b606081525f62004181606083018662003364565b828103602084015262004195818662003364565b91505060ff83166040830152949350505050565b5f8251620041bc81846020870162003340565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d882bf842f972377a47949b222d70f7df9fd5bdbf62dfddc31a07da24277734264736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x6080604052600436106200019b575f3560e01c80635c975abb11620000de5780638456cb591162000092578063a86f9d9e116200006a578063a86f9d9e14620004c9578063e30c397814620004ed578063f09a4016146200050c578063f2fde38b1462000530575f80fd5b80638456cb59146200045d5780638da5cb5b14620004745780639aa8605c1462000493575f80fd5b80635c975abb146200039c578063634da63a14620003be57806367090ccf14620003d4578063715018a6146200041857806379ba5097146200042f5780637f07c9471462000446575f80fd5b80633ab76e9f11620001525780633f4ba83a116200012a5780633f4ba83a146200033b5780634f1ef286146200035257806352d1902d146200036957806359f4a9071462000380575f80fd5b80633ab76e9f14620002c65780633c6f5de214620003005780633eb6b8cf1462000317575f80fd5b806301ffc9a7146200019f57806306fdde0314620001e85780631507cc471462000215578063150b7a02146200023b5780632ca069a514620002845780633659cfe614620002a0575b5f80fd5b348015620001ab575f80fd5b50620001d3620001bd3660046200276b565b6001600160e01b031916631e37aef160e11b1490565b60405190151581526020015b60405180910390f35b348015620001f4575f80fd5b506b195c98cdcc8c57dd985d5b1d60a21b5b604051908152602001620001df565b6200022c62000226366004620029aa565b62000554565b604051620001df919062002b2f565b34801562000247575f80fd5b506200026a6200025936600462002c9c565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001620001df565b34801562000290575f80fd5b506200026a636cdb3d1360e11b81565b348015620002ac575f80fd5b50620002c4620002be36600462002d11565b6200095e565b005b348015620002d2575f80fd5b50609754620002e7906001600160a01b031681565b6040516001600160a01b039091168152602001620001df565b620002c46200031136600462002d2f565b62000a50565b34801562000323575f80fd5b50620002e76200033536600462002d86565b62000c22565b34801562000347575f80fd5b50620002c462000c3a565b620002c46200036336600462002dca565b62000cbd565b34801562000375575f80fd5b506200020662000d94565b3480156200038c575f80fd5b506200026a6380ac58cd60e01b81565b348015620003a8575f80fd5b50620001d360c954610100900460ff1660021490565b348015620003ca575f80fd5b5062000206600a81565b348015620003e0575f80fd5b50620002e7620003f236600462002e1c565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000424575f80fd5b50620002c462000e49565b3480156200043b575f80fd5b50620002c462000e5e565b620002c46200045736600462002e4d565b62000ed9565b34801562000469575f80fd5b50620002c46200108a565b34801562000480575f80fd5b506033546001600160a01b0316620002e7565b3480156200049f575f80fd5b50620004b7620004b136600462002d11565b620010fe565b604051620001df949392919062002e8f565b348015620004d5575f80fd5b50620002e7620004e736600462002ee2565b62001259565b348015620004f9575f80fd5b506065546001600160a01b0316620002e7565b34801562000518575f80fd5b50620002c46200052a36600462002f08565b62001270565b3480156200053c575f80fd5b50620002c46200054e36600462002d11565b62001388565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820183905261014082019290925261016081018290526101808101919091526002620005ca620013fc565b60ff1603620005ec5760405163dfc60d8560e01b815260040160405180910390fd5b620005f8600262001436565b6200060d60c954610100900460ff1660021490565b156200062c5760405163bae6e2a960e01b815260040160405180910390fd5b818060a001515181608001515114620006585760405163196e8a4160e31b815260040160405180910390fd5b600a8160800151511115620006805760405163e4a4c1c760e01b815260040160405180910390fd5b60608101516001600160a01b0316620006ac576040516303f8a7d360e01b815260040160405180910390fd5b5f5b83608001515181101562000706578360a001518181518110620006d557620006d562002f39565b60200260200101515f14620006fd57604051634299323b60e11b815260040160405180910390fd5b600101620006ae565b50606083015162000728906001600160a01b03166380ac58cd60e01b62001479565b6200074657604051633ee915f560e11b815260040160405180910390fd5b5f806200075433866200150c565b604080516101a0810182525f808252602080830182905292820181905289516001600160401b03166060830152336080830152918901519395509193509160a08201906001600160a01b0316620007ac5733620007b2565b87602001515b6001600160a01b03168152602001620007e6885f0151620007df6b195c98cdcc8c57dd985d5b1d60a21b90565b5f62000c22565b6001600160a01b031681526020018761010001516001600160a01b031681526020018760e00151346200081a919062002f4d565b81526020018760e0015181526020018760c00151815260200184815260200187610120015181525090505f6200085a6562726964676560d01b5f62001259565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b815260040162000888919062002b2f565b5f6040518083038185885af1158015620008a4573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620008ce919081019062002fe7565b809750819250505086604001516001600160a01b031686608001516001600160a01b0316827fabbf62a1459339f9ac59136d313a5ccd83d2706cc6d4c04d90642520169144dc896060015187602001518c606001518d608001518e60a001516040516200094095949392919062003182565b60405180910390a4505050505062000959600162001436565b919050565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000000003163003620009b25760405162461bcd60e51b8152600401620009a990620031de565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000000036001600160a01b0316620009fc5f8051602062003e9c833981519152546001600160a01b031690565b6001600160a01b03161462000a255760405162461bcd60e51b8152600401620009a9906200322a565b62000a3081620019d7565b604080515f8082526020820190925262000a4d91839190620019e1565b50565b600262000a5c620013fc565b60ff160362000a7e5760405163dfc60d8560e01b815260040160405180910390fd5b62000a8a600262001436565b62000a9f60c954610100900460ff1660021490565b1562000abe5760405163bae6e2a960e01b815260040160405180910390fd5b62000ac862001b58565b505f62000ada61016084018462003276565b62000aea916004908290620032bb565b81019062000af99190620032e4565b90505f808280602001905181019062000b1391906200337c565b9350505091505f62000b3b8387608001602081019062000b34919062002d11565b8462001c4f565b905062000b6961010087013562000b5960a0890160808a0162002d11565b6001600160a01b03169062001dd9565b62000b7b60a087016080880162002d11565b6001600160a01b0316857fe48bef18455e47bca14864ab6e82dffa29df148b051c09de95aec44ecf13598c8560200151848687516001600160401b0381111562000bc95762000bc962002794565b60405190808252806020026020018201604052801562000bf3578160200160208202803683370190505b5060405162000c06949392919062003486565b60405180910390a35050505062000c1e600162001436565b5050565b5f62000c3084848462001de6565b90505b9392505050565b62000c4f60c954610100900460ff1660021490565b62000c6d5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000cbb33620019d7565b565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000316300362000d085760405162461bcd60e51b8152600401620009a990620031de565b7f00000000000000000000000001670020000000000000000000000000000000036001600160a01b031662000d525f8051602062003e9c833981519152546001600160a01b031690565b6001600160a01b03161462000d7b5760405162461bcd60e51b8152600401620009a9906200322a565b62000d8682620019d7565b62000c1e82826001620019e1565b5f306001600160a01b037f0000000000000000000000000167002000000000000000000000000000000003161462000e355760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401620009a9565b505f8051602062003e9c8339815191525b90565b62000e5362001ed9565b62000cbb5f62001f35565b60655433906001600160a01b0316811462000ece5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401620009a9565b62000a4d8162001f35565b600262000ee5620013fc565b60ff160362000f075760405163dfc60d8560e01b815260040160405180910390fd5b62000f13600262001436565b62000f2860c954610100900460ff1660021490565b1562000f475760405163bae6e2a960e01b815260040160405180910390fd5b5f80808062000f5985870187620034c7565b93509350935093505f62000f6c62001f50565b90506001600160a01b038316158062000f8d57506001600160a01b03831630145b1562000fac5760405163def9481360e01b815260040160405180910390fd5b5f62000fba86858562001c4f565b905062000fd16001600160a01b0385163462001dd9565b836001600160a01b0316856001600160a01b0316835f01517f895f73e418d1bbbad2a311d085fad00e5d98a960e9f2afa4b942071d39bec43a85604001518a6020015186898a516001600160401b0381111562001032576200103262002794565b6040519080825280602002602001820160405280156200105c578160200160208202803683370190505b506040516200107095949392919062003182565b60405180910390a450505050505062000c1e600162001436565b6200109f60c954610100900460ff1660021490565b15620010be5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000ca8565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b03169291906200113e90620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200116c90620035c5565b8015620011bb5780601f106200119157610100808354040283529160200191620011bb565b820191905f5260205f20905b8154815290600101906020018083116200119d57829003601f168201915b505050505090806002018054620011d290620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200120090620035c5565b80156200124f5780601f1062001225576101008083540402835291602001916200124f565b820191905f5260205f20905b8154815290600101906020018083116200123157829003601f168201915b5050505050905084565b5f6200126746848462001de6565b90505b92915050565b5f54610100900460ff16158080156200128f57505f54600160ff909116105b80620012aa5750303b158015620012aa57505f5460ff166001145b6200130f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401620009a9565b5f805460ff19166001179055801562001331575f805461ff0019166101001790555b6200133d838362002076565b801562001383575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6200139262001ed9565b606580546001600160a01b0383166001600160a01b03199091168117909155620013c46033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f466001036200142c57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b466001036200146557807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f6001600160a01b0383163b6200149257505f6200126a565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015620014ff575060408051601f3d908101601f19168201909252620014fc91810190620035ff565b60015b156200126a579392505050565b604080516080810182525f8082526020820152606091810182905280820182905260608301516001600160a01b039081165f90815261012d6020526040902054600160401b90041615620017925760608301516001600160a01b039081165f90815261012d6020908152604091829020825160808101845281546001600160401b0381168252600160401b9004909416918401919091526001810180549192840191620015b990620035c5565b80601f0160208091040260200160405190810160405280929190818152602001828054620015e790620035c5565b8015620016365780601f106200160c5761010080835404028352916020019162001636565b820191905f5260205f20905b8154815290600101906020018083116200161857829003601f168201915b505050505081526020016002820180546200165190620035c5565b80601f01602080910402602001604051908101604052809291908181526020018280546200167f90620035c5565b8015620016ce5780601f10620016a457610100808354040283529160200191620016ce565b820191905f5260205f20905b815481529060010190602001808311620016b057829003601f168201915b50505050508152505090505f5b8360800151518110156200178b5783606001516001600160a01b0316639dc29fac868660800151848151811062001716576200171662002f39565b60200260200101516040518363ffffffff1660e01b8152600401620017509291906001600160a01b03929092168252602082015260400190565b5f604051808303815f87803b15801562001768575f80fd5b505af11580156200177b573d5f803e3d5ffd5b50505050806001019050620016db565b5062001952565b5f836060015190506040518060800160405280466001600160401b0316815260200185606001516001600160a01b03168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa15801562001803573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200182c91908101906200361d565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa1580156200186d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526200189691908101906200361d565b905291505f5b8460800151518110156200194f57816001600160a01b03166342842e0e873088608001518581518110620018d457620018d462002f39565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b1580156200192c575f80fd5b505af11580156200193f573d5f803e3d5ffd5b505050508060010190506200189c565b50505b306001600160a01b0316637f07c94782868660400151876080015160405160200162001982949392919062003652565b60408051601f1981840301815290829052620019a191602401620036e1565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505091509250929050565b62000a4d62001ed9565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001a17576200138383620020dd565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001a74575060408051601f3d908101601f1916820190925262001a7191810190620036f5565b60015b62001ad95760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401620009a9565b5f8051602062003e9c833981519152811462001b4a5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401620009a9565b50620013838383836200217b565b604080516060810182525f808252602082018190529181019190915262001b896562726964676560d01b5f62001259565b6001600160a01b0316336001600160a01b03161462001bbb57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001bf8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001c1e91906200370d565b60208101519091506001600160a01b0316331462000e4657604051632583296b60e01b815260040160405180910390fd5b5f46845f01516001600160401b03160362001d1e575060208301515f5b825181101562001d1757816001600160a01b03166342842e0e308686858151811062001c9c5762001c9c62002f39565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b15801562001cf4575f80fd5b505af115801562001d07573d5f803e3d5ffd5b5050505080600101905062001c6c565b5062000c33565b62001d2984620021ab565b90505f5b825181101562001dd157816001600160a01b03166340c10f198585848151811062001d5c5762001d5c62002f39565b60200260200101516040518363ffffffff1660e01b815260040162001d969291906001600160a01b03929092168252602082015260400190565b5f604051808303815f87803b15801562001dae575f80fd5b505af115801562001dc1573d5f803e3d5ffd5b5050505080600101905062001d2d565b509392505050565b62000c1e82825a620021f0565b6097545f906001600160a01b031662001e1257604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001e69573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001e8f91906200377b565b90508115801562001ea757506001600160a01b038116155b1562000c3357604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401620009a9565b6033546001600160a01b0316331462000cbb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620009a9565b606580546001600160a01b031916905562000a4d8162002258565b604080516060810182525f808252602082018190529181019190915262001f816562726964676560d01b5f62001259565b6001600160a01b0316336001600160a01b03161462001fb357604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001ff0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200201691906200370d565b90505f620020398260400151620007df6b195c98cdcc8c57dd985d5b1d60a21b90565b9050806001600160a01b031682602001516001600160a01b0316146200207257604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff166200209f5760405162461bcd60e51b8152600401620009a99062003799565b620020aa82620022a9565b6001600160a01b038116620020d2576040516375cabfef60e11b815260040160405180910390fd5b62000c1e81620022dd565b6001600160a01b0381163b6200214c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620009a9565b5f8051602062003e9c83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b620021868362002351565b5f82511180620021935750805b156200138357620021a5838362002392565b50505050565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b039081168552925290912054168062000959576200126a82620023ba565b6001600160a01b0383166200221857604051634c67134d60e11b815260040160405180910390fd5b5f620022368483856040805180602001604052805f815250620025a5565b50905080620021a557604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620022cb6001600160a01b03821615620022c4578162001f35565b3362001f35565b5060c9805461ff001916610100179055565b5f54610100900460ff16620023065760405162461bcd60e51b8152600401620009a99062003799565b6001600160401b034611156200232f5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6200235c81620020dd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062001267838360405180606001604052806027815260200162003ebc602791396200262f565b5f80620023cf6033546001600160a01b031690565b60975460208501518551604080880151606089015191516200240296956001600160a01b031694939290602401620037e4565b60408051601f198184030181529190526020810180516001600160e01b03166377c6257360e11b17905290506200244b6d627269646765645f65726337323160901b5f62001259565b816040516200245a906200275d565b6200246792919062003849565b604051809103905ff08015801562002481573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620024e79082620038bd565b5060608201516002820190620024fe9082620038bd565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b9262002597929062003989565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b03811115620025ca57620025ca62002794565b6040519080825280601f01601f191660200182016040528015620025f5576020820181803683370190505b5090505f808751602089018b8e8ef191503d92508683111562002616578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b0316856040516200264d9190620039ba565b5f60405180830381855af49150503d805f811462002687576040519150601f19603f3d011682016040523d82523d5f602084013e6200268c565b606091505b50915091506200269f86838387620026a9565b9695505050505050565b606083156200271c5782515f0362002714576001600160a01b0385163b620027145760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620009a9565b508162002728565b62002728838362002730565b949350505050565b815115620027415781518083602001fd5b8060405162461bcd60e51b8152600401620009a99190620036e1565b6104c480620039d883390190565b5f602082840312156200277c575f80fd5b81356001600160e01b03198116811462001267575f80fd5b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715620027ce57620027ce62002794565b60405290565b6040516101a081016001600160401b0381118282101715620027ce57620027ce62002794565b604051608081016001600160401b0381118282101715620027ce57620027ce62002794565b604051601f8201601f191681016001600160401b03811182821017156200284a576200284a62002794565b604052919050565b6001600160401b038116811462000a4d575f80fd5b8035620009598162002852565b6001600160a01b038116811462000a4d575f80fd5b8035620009598162002874565b5f6001600160401b03821115620028b157620028b162002794565b5060051b60200190565b5f82601f830112620028cb575f80fd5b81356020620028e4620028de8362002896565b6200281f565b8083825260208201915060208460051b87010193508684111562002906575f80fd5b602086015b848110156200292457803583529183019183016200290b565b509695505050505050565b5f6001600160401b038211156200294a576200294a62002794565b50601f01601f191660200190565b5f82601f83011262002968575f80fd5b813562002979620028de826200292f565b8181528460208386010111156200298e575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60208284031215620029bb575f80fd5b81356001600160401b0380821115620029d2575f80fd5b908301906101408286031215620029e7575f80fd5b620029f1620027a8565b620029fc8362002867565b815262002a0c6020840162002889565b602082015262002a1f6040840162002889565b604082015262002a326060840162002889565b606082015260808301358281111562002a49575f80fd5b62002a5787828601620028bb565b60808301525060a08301358281111562002a6f575f80fd5b62002a7d87828601620028bb565b60a08301525060c083013560c082015260e083013560e082015261010062002aa781850162002889565b90820152610120838101358381111562002abf575f80fd5b62002acd8882870162002958565b918301919091525095945050505050565b5f5b8381101562002afa57818101518382015260200162002ae0565b50505f910152565b5f815180845262002b1b81602086016020860162002ade565b601f01601f19169290920160200192915050565b6020815262002b4a6020820183516001600160801b03169052565b5f602083015162002b6660408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010062002bed818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a06101808086018290529192509062002c376101c086018462002b02565b90860151858203601f1901838701529092506200269f838262002b02565b5f8083601f84011262002c66575f80fd5b5081356001600160401b0381111562002c7d575f80fd5b60208301915083602082850101111562002c95575f80fd5b9250929050565b5f805f805f6080868803121562002cb1575f80fd5b853562002cbe8162002874565b9450602086013562002cd08162002874565b93506040860135925060608601356001600160401b0381111562002cf2575f80fd5b62002d008882890162002c55565b969995985093965092949392505050565b5f6020828403121562002d22575f80fd5b8135620012678162002874565b5f806040838503121562002d41575f80fd5b82356001600160401b0381111562002d57575f80fd5b83016101a0818603121562002d6a575f80fd5b946020939093013593505050565b801515811462000a4d575f80fd5b5f805f6060848603121562002d99575f80fd5b833562002da68162002852565b925060208401359150604084013562002dbf8162002d78565b809150509250925092565b5f806040838503121562002ddc575f80fd5b823562002de98162002874565b915060208301356001600160401b0381111562002e04575f80fd5b62002e128582860162002958565b9150509250929050565b5f806040838503121562002e2e575f80fd5b82359150602083013562002e428162002874565b809150509250929050565b5f806020838503121562002e5f575f80fd5b82356001600160401b0381111562002e75575f80fd5b62002e838582860162002c55565b90969095509350505050565b6001600160401b03851681526001600160a01b03841660208201526080604082018190525f9062002ec39083018562002b02565b828103606084015262002ed7818562002b02565b979650505050505050565b5f806040838503121562002ef4575f80fd5b82359150602083013562002e428162002d78565b5f806040838503121562002f1a575f80fd5b823562002f278162002874565b9150602083013562002e428162002874565b634e487b7160e01b5f52603260045260245ffd5b818103818111156200126a57634e487b7160e01b5f52601160045260245ffd5b80516001600160801b038116811462000959575f80fd5b8051620009598162002874565b8051620009598162002852565b5f82601f83011262002fae575f80fd5b815162002fbf620028de826200292f565b81815284602083860101111562002fd4575f80fd5b6200272882602083016020870162002ade565b5f806040838503121562002ff9575f80fd5b8251915060208301516001600160401b038082111562003017575f80fd5b908401906101a082870312156200302c575f80fd5b62003036620027d4565b620030418362002f6d565b8152620030516020840162002f84565b6020820152620030646040840162002f91565b6040820152620030776060840162002f91565b60608201526200308a6080840162002f84565b60808201526200309d60a0840162002f84565b60a0820152620030b060c0840162002f84565b60c0820152620030c360e0840162002f84565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015183811115620030fd575f80fd5b6200310b8982870162002f9e565b828401525050610180808401518381111562003125575f80fd5b620031338982870162002f9e565b8284015250508093505050509250929050565b5f815180845260208085019450602084015f5b83811015620031775781518752958201959082019060010162003159565b509495945050505050565b6001600160401b03861681526001600160a01b0385811660208301528416604082015260a0606082018190525f90620031be9083018562003146565b8281036080840152620031d2818562003146565b98975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f808335601e198436030181126200328c575f80fd5b8301803591506001600160401b03821115620032a6575f80fd5b60200191503681900382131562002c95575f80fd5b5f8085851115620032ca575f80fd5b83861115620032d7575f80fd5b5050820193919092039150565b5f60208284031215620032f5575f80fd5b81356001600160401b038111156200330b575f80fd5b620027288482850162002958565b5f82601f83011262003329575f80fd5b815160206200333c620028de8362002896565b8083825260208201915060208460051b8701019350868411156200335e575f80fd5b602086015b8481101562002924578051835291830191830162003363565b5f805f806080858703121562003390575f80fd5b84516001600160401b0380821115620033a7575f80fd5b9086019060808289031215620033bb575f80fd5b620033c5620027fa565b8251620033d28162002852565b81526020830151620033e48162002874565b6020820152604083015182811115620033fb575f80fd5b620034098a82860162002f9e565b60408301525060608301518281111562003421575f80fd5b6200342f8a82860162002f9e565b6060830152509550620034456020880162002f84565b9450620034556040880162002f84565b935060608701519150808211156200346b575f80fd5b506200347a8782880162003319565b91505092959194509250565b6001600160a01b038581168252841660208201526080604082018190525f90620034b39083018562003146565b828103606084015262002ed7818562003146565b5f805f8060808587031215620034db575f80fd5b84356001600160401b0380821115620034f2575f80fd5b908601906080828903121562003506575f80fd5b62003510620027fa565b82356200351d8162002852565b815260208301356200352f8162002874565b602082015260408301358281111562003546575f80fd5b620035548a82860162002958565b6040830152506060830135828111156200356c575f80fd5b6200357a8a82860162002958565b6060830152509550620035906020880162002889565b9450620035a06040880162002889565b93506060870135915080821115620035b6575f80fd5b506200347a87828801620028bb565b600181811c90821680620035da57607f821691505b602082108103620035f957634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121562003610575f80fd5b8151620012678162002d78565b5f602082840312156200362e575f80fd5b81516001600160401b0381111562003644575f80fd5b620027288482850162002f9e565b608080825285516001600160401b03168282015260208601516001600160a01b0390811660a0840152604087015160c08401929092525f91906200369b61010085018362002b02565b91506060880151607f198584030160e0860152620036ba838262002b02565b88831660208701529187166040860152508381036060850152905062002ed7818562003146565b602081525f62001267602083018462002b02565b5f6020828403121562003706575f80fd5b5051919050565b5f606082840312156200371e575f80fd5b604051606081018181106001600160401b038211171562003743576200374362002794565b6040528251815260208301516200375a8162002874565b602082015260408301516200376f8162002852565b60408201529392505050565b5f602082840312156200378c575f80fd5b8151620012678162002874565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b0387811682528681166020830152851660408201526001600160401b038416606082015260c0608082018190525f90620038289083018562002b02565b82810360a08401526200383c818562002b02565b9998505050505050505050565b6001600160a01b03831681526040602082018190525f9062000c309083018462002b02565b601f8211156200138357805f5260205f20601f840160051c81016020851015620038955750805b601f840160051c820191505b81811015620038b6575f8155600101620038a1565b5050505050565b81516001600160401b03811115620038d957620038d962002794565b620038f181620038ea8454620035c5565b846200386e565b602080601f83116001811462003927575f84156200390f5750858301515b5f19600386901b1c1916600185901b17855562003981565b5f85815260208120601f198616915b82811015620039575788860151825594840194600190910190840162003936565b50858210156200397557878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f6200399d604083018562002b02565b8281036020840152620039b1818562002b02565b95945050505050565b5f8251620039cd81846020870162002ade565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220838a65434637367b0dce4f01d48f09f1bff466edff41473526507bfd76721ee164736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000003" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x608060405260043610620001b7575f3560e01c8063634da63a11620000fa5780639aa8605c1162000092578063e30c3978116200006a578063e30c397814620004fd578063f09a4016146200051c578063f23a6e611462000540578063f2fde38b1462000570575f80fd5b80639aa8605c1462000471578063a86f9d9e14620004a7578063bc197c8114620004cb575f80fd5b806379ba509711620000d257806379ba5097146200040d5780637f07c94714620004245780638456cb59146200043b5780638da5cb5b1462000452575f80fd5b8063634da63a146200039c57806367090ccf14620003b2578063715018a614620003f6575f80fd5b80633c6f5de2116200016e5780634f1ef28611620001465780634f1ef286146200033057806352d1902d146200034757806359f4a907146200035e5780635c975abb146200037a575f80fd5b80633c6f5de214620002de5780633eb6b8cf14620002f55780633f4ba83a1462000319575f80fd5b806301ffc9a714620001bb57806306fdde0314620001f45780631507cc4714620002225780632ca069a514620002485780633659cfe6146200027e5780633ab76e9f14620002a4575b5f80fd5b348015620001c7575f80fd5b50620001df620001d936600462002745565b62000594565b60405190151581526020015b60405180910390f35b34801562000200575f80fd5b506c195c98cc4c4d4d57dd985d5b1d609a1b5b604051908152602001620001eb565b620002396200023336600462002984565b620005cb565b604051620001eb919062002b09565b34801562000254575f80fd5b5062000264636cdb3d1360e11b81565b6040516001600160e01b03199091168152602001620001eb565b3480156200028a575f80fd5b50620002a26200029c36600462002c2f565b620009d6565b005b348015620002b0575f80fd5b50609754620002c5906001600160a01b031681565b6040516001600160a01b039091168152602001620001eb565b620002a2620002ef36600462002c4d565b62000ac8565b34801562000301575f80fd5b50620002c56200031336600462002ca4565b62000c59565b34801562000325575f80fd5b50620002a262000c71565b620002a26200034136600462002ce8565b62000cf4565b34801562000353575f80fd5b506200021362000dcb565b3480156200036a575f80fd5b50620002646380ac58cd60e01b81565b34801562000386575f80fd5b50620001df60c954610100900460ff1660021490565b348015620003a8575f80fd5b5062000213600a81565b348015620003be575f80fd5b50620002c5620003d036600462002d3a565b61012e60209081525f92835260408084209091529082529020546001600160a01b031681565b34801562000402575f80fd5b50620002a262000e80565b34801562000419575f80fd5b50620002a262000e95565b620002a26200043536600462002db2565b62000f10565b34801562000447575f80fd5b50620002a262001080565b3480156200045e575f80fd5b506033546001600160a01b0316620002c5565b3480156200047d575f80fd5b50620004956200048f36600462002c2f565b620010f4565b604051620001eb949392919062002df4565b348015620004b3575f80fd5b50620002c5620004c536600462002e47565b6200124f565b348015620004d7575f80fd5b5062000264620004e936600462002eb0565b63bc197c8160e01b98975050505050505050565b34801562000509575f80fd5b506065546001600160a01b0316620002c5565b34801562000528575f80fd5b50620002a26200053a36600462002f74565b6200125d565b3480156200054c575f80fd5b50620002646200055e36600462002fa5565b63f23a6e6160e01b9695505050505050565b3480156200057c575f80fd5b50620002a26200058e36600462002c2f565b62001375565b5f6001600160e01b031982166301ffc9a760e01b1480620005c55750631e37aef160e11b6001600160e01b03198316145b92915050565b604080516101a0810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201929092526101608101829052610180810191909152600262000641620013e9565b60ff1603620006635760405163dfc60d8560e01b815260040160405180910390fd5b6200066f600262001423565b6200068460c954610100900460ff1660021490565b15620006a35760405163bae6e2a960e01b815260040160405180910390fd5b818060a001515181608001515114620006cf5760405163196e8a4160e31b815260040160405180910390fd5b600a8160800151511115620006f75760405163e4a4c1c760e01b815260040160405180910390fd5b60608101516001600160a01b031662000723576040516303f8a7d360e01b815260040160405180910390fd5b5f5b8360a00151518110156200077d578360a0015181815181106200074c576200074c62003023565b60200260200101515f036200077457604051634299323b60e11b815260040160405180910390fd5b60010162000725565b5060608301516200079f906001600160a01b0316636cdb3d1360e11b62001466565b620007bd57604051633ee915f560e11b815260040160405180910390fd5b5f80620007cb3386620014f9565b604080516101a0810182525f808252602080830182905292820181905289516001600160401b03166060830152336080830152918901519395509193509160a08201906001600160a01b031662000823573362000829565b87602001515b6001600160a01b031681526020016200085e885f0151620008576c195c98cc4c4d4d57dd985d5b1d609a1b90565b5f62000c59565b6001600160a01b031681526020018761010001516001600160a01b031681526020018760e001513462000892919062003037565b81526020018760e0015181526020018760c00151815260200184815260200187610120015181525090505f620008d26562726964676560d01b5f6200124f565b6001600160a01b0316636c334e2e34846040518363ffffffff1660e01b815260040162000900919062002b09565b5f6040518083038185885af11580156200091c573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052620009469190810190620030d1565b809750819250505086604001516001600160a01b031686608001516001600160a01b0316827fabbf62a1459339f9ac59136d313a5ccd83d2706cc6d4c04d90642520169144dc896060015187602001518c606001518d608001518e60a00151604051620009b89594939291906200326c565b60405180910390a45050505050620009d1600162001423565b919050565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000416300362000a2a5760405162461bcd60e51b815260040162000a2190620032c8565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000000046001600160a01b031662000a745f805160206200408f833981519152546001600160a01b031690565b6001600160a01b03161462000a9d5760405162461bcd60e51b815260040162000a219062003314565b62000aa88162001a4b565b604080515f8082526020820190925262000ac59183919062001a55565b50565b600262000ad4620013e9565b60ff160362000af65760405163dfc60d8560e01b815260040160405180910390fd5b62000b02600262001423565b62000b1760c954610100900460ff1660021490565b1562000b365760405163bae6e2a960e01b815260040160405180910390fd5b62000b4062001bcc565b505f62000b5261016084018462003360565b62000b62916004908290620033a5565b81019062000b719190620033ce565b90505f805f8380602001905181019062000b8c919062003466565b94509450505092505f62000bb78488608001602081019062000baf919062002c2f565b858562001cc3565b905062000be561010088013562000bd560a08a0160808b0162002c2f565b6001600160a01b03169062001dbf565b62000bf760a088016080890162002c2f565b6001600160a01b0316867fe48bef18455e47bca14864ab6e82dffa29df148b051c09de95aec44ecf13598c866020015184878760405162000c3c949392919062003596565b60405180910390a3505050505062000c55600162001423565b5050565b5f62000c6784848462001dcc565b90505b9392505050565b62000c8660c954610100900460ff1660021490565b62000ca45760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a162000cf23362001a4b565b565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000416300362000d3f5760405162461bcd60e51b815260040162000a2190620032c8565b7f00000000000000000000000001670020000000000000000000000000000000046001600160a01b031662000d895f805160206200408f833981519152546001600160a01b031690565b6001600160a01b03161462000db25760405162461bcd60e51b815260040162000a219062003314565b62000dbd8262001a4b565b62000c558282600162001a55565b5f306001600160a01b037f0000000000000000000000000167002000000000000000000000000000000004161462000e6c5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000a21565b505f805160206200408f8339815191525b90565b62000e8a62001ebf565b62000cf25f62001f1b565b60655433906001600160a01b0316811462000f055760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840162000a21565b62000ac58162001f1b565b600262000f1c620013e9565b60ff160362000f3e5760405163dfc60d8560e01b815260040160405180910390fd5b62000f4a600262001423565b62000f5f60c954610100900460ff1660021490565b1562000f7e5760405163bae6e2a960e01b815260040160405180910390fd5b5f8080808062000f9186880188620035d7565b945094509450945094505f62000fa662001f36565b90506001600160a01b038416158062000fc757506001600160a01b03841630145b1562000fe65760405163def9481360e01b815260040160405180910390fd5b5f62000ff58786868662001cc3565b90506200100c6001600160a01b0386163462001dbf565b846001600160a01b0316866001600160a01b0316835f01517f895f73e418d1bbbad2a311d085fad00e5d98a960e9f2afa4b942071d39bec43a85604001518b60200151868a8a604051620010659594939291906200326c565b60405180910390a45050505050505062000c55600162001423565b6200109560c954610100900460ff1660021490565b15620010b45760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000cdf565b61012d6020525f9081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b03169291906200113490620036fa565b80601f01602080910402602001604051908101604052809291908181526020018280546200116290620036fa565b8015620011b15780601f106200118757610100808354040283529160200191620011b1565b820191905f5260205f20905b8154815290600101906020018083116200119357829003601f168201915b505050505090806002018054620011c890620036fa565b80601f0160208091040260200160405190810160405280929190818152602001828054620011f690620036fa565b8015620012455780601f106200121b5761010080835404028352916020019162001245565b820191905f5260205f20905b8154815290600101906020018083116200122757829003601f168201915b5050505050905084565b5f62000c6a46848462001dcc565b5f54610100900460ff16158080156200127c57505f54600160ff909116105b80620012975750303b1580156200129757505f5460ff166001145b620012fc5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000a21565b5f805460ff1916600117905580156200131e575f805461ff0019166101001790555b6200132a83836200205d565b801562001370575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6200137f62001ebf565b606580546001600160a01b0383166001600160a01b03199091168117909155620013b16033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b5f466001036200141957507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b466001036200145257807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b5f6001600160a01b0383163b6200147f57505f620005c5565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015620014ec575060408051601f3d908101601f19168201909252620014e99181019062003734565b60015b15620005c5579392505050565b604080516080810182525f8082526020820152606091810182905280820182905260608301516001600160a01b039081165f90815261012d6020526040902054600160401b90041615620017a55760608301516001600160a01b039081165f90815261012d6020908152604091829020825160808101845281546001600160401b0381168252600160401b9004909416918401919091526001810180549192840191620015a690620036fa565b80601f0160208091040260200160405190810160405280929190818152602001828054620015d490620036fa565b8015620016235780601f10620015f95761010080835404028352916020019162001623565b820191905f5260205f20905b8154815290600101906020018083116200160557829003601f168201915b505050505081526020016002820180546200163e90620036fa565b80601f01602080910402602001604051908101604052809291908181526020018280546200166c90620036fa565b8015620016bb5780601f106200169157610100808354040283529160200191620016bb565b820191905f5260205f20905b8154815290600101906020018083116200169d57829003601f168201915b50505050508152505090505f5b8360800151518110156200179e5783606001516001600160a01b031663f5298aca868660800151848151811062001703576200170362003023565b60200260200101518760a00151858151811062001724576200172462003023565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064015f604051808303815f87803b1580156200177b575f80fd5b505af11580156200178e573d5f803e3d5ffd5b50505050806001019050620016c8565b50620019c9565b6040518060800160405280466001600160401b0316815260200184606001516001600160a01b0316815260200160405180602001604052805f815250815260200160405180602001604052805f81525081525090505f83606001519050806001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa9250505080156200186257506040513d5f823e601f3d908101601f191682016040526200185f919081019062003752565b60015b156200186e5760608301525b806001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa925050508015620018ce57506040513d5f823e601f3d908101601f19168201604052620018cb919081019062003752565b60015b15620018da5760408301525b5f5b846080015151811015620019c65784606001516001600160a01b031663f242432a33308860800151858151811062001918576200191862003023565b60200260200101518960a00151868151811062001939576200193962003023565b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a060848201525f60a482015260c4015f604051808303815f87803b158015620019a3575f80fd5b505af1158015620019b6573d5f803e3d5ffd5b50505050806001019050620018dc565b50505b604080840151608085015160a086015192513093637f07c94793620019f69387938b939060200162003787565b60408051601f198184030181529082905262001a15916024016200383e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505091509250929050565b62000ac562001ebf565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001a8b576200137083620020c4565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001ae8575060408051601f3d908101601f1916820190925262001ae59181019062003852565b60015b62001b4d5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000a21565b5f805160206200408f833981519152811462001bbe5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000a21565b506200137083838362002162565b604080516060810182525f808252602082018190529181019190915262001bfd6562726964676560d01b5f6200124f565b6001600160a01b0316336001600160a01b03161462001c2f57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001c6c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001c9291906200386a565b60208101519091506001600160a01b0316331462000e7d57604051632583296b60e01b815260040160405180910390fd5b5f46855f01516001600160401b03160362001d4757506020840151604051631759616b60e11b81526001600160a01b03821690632eb2c2d69062001d12903090889088908890600401620038d8565b5f604051808303815f87803b15801562001d2a575f80fd5b505af115801562001d3d573d5f803e3d5ffd5b5050505062001db7565b62001d528562002192565b60405163d81d0a1560e01b81529091506001600160a01b0382169063d81d0a159062001d879087908790879060040162003935565b5f604051808303815f87803b15801562001d9f575f80fd5b505af115801562001db2573d5f803e3d5ffd5b505050505b949350505050565b62000c5582825a620021d7565b6097545f906001600160a01b031662001df857604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001e4f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001e7591906200396e565b90508115801562001e8d57506001600160a01b038116155b1562000c6a57604051632b0d65db60e01b81526001600160401b03851660048201526024810184905260440162000a21565b6033546001600160a01b0316331462000cf25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000a21565b606580546001600160a01b031916905562000ac5816200223f565b604080516060810182525f808252602082018190529181019190915262001f676562726964676560d01b5f6200124f565b6001600160a01b0316336001600160a01b03161462001f9957604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001fd6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062001ffc91906200386a565b90505f620020208260400151620008576c195c98cc4c4d4d57dd985d5b1d609a1b90565b9050806001600160a01b031682602001516001600160a01b0316146200205957604051632583296b60e01b815260040160405180910390fd5b5090565b5f54610100900460ff16620020865760405162461bcd60e51b815260040162000a21906200398c565b620020918262002290565b6001600160a01b038116620020b9576040516375cabfef60e11b815260040160405180910390fd5b62000c5581620022c4565b6001600160a01b0381163b620021335760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000a21565b5f805160206200408f83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6200216d8362002338565b5f825111806200217a5750805b1562001370576200218c838362002379565b50505050565b80516001600160401b03165f90815261012e60209081526040808320828501516001600160a01b0390811685529252909120541680620009d157620005c582620023a1565b6001600160a01b038316620021ff57604051634c67134d60e11b815260040160405180910390fd5b5f6200221d8483856040805180602001604052805f8152506200258d565b509050806200218c57604051634c67134d60e11b815260040160405180910390fd5b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620022b26001600160a01b03821615620022ab578162001f1b565b3362001f1b565b5060c9805461ff001916610100179055565b5f54610100900460ff16620022ed5760405162461bcd60e51b815260040162000a21906200398c565b6001600160401b03461115620023165760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6200234381620020c4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606062000c6a8383604051806060016040528060278152602001620040af6027913962002617565b5f80620023b66033546001600160a01b031690565b6097546020850151855160408088015160608901519151620023e996956001600160a01b031694939290602401620039d7565b60408051601f198184030181529190526020810180516001600160e01b03166377c6257360e11b1790529050620024336e627269646765645f6572633131353560881b5f6200124f565b81604051620024429062002737565b6200244f92919062003a3c565b604051809103905ff08015801562002469573d5f803e3d5ffd5b506001600160a01b038082165f90815261012d60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620024cf908262003ab0565b5060608201516002820190620024e6908262003ab0565b505083516001600160401b039081165f90815261012e6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b926200257f929062003b7c565b60405180910390a450919050565b5f60605f805f8661ffff166001600160401b03811115620025b257620025b26200276e565b6040519080825280601f01601f191660200182016040528015620025dd576020820181803683370190505b5090505f808751602089018b8e8ef191503d925086831115620025fe578692505b828152825f602083013e90999098509650505050505050565b60605f80856001600160a01b03168560405162002635919062003bad565b5f60405180830381855af49150503d805f81146200266f576040519150601f19603f3d011682016040523d82523d5f602084013e62002674565b606091505b5091509150620026878683838762002691565b9695505050505050565b60608315620027045782515f03620026fc576001600160a01b0385163b620026fc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000a21565b508162001db7565b62001db783838151156200271b5781518083602001fd5b8060405162461bcd60e51b815260040162000a2191906200383e565b6104c48062003bcb83390190565b5f6020828403121562002756575f80fd5b81356001600160e01b03198116811462000c6a575f80fd5b634e487b7160e01b5f52604160045260245ffd5b60405161014081016001600160401b0381118282101715620027a857620027a86200276e565b60405290565b6040516101a081016001600160401b0381118282101715620027a857620027a86200276e565b604051608081016001600160401b0381118282101715620027a857620027a86200276e565b604051601f8201601f191681016001600160401b03811182821017156200282457620028246200276e565b604052919050565b6001600160401b038116811462000ac5575f80fd5b8035620009d1816200282c565b6001600160a01b038116811462000ac5575f80fd5b8035620009d1816200284e565b5f6001600160401b038211156200288b576200288b6200276e565b5060051b60200190565b5f82601f830112620028a5575f80fd5b81356020620028be620028b88362002870565b620027f9565b8083825260208201915060208460051b870101935086841115620028e0575f80fd5b602086015b84811015620028fe5780358352918301918301620028e5565b509695505050505050565b5f6001600160401b038211156200292457620029246200276e565b50601f01601f191660200190565b5f82601f83011262002942575f80fd5b813562002953620028b88262002909565b81815284602083860101111562002968575f80fd5b816020850160208301375f918101602001919091529392505050565b5f6020828403121562002995575f80fd5b81356001600160401b0380821115620029ac575f80fd5b908301906101408286031215620029c1575f80fd5b620029cb62002782565b620029d68362002841565b8152620029e66020840162002863565b6020820152620029f96040840162002863565b604082015262002a0c6060840162002863565b606082015260808301358281111562002a23575f80fd5b62002a318782860162002895565b60808301525060a08301358281111562002a49575f80fd5b62002a578782860162002895565b60a08301525060c083013560c082015260e083013560e082015261010062002a8181850162002863565b90820152610120838101358381111562002a99575f80fd5b62002aa78882870162002932565b918301919091525095945050505050565b5f5b8381101562002ad457818101518382015260200162002aba565b50505f910152565b5f815180845262002af581602086016020860162002ab8565b601f01601f19169290920160200192915050565b6020815262002b246020820183516001600160801b03169052565b5f602083015162002b4060408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010062002bc7818501836001600160a01b03169052565b8401516101208481019190915284015161014080850191909152840151610160808501919091528401516101a06101808086018290529192509062002c116101c086018462002adc565b90860151858203601f19018387015290925062002687838262002adc565b5f6020828403121562002c40575f80fd5b813562000c6a816200284e565b5f806040838503121562002c5f575f80fd5b82356001600160401b0381111562002c75575f80fd5b83016101a0818603121562002c88575f80fd5b946020939093013593505050565b801515811462000ac5575f80fd5b5f805f6060848603121562002cb7575f80fd5b833562002cc4816200282c565b925060208401359150604084013562002cdd8162002c96565b809150509250925092565b5f806040838503121562002cfa575f80fd5b823562002d07816200284e565b915060208301356001600160401b0381111562002d22575f80fd5b62002d308582860162002932565b9150509250929050565b5f806040838503121562002d4c575f80fd5b82359150602083013562002d60816200284e565b809150509250929050565b5f8083601f84011262002d7c575f80fd5b5081356001600160401b0381111562002d93575f80fd5b60208301915083602082850101111562002dab575f80fd5b9250929050565b5f806020838503121562002dc4575f80fd5b82356001600160401b0381111562002dda575f80fd5b62002de88582860162002d6b565b90969095509350505050565b6001600160401b03851681526001600160a01b03841660208201526080604082018190525f9062002e289083018562002adc565b828103606084015262002e3c818562002adc565b979650505050505050565b5f806040838503121562002e59575f80fd5b82359150602083013562002d608162002c96565b5f8083601f84011262002e7e575f80fd5b5081356001600160401b0381111562002e95575f80fd5b6020830191508360208260051b850101111562002dab575f80fd5b5f805f805f805f8060a0898b03121562002ec8575f80fd5b883562002ed5816200284e565b9750602089013562002ee7816200284e565b965060408901356001600160401b038082111562002f03575f80fd5b62002f118c838d0162002e6d565b909850965060608b013591508082111562002f2a575f80fd5b62002f388c838d0162002e6d565b909650945060808b013591508082111562002f51575f80fd5b5062002f608b828c0162002d6b565b999c989b5096995094979396929594505050565b5f806040838503121562002f86575f80fd5b823562002f93816200284e565b9150602083013562002d60816200284e565b5f805f805f8060a0878903121562002fbb575f80fd5b863562002fc8816200284e565b9550602087013562002fda816200284e565b9450604087013593506060870135925060808701356001600160401b0381111562003003575f80fd5b6200301189828a0162002d6b565b979a9699509497509295939492505050565b634e487b7160e01b5f52603260045260245ffd5b81810381811115620005c557634e487b7160e01b5f52601160045260245ffd5b80516001600160801b0381168114620009d1575f80fd5b8051620009d1816200284e565b8051620009d1816200282c565b5f82601f83011262003098575f80fd5b8151620030a9620028b88262002909565b818152846020838601011115620030be575f80fd5b62001db782602083016020870162002ab8565b5f8060408385031215620030e3575f80fd5b8251915060208301516001600160401b038082111562003101575f80fd5b908401906101a0828703121562003116575f80fd5b62003120620027ae565b6200312b8362003057565b81526200313b602084016200306e565b60208201526200314e604084016200307b565b604082015262003161606084016200307b565b606082015262003174608084016200306e565b60808201526200318760a084016200306e565b60a08201526200319a60c084016200306e565b60c0820152620031ad60e084016200306e565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015183811115620031e7575f80fd5b620031f58982870162003088565b82840152505061018080840151838111156200320f575f80fd5b6200321d8982870162003088565b8284015250508093505050509250929050565b5f815180845260208085019450602084015f5b83811015620032615781518752958201959082019060010162003243565b509495945050505050565b6001600160401b03861681526001600160a01b0385811660208301528416604082015260a0606082018190525f90620032a89083018562003230565b8281036080840152620032bc818562003230565b98975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f808335601e1984360301811262003376575f80fd5b8301803591506001600160401b0382111562003390575f80fd5b60200191503681900382131562002dab575f80fd5b5f8085851115620033b4575f80fd5b83861115620033c1575f80fd5b5050820193919092039150565b5f60208284031215620033df575f80fd5b81356001600160401b03811115620033f5575f80fd5b62001db78482850162002932565b5f82601f83011262003413575f80fd5b8151602062003426620028b88362002870565b8083825260208201915060208460051b87010193508684111562003448575f80fd5b602086015b84811015620028fe57805183529183019183016200344d565b5f805f805f60a086880312156200347b575f80fd5b85516001600160401b038082111562003492575f80fd5b908701906080828a031215620034a6575f80fd5b620034b0620027d4565b8251620034bd816200282c565b81526020830151620034cf816200284e565b6020820152604083015182811115620034e6575f80fd5b620034f48b82860162003088565b6040830152506060830151828111156200350c575f80fd5b6200351a8b82860162003088565b606083015250965062003530602089016200306e565b955062003540604089016200306e565b9450606088015191508082111562003556575f80fd5b6200356489838a0162003403565b935060808801519150808211156200357a575f80fd5b50620035898882890162003403565b9150509295509295909350565b6001600160a01b038581168252841660208201526080604082018190525f90620035c39083018562003230565b828103606084015262002e3c818562003230565b5f805f805f60a08688031215620035ec575f80fd5b85356001600160401b038082111562003603575f80fd5b908701906080828a03121562003617575f80fd5b62003621620027d4565b82356200362e816200282c565b8152602083013562003640816200284e565b602082015260408301358281111562003657575f80fd5b620036658b82860162002932565b6040830152506060830135828111156200367d575f80fd5b6200368b8b82860162002932565b6060830152509650620036a16020890162002863565b9550620036b16040890162002863565b94506060880135915080821115620036c7575f80fd5b620036d589838a0162002895565b93506080880135915080821115620036eb575f80fd5b50620035898882890162002895565b600181811c908216806200370f57607f821691505b6020821081036200372e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f6020828403121562003745575f80fd5b815162000c6a8162002c96565b5f6020828403121562003763575f80fd5b81516001600160401b0381111562003779575f80fd5b62001db78482850162003088565b60a080825286516001600160401b03169082015260208601516001600160a01b031660c08201526040860151608060e08301525f90620037cc61012084018262002adc565b90506060880151609f1984830301610100850152620037ec828262002adc565b9150506200380560208401886001600160a01b03169052565b6001600160a01b0386166040840152828103606084015262003828818662003230565b90508281036080840152620032bc818562003230565b602081525f62000c6a602083018462002adc565b5f6020828403121562003863575f80fd5b5051919050565b5f606082840312156200387b575f80fd5b604051606081018181106001600160401b0382111715620038a057620038a06200276e565b604052825181526020830151620038b7816200284e565b60208201526040830151620038cc816200282c565b60408201529392505050565b6001600160a01b0385811682528416602082015260a0604082018190525f90620039059083018562003230565b828103606084015262003919818562003230565b83810360809094019390935250505f8152602001949350505050565b6001600160a01b03841681526060602082018190525f906200395a9083018562003230565b828103604084015262002687818562003230565b5f602082840312156200397f575f80fd5b815162000c6a816200284e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b0387811682528681166020830152851660408201526001600160401b038416606082015260c0608082018190525f9062003a1b9083018562002adc565b82810360a084015262003a2f818562002adc565b9998505050505050505050565b6001600160a01b03831681526040602082018190525f9062000c679083018462002adc565b601f8211156200137057805f5260205f20601f840160051c8101602085101562003a885750805b601f840160051c820191505b8181101562003aa9575f815560010162003a94565b5050505050565b81516001600160401b0381111562003acc5762003acc6200276e565b62003ae48162003add8454620036fa565b8462003a61565b602080601f83116001811462003b1a575f841562003b025750858301515b5f19600386901b1c1916600185901b17855562003b74565b5f85815260208120601f198616915b8281101562003b4a5788860151825594840194600190910190840162003b29565b508582101562003b6857878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f62003b90604083018562002adc565b828103602084015262003ba4818562002adc565b95945050505050565b5f825162003bc081846020870162002ab8565b919091019291505056fe60806040526040516104c43803806104c4833981016040819052610022916102d2565b61002d82825f610034565b50506103e7565b61003d8361005f565b5f825111806100495750805b1561005a57610058838361009e565b505b505050565b610068816100ca565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606100c3838360405180606001604052806027815260200161049d6027913961017d565b9392505050565b6001600160a01b0381163b61013c5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80856001600160a01b031685604051610199919061039a565b5f60405180830381855af49150503d805f81146101d1576040519150601f19603f3d011682016040523d82523d5f602084013e6101d6565b606091505b5090925090506101e8868383876101f2565b9695505050505050565b606083156102605782515f03610259576001600160a01b0385163b6102595760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610133565b508161026a565b61026a8383610272565b949350505050565b8151156102825781518083602001fd5b8060405162461bcd60e51b815260040161013391906103b5565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156102ca5781810151838201526020016102b2565b50505f910152565b5f80604083850312156102e3575f80fd5b82516001600160a01b03811681146102f9575f80fd5b60208401519092506001600160401b0380821115610315575f80fd5b818501915085601f830112610328575f80fd5b81518181111561033a5761033a61029c565b604051601f8201601f19908116603f011681019083821181831017156103625761036261029c565b8160405282815288602084870101111561037a575f80fd5b61038b8360208301602088016102b0565b80955050505050509250929050565b5f82516103ab8184602087016102b0565b9190910192915050565b602081525f82518060208401526103d38160408501602087016102b0565b601f01601f19169190910160400192915050565b60aa806103f35f395ff3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220ba16509e7570dfe3f082a305760ac815a19b24a35621effccf96b2da504ccb7a64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000004" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010096": { + "storage": {}, + "code": "0x6080604052600436106102bf575f3560e01c806370a082311161016f5780639ab24eb0116100d8578063bb86ef9311610092578063dd62ed3e1161006d578063dd62ed3e1461088c578063e30c3978146108ab578063f1127ed8146108c8578063f2fde38b14610911575f80fd5b8063bb86ef931461082f578063c3cda5201461084e578063d505accf1461086d575f80fd5b80639ab24eb0146107755780639dc29fac14610794578063a457c2d7146107b3578063a86f9d9e146107d2578063a9059cbb146107f1578063b8f2e0c514610810575f80fd5b80638456cb59116101295780638456cb59146106e75780638da5cb5b146106fb5780638e539e8c1461070f57806395d89b411461072e5780639711715a14610742578063981b24d014610756575f80fd5b806370a082311461062c578063715018a61461066157806379ba5097146106755780637cf8ed0d146106895780637e474634146106a95780637ecebe00146106c8575f80fd5b80633a46b1a81161022b5780634ee2cd7e116101e5578063587cde1e116101c0578063587cde1e146105815780635c19a95c146105b95780635c975abb146105d85780636fcfff45146105f8575f80fd5b80634ee2cd7e1461053b5780634f1ef2861461055a57806352d1902d1461056d575f80fd5b80633a46b1a8146104955780633ab76e9f146104b45780633eb6b8cf146104d35780633f4ba83a146104f257806340c10f191461050657806349d1260514610525575f80fd5b80632e74eb2d1161027c5780632e74eb2d146103be578063313ce567146103df5780633644e5151461040b5780633659cfe61461041f57806337fbe1121461043e5780633950935114610476575f80fd5b806306fdde03146102c3578063095ea7b3146102ed5780630ae745481461031c57806318160ddd1461033c57806323b872dd1461035b57806326afaadd1461037a575b5f80fd5b3480156102ce575f80fd5b506102d7610930565b6040516102e49190613924565b60405180910390f35b3480156102f8575f80fd5b5061030c61030736600461396a565b61094b565b60405190151581526020016102e4565b348015610327575f80fd5b5060fb5461030c90600160a01b900460ff1681565b348015610347575f80fd5b5061012f545b6040519081526020016102e4565b348015610366575f80fd5b5061030c610375366004613994565b610964565b348015610385575f80fd5b5061039f61022a5461022b546001600160a01b0390911691565b604080516001600160a01b0390931683526020830191909152016102e4565b3480156103c9575f80fd5b506103dd6103d83660046139d2565b610989565b005b3480156103ea575f80fd5b5061022a54600160a01b900460ff1660405160ff90911681526020016102e4565b348015610416575f80fd5b5061034d6109b4565b34801561042a575f80fd5b506103dd6104393660046139d2565b6109bd565b348015610449575f80fd5b5061022c5461045e906001600160a01b031681565b6040516001600160a01b0390911681526020016102e4565b348015610481575f80fd5b5061030c61049036600461396a565b610aa3565b3480156104a0575f80fd5b5061034d6104af36600461396a565b610ac4565b3480156104bf575f80fd5b5060975461045e906001600160a01b031681565b3480156104de575f80fd5b5061045e6104ed3660046139fc565b610b36565b3480156104fd575f80fd5b506103dd610b4a565b348015610511575f80fd5b506103dd61052036600461396a565b610bc9565b348015610530575f80fd5b5061034d61022b5481565b348015610546575f80fd5b5061034d61055536600461396a565b610d13565b6103dd610568366004613aca565b610d6c565b348015610578575f80fd5b5061034d610e37565b34801561058c575f80fd5b5061045e61059b3660046139d2565b6001600160a01b039081165f9081526101f860205260409020541690565b3480156105c4575f80fd5b506103dd6105d33660046139d2565b610ee8565b3480156105e3575f80fd5b5061030c60c954610100900460ff1660021490565b348015610603575f80fd5b506106176106123660046139d2565b610ef2565b60405163ffffffff90911681526020016102e4565b348015610637575f80fd5b5061034d6106463660046139d2565b6001600160a01b03165f90815261012d602052604090205490565b34801561066c575f80fd5b506103dd610f14565b348015610680575f80fd5b506103dd610f25565b348015610694575f80fd5b5061022a5461045e906001600160a01b031681565b3480156106b4575f80fd5b5060fb5461045e906001600160a01b031681565b3480156106d3575f80fd5b5061034d6106e23660046139d2565b610f9c565b3480156106f2575f80fd5b506103dd610fba565b348015610706575f80fd5b5061045e61102b565b34801561071a575f80fd5b5061034d610729366004613b2a565b61103e565b348015610739575f80fd5b506102d761109a565b34801561074d575f80fd5b506103dd6110ac565b348015610761575f80fd5b5061034d610770366004613b2a565b611107565b348015610780575f80fd5b5061034d61078f3660046139d2565b611128565b34801561079f575f80fd5b506103dd6107ae36600461396a565b6111ad565b3480156107be575f80fd5b5061030c6107cd36600461396a565b611348565b3480156107dd575f80fd5b5061045e6107ec366004613b41565b6113cd565b3480156107fc575f80fd5b5061030c61080b36600461396a565b6113d9565b34801561081b575f80fd5b506103dd61082a366004613b6b565b6113e6565b34801561083a575f80fd5b506103dd610849366004613bc3565b61157f565b348015610859575f80fd5b506103dd610868366004613c72565b6116f1565b348015610878575f80fd5b506103dd610887366004613cc8565b611826565b348015610897575f80fd5b5061034d6108a6366004613d31565b611987565b3480156108b6575f80fd5b506065546001600160a01b031661045e565b3480156108d3575f80fd5b506108e76108e2366004613d68565b6119b2565b60408051825163ffffffff1681526020928301516001600160e01b031692810192909252016102e4565b34801561091c575f80fd5b506103dd61092b3660046139d2565b611a34565b606061094661093d611a9a565b61022b54611b2b565b905090565b5f33610958818585611b5f565b60019150505b92915050565b5f33610971858285611c83565b61097c858585611cfb565b60019150505b9392505050565b610991611eb7565b61022c80546001600160a01b0319166001600160a01b0392909216919091179055565b5f610946611f16565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000010096163003610a0e5760405162461bcd60e51b8152600401610a0590613d9c565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000100966001600160a01b0316610a565f80516020614124833981519152546001600160a01b031690565b6001600160a01b031614610a7c5760405162461bcd60e51b8152600401610a0590613de8565b610a8581611f91565b604080515f80825260208201909252610aa091839190611f99565b50565b5f33610958818585610ab58383611987565b610abf9190613e48565b611b5f565b5f438210610b145760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610a05565b6001600160a01b0383165f9081526101f9602052604090206109829083612108565b5f610b428484846121f8565b949350505050565b610b5e60c954610100900460ff1660021490565b610b7b5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610bc733611f91565b565b6002610bd36122e6565b60ff1603610bf45760405163dfc60d8560e01b815260040160405180910390fd5b610bfe600261231f565b610c1260c954610100900460ff1660021490565b15610c305760405163bae6e2a960e01b815260040160405180910390fd5b610c38612361565b15610c565760405163b19aa30f60e01b815260040160405180910390fd5b60fb546001600160a01b03163303610cb15760fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a3610cfb565b610cca6a195c98cc8c17dd985d5b1d60aa1b60016113cd565b6001600160a01b0316336001600160a01b031614610cfb576040516361fad54f60e11b815260040160405180910390fd5b610d05828261238a565b610d0f600161231f565b5050565b6001600160a01b0382165f90815261015f6020526040812081908190610d3a908590612394565b9150915081610d61576001600160a01b0385165f90815261012d6020526040902054610d63565b805b95945050505050565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000010096163003610db45760405162461bcd60e51b8152600401610a0590613d9c565b7f00000000000000000000000001670020000000000000000000000000000100966001600160a01b0316610dfc5f80516020614124833981519152546001600160a01b031690565b6001600160a01b031614610e225760405162461bcd60e51b8152600401610a0590613de8565b610e2b82611f91565b610d0f82826001611f99565b5f306001600160a01b037f00000000000000000000000001670020000000000000000000000000000100961614610ed65760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610a05565b505f8051602061412483398151915290565b610aa03382612484565b6001600160a01b0381165f9081526101f9602052604081205461095e906124ff565b610f1c611eb7565b610bc75f612567565b60655433906001600160a01b03168114610f935760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610a05565b610aa081612567565b6001600160a01b0381165f9081526101c5602052604081205461095e565b610fce60c954610100900460ff1660021490565b15610fec5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610bb6565b5f6109466033546001600160a01b031690565b5f43821061108e5760405162461bcd60e51b815260206004820152601f60248201527f4552433230566f7465733a20626c6f636b206e6f7420796574206d696e6564006044820152606401610a05565b61095e6101fa83612108565b60606109466110a7612580565b612590565b6110b461102b565b6001600160a01b0316336001600160a01b0316141580156110e1575061022c546001600160a01b03163314155b156110ff57604051630b1d89d360e41b815260040160405180910390fd5b610aa06125b9565b5f805f61111684610160612394565b91509150816109825761012f54610b42565b6001600160a01b0381165f9081526101f96020526040812054801561119b576001600160a01b0383165f9081526101f96020526040902061116a600183613e5b565b8154811061117a5761117a613e6e565b5f9182526020909120015464010000000090046001600160e01b031661119d565b5f5b6001600160e01b03169392505050565b60026111b76122e6565b60ff16036111d85760405163dfc60d8560e01b815260040160405180910390fd5b6111e2600261231f565b6111f660c954610100900460ff1660021490565b156112145760405163bae6e2a960e01b815260040160405180910390fd5b61121c612361565b156112f457336001600160a01b0383161461124a576040516361fad54f60e11b815260040160405180910390fd5b60fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a360fb546040516340c10f1960e01b81526001600160a01b03848116600483015260248201849052909116906340c10f19906044015f604051808303815f87803b1580156112d9575f80fd5b505af11580156112eb573d5f803e3d5ffd5b5050505061133e565b61130d6a195c98cc8c17dd985d5b1d60aa1b60016113cd565b6001600160a01b0316336001600160a01b03161461133e57604051630d85cccf60e11b815260040160405180910390fd5b610d058282612612565b5f33816113558286611987565b9050838110156113b55760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610a05565b6113c28286868403611b5f565b506001949350505050565b5f6109824684846121f8565b5f33610958818585611cfb565b60026113f06122e6565b60ff16036114115760405163dfc60d8560e01b815260040160405180910390fd5b61141b600261231f565b61142f60c954610100900460ff1660021490565b1561144d5760405163bae6e2a960e01b815260040160405180910390fd5b6a195c98cc8c17dd985d5b1d60aa1b61146461102b565b6001600160a01b0316336001600160a01b0316141580156114a1575061148b8160016113cd565b6001600160a01b0316336001600160a01b031614155b156114bf57604051630d85cccf60e11b815260040160405180910390fd5b60fb546001600160a01b0384811691161480156114ee575060fb60149054906101000a900460ff161515821515145b1561150c5760405163b253fdfd60e01b815260040160405180910390fd5b60fb80546001600160a01b0385166001600160a81b03199091168117600160a01b851515908102919091179092556040805191825260208201929092527fa6b6f959792843a48d9d03d13595f2de7c86ae0ce12ef0fa759dd911b205e565910160405180910390a150610d0f600161231f565b5f54610100900460ff161580801561159d57505f54600160ff909116105b806115b65750303b1580156115b657505f5460ff166001145b6116195760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610a05565b5f805460ff19166001179055801561163a575f805461ff0019166101001790555b6116468686858561261c565b611650888861266c565b61165a82846126cb565b6116626126fb565b61166a6126fb565b61167382612721565b61022a805461022b87905560ff8616600160a01b026001600160a81b03199091166001600160a01b0389161717905580156116e7575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b834211156117415760405162461bcd60e51b815260206004820152601d60248201527f4552433230566f7465733a207369676e617475726520657870697265640000006044820152606401610a05565b604080517fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60208201526001600160a01b0388169181019190915260608101869052608081018590525f906117ba906117b29060a0016040516020818303038152906040528051906020012061276a565b8585856127b6565b90506117c5816127dc565b86146118135760405162461bcd60e51b815260206004820152601960248201527f4552433230566f7465733a20696e76616c6964206e6f6e6365000000000000006044820152606401610a05565b61181d8188612484565b50505050505050565b834211156118765760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610a05565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886118a48c6127dc565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f6118fe8261276a565b90505f61190d828787876127b6565b9050896001600160a01b0316816001600160a01b0316146119705760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610a05565b61197b8a8a8a611b5f565b50505050505050505050565b6001600160a01b039182165f90815261012e6020908152604080832093909416825291909152205490565b604080518082019091525f80825260208201526001600160a01b0383165f9081526101f960205260409020805463ffffffff84169081106119f5576119f5613e6e565b5f9182526020918290206040805180820190915291015463ffffffff8116825264010000000090046001600160e01b0316918101919091529392505050565b611a3c611eb7565b606580546001600160a01b0319166001600160a01b038316908117909155611a6261102b565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60606101308054611aaa90613e82565b80601f0160208091040260200160405190810160405280929190818152602001828054611ad690613e82565b8015611b215780601f10611af857610100808354040283529160200191611b21565b820191905f5260205f20905b815481529060010190602001808311611b0457829003601f168201915b5050505050905090565b606082611b3783612804565b604051602001611b48929190613eb4565b604051602081830303815290604052905092915050565b6001600160a01b038316611bc15760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a05565b6001600160a01b038216611c225760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a05565b6001600160a01b038381165f81815261012e602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f611c8e8484611987565b90505f198114611cf55781811015611ce85760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a05565b611cf58484848403611b5f565b50505050565b6001600160a01b038316611d5f5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a05565b6001600160a01b038216611dc15760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a05565b611dcc838383612894565b6001600160a01b0383165f90815261012d602052604090205481811015611e445760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610a05565b6001600160a01b038085165f81815261012d602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611ea49086815260200190565b60405180910390a3611cf58484846128fa565b33611ec061102b565b6001600160a01b031614610bc75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a05565b5f6109467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f611f456101915490565b610192546040805160208101859052908101839052606081018290524660808201523060a08201525f9060c0016040516020818303038152906040528051906020012090509392505050565b610aa0611eb7565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611fd157611fcc83612905565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561202b575060408051601f3d908101601f1916820190925261202891810190613f14565b60015b61208e5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610a05565b5f8051602061412483398151915281146120fc5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610a05565b50611fcc8383836129a0565b81545f908181600581111561215f575f612121846129c4565b61212b9085613e5b565b5f88815260209020909150869082015463ffffffff16111561214f5780915061215d565b61215a816001613e48565b92505b505b808210156121aa575f6121728383612aa8565b5f88815260209020909150869082015463ffffffff161115612196578091506121a4565b6121a1816001613e48565b92505b5061215f565b80156121e3576121cc866121bf600184613e5b565b5f91825260209091200190565b5464010000000090046001600160e01b03166121e5565b5f5b6001600160e01b03169695505050505050565b6097545f906001600160a01b031661222357604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801561227a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061229e9190613f2b565b9050811580156122b557506001600160a01b038116155b1561098257604051632b0d65db60e01b815267ffffffffffffffff8516600482015260248101849052604401610a05565b5f4660010361231557507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361234d57807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b60fb545f906001600160a01b03161580159061094657505060fb54600160a01b900460ff161590565b610d0f8282612ac2565b5f805f84116123de5760405162461bcd60e51b815260206004820152601660248201527504552433230536e617073686f743a20696420697320360541b6044820152606401610a05565b6123e6612acc565b8411156124355760405162461bcd60e51b815260206004820152601d60248201527f4552433230536e617073686f743a206e6f6e6578697374656e742069640000006044820152606401610a05565b5f6124408486612ad7565b84549091508103612457575f80925092505061247d565b600184600101828154811061246e5761246e613e6e565b905f5260205f20015492509250505b9250929050565b6001600160a01b038281165f8181526101f860208181526040808420805461012d845282862054949093528787166001600160a01b03198416811790915590519190951694919391928592917f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611cf5828483612b70565b5f63ffffffff8211156125635760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201526532206269747360d01b6064820152608401610a05565b5090565b606580546001600160a01b0319169055610aa081612cac565b60606101318054611aaa90613e82565b6060816040516020016125a39190613f46565b6040516020818303038152906040529050919050565b5f6125c961016280546001019055565b5f6125d2612acc565b90507f8030e83b04d87bef53480e26263266d6ca66863aa8506aca6f2559d18aa1cb678160405161260591815260200190565b60405180910390a1919050565b610d0f8282612cfd565b6001600160a01b0384161580612630575082155b8061263a57504683145b8061264457508151155b8061264e57508051155b15611cf55760405163c118d2f360e01b815260040160405180910390fd5b5f54610100900460ff166126925760405162461bcd60e51b8152600401610a0590613f6b565b61269b82612d07565b6001600160a01b0381166126c2576040516375cabfef60e11b815260040160405180910390fd5b610d0f81612d37565b5f54610100900460ff166126f15760405162461bcd60e51b8152600401610a0590613f6b565b610d0f8282612da8565b5f54610100900460ff16610bc75760405162461bcd60e51b8152600401610a0590613f6b565b5f54610100900460ff166127475760405162461bcd60e51b8152600401610a0590613f6b565b610aa081604051806040016040528060018152602001603160f81b815250612de9565b5f61095e612776611f16565b8360405161190160f01b602082015260228101839052604281018290525f9060620160405160208183030381529060405280519060200120905092915050565b5f805f6127c587878787612e2b565b915091506127d281612ee8565b5095945050505050565b6001600160a01b0381165f9081526101c5602052604090208054600181018255905b50919050565b60605f61281083613031565b60010190505f8167ffffffffffffffff81111561282f5761282f613a43565b6040519080825280601f01601f191660200182016040528015612859576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461286357509392505050565b306001600160a01b038316036128bd57604051630183150560e21b815260040160405180910390fd5b6128d160c954610100900460ff1660021490565b156128ef5760405163bae6e2a960e01b815260040160405180910390fd5b611fcc838383613108565b611fcc838383613150565b6001600160a01b0381163b6129725760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610a05565b5f8051602061412483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6129a983613182565b5f825111806129b55750805b15611fcc57611cf583836131c1565b5f815f036129d357505f919050565b5f60016129df846131e6565b901c6001901b905060018184816129f8576129f8613fb6565b048201901c90506001818481612a1057612a10613fb6565b048201901c90506001818481612a2857612a28613fb6565b048201901c90506001818481612a4057612a40613fb6565b048201901c90506001818481612a5857612a58613fb6565b048201901c90506001818481612a7057612a70613fb6565b048201901c90506001818481612a8857612a88613fb6565b048201901c905061098281828581612aa257612aa2613fb6565b04613279565b5f612ab66002848418613fca565b61098290848416613e48565b610d0f828261328e565b5f6109466101625490565b81545f908103612ae857505f61095e565b82545f905b80821015612b32575f612b008383612aa8565b5f8781526020902090915085908201541115612b1e57809150612b2c565b612b29816001613e48565b92505b50612aed565b5f82118015612b4f575083612b4c866121bf600186613e5b565b54145b15612b6857612b5f600183613e5b565b9250505061095e565b50905061095e565b816001600160a01b0316836001600160a01b031614158015612b9157505f81115b15611fcc576001600160a01b03831615612c1f576001600160a01b0383165f9081526101f9602052604081208190612bcc9061331a85613325565b91509150846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612c14929190918252602082015260400190565b60405180910390a250505b6001600160a01b03821615611fcc576001600160a01b0382165f9081526101f9602052604081208190612c559061347585613325565b91509150836001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248383604051612c9d929190918252602082015260400190565b60405180910390a25050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610d0f8282613480565b612d256001600160a01b03821615612d1f5781612567565b33612567565b5060c9805461ff001916610100179055565b5f54610100900460ff16612d5d5760405162461bcd60e51b8152600401610a0590613f6b565b67ffffffffffffffff461115612d865760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f54610100900460ff16612dce5760405162461bcd60e51b8152600401610a0590613f6b565b610130612ddb8382614034565b50610131611fcc8282614034565b5f54610100900460ff16612e0f5760405162461bcd60e51b8152600401610a0590613f6b565b8151602092830120815191909201206101919190915561019255565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612e6057505f90506003612edf565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015612eb1573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612ed9575f60019250925050612edf565b91505f90505b94509492505050565b5f816004811115612efb57612efb6140f4565b03612f035750565b6001816004811115612f1757612f176140f4565b03612f645760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610a05565b6002816004811115612f7857612f786140f4565b03612fc55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610a05565b6003816004811115612fd957612fd96140f4565b03610aa05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610a05565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061306f5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061309b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106130b957662386f26fc10000830492506010015b6305f5e10083106130d1576305f5e100830492506008015b61271083106130e557612710830492506004015b606483106130f7576064830492506002015b600a831061095e5760010192915050565b6001600160a01b0383166131275761311f82613499565b611fcc6134cd565b6001600160a01b03821661313e5761311f83613499565b61314783613499565b611fcc82613499565b6001600160a01b038381165f9081526101f86020526040808220548584168352912054611fcc92918216911683612b70565b61318b81612905565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606109828383604051806060016040528060278152602001614144602791396134dd565b5f80608083901c156131fa57608092831c92015b604083901c1561320c57604092831c92015b602083901c1561321e57602092831c92015b601083901c1561323057601092831c92015b600883901c1561324257600892831c92015b600483901c1561325457600492831c92015b600283901c1561326657600292831c92015b600183901c1561095e5760010192915050565b5f8183106132875781610982565b5090919050565b6132988282613551565b61012f546001600160e01b03101561330b5760405162461bcd60e51b815260206004820152603060248201527f4552433230566f7465733a20746f74616c20737570706c79207269736b73206f60448201526f766572666c6f77696e6720766f74657360801b6064820152608401610a05565b611cf56101fa61347583613325565b5f6109828284613e5b565b82545f90819081811561337157613341876121bf600185613e5b565b60408051808201909152905463ffffffff8116825264010000000090046001600160e01b03166020820152613385565b604080518082019091525f80825260208201525b905080602001516001600160e01b031693506133a584868863ffffffff16565b92505f821180156133bc5750805163ffffffff1643145b15613401576133ca83613624565b6133d9886121bf600186613e5b565b80546001600160e01b03929092166401000000000263ffffffff90921691909117905561346b565b866040518060400160405280613416436124ff565b63ffffffff16815260200161342a86613624565b6001600160e01b0390811690915282546001810184555f938452602093849020835194909301519091166401000000000263ffffffff909316929092179101555b5050935093915050565b5f6109828284613e48565b61348a828261368c565b611cf56101fa61331a83613325565b6001600160a01b0381165f90815261015f6020908152604080832061012d90925290912054610aa091906137d2565b6137d2565b610bc76101606134c861012f5490565b60605f80856001600160a01b0316856040516134f99190614108565b5f60405180830381855af49150503d805f8114613531576040519150601f19603f3d011682016040523d82523d5f602084013e613536565b606091505b50915091506135478683838761381a565b9695505050505050565b6001600160a01b0382166135a75760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a05565b6135b25f8383612894565b8061012f5f8282546135c49190613e48565b90915550506001600160a01b0382165f81815261012d60209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610d0f5f83836128fa565b5f6001600160e01b038211156125635760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20326044820152663234206269747360c81b6064820152608401610a05565b6001600160a01b0382166136ec5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a05565b6136f7825f83612894565b6001600160a01b0382165f90815261012d60205260409020548181101561376b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a05565b6001600160a01b0383165f81815261012d60209081526040808320868603905561012f80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611fcc835f846128fa565b5f6137db612acc565b9050806137e784613892565b1015611fcc578254600180820185555f858152602080822090930193909355938401805494850181558252902090910155565b606083156138885782515f03613881576001600160a01b0385163b6138815760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a05565b5081610b42565b610b4283836138d8565b80545f9081036138a357505f919050565b815482906138b390600190613e5b565b815481106138c3576138c3613e6e565b905f5260205f2001549050919050565b919050565b8151156138e85781518083602001fd5b8060405162461bcd60e51b8152600401610a059190613924565b5f5b8381101561391c578181015183820152602001613904565b50505f910152565b602081525f8251806020840152613942816040850160208701613902565b601f01601f19169190910160400192915050565b6001600160a01b0381168114610aa0575f80fd5b5f806040838503121561397b575f80fd5b823561398681613956565b946020939093013593505050565b5f805f606084860312156139a6575f80fd5b83356139b181613956565b925060208401356139c181613956565b929592945050506040919091013590565b5f602082840312156139e2575f80fd5b813561098281613956565b803580151581146138d3575f80fd5b5f805f60608486031215613a0e575f80fd5b833567ffffffffffffffff81168114613a25575f80fd5b925060208401359150613a3a604085016139ed565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f67ffffffffffffffff80841115613a7157613a71613a43565b604051601f8501601f19908116603f01168101908282118183101715613a9957613a99613a43565b81604052809350858152868686011115613ab1575f80fd5b858560208301375f602087830101525050509392505050565b5f8060408385031215613adb575f80fd5b8235613ae681613956565b9150602083013567ffffffffffffffff811115613b01575f80fd5b8301601f81018513613b11575f80fd5b613b2085823560208401613a57565b9150509250929050565b5f60208284031215613b3a575f80fd5b5035919050565b5f8060408385031215613b52575f80fd5b82359150613b62602084016139ed565b90509250929050565b5f8060408385031215613b7c575f80fd5b8235613b8781613956565b9150613b62602084016139ed565b803560ff811681146138d3575f80fd5b5f82601f830112613bb4575f80fd5b61098283833560208501613a57565b5f805f805f805f60e0888a031215613bd9575f80fd5b8735613be481613956565b96506020880135613bf481613956565b95506040880135613c0481613956565b945060608801359350613c1960808901613b95565b925060a088013567ffffffffffffffff80821115613c35575f80fd5b613c418b838c01613ba5565b935060c08a0135915080821115613c56575f80fd5b50613c638a828b01613ba5565b91505092959891949750929550565b5f805f805f8060c08789031215613c87575f80fd5b8635613c9281613956565b95506020870135945060408701359350613cae60608801613b95565b92506080870135915060a087013590509295509295509295565b5f805f805f805f60e0888a031215613cde575f80fd5b8735613ce981613956565b96506020880135613cf981613956565b95506040880135945060608801359350613d1560808901613b95565b925060a0880135915060c0880135905092959891949750929550565b5f8060408385031215613d42575f80fd5b8235613d4d81613956565b91506020830135613d5d81613956565b809150509250929050565b5f8060408385031215613d79575f80fd5b8235613d8481613956565b9150602083013563ffffffff81168114613d5d575f80fd5b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561095e5761095e613e34565b8181038181111561095e5761095e613e34565b634e487b7160e01b5f52603260045260245ffd5b600181811c90821680613e9657607f821691505b6020821081036127fe57634e487b7160e01b5f52602260045260245ffd5b670213934b233b2b2160c51b81525f8351613ed6816008850160208801613902565b634051c55b60df1b6008918401918201528351613efa81600d840160208801613902565b602960f81b600d9290910191820152600e01949350505050565b5f60208284031215613f24575f80fd5b5051919050565b5f60208284031215613f3b575f80fd5b815161098281613956565b5f8251613f57818460208701613902565b610b9d60f21b920191825250600201919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b5f52601260045260245ffd5b5f82613fe457634e487b7160e01b5f52601260045260245ffd5b500490565b601f821115611fcc57805f5260205f20601f840160051c8101602085101561400e5750805b601f840160051c820191505b8181101561402d575f815560010161401a565b5050505050565b815167ffffffffffffffff81111561404e5761404e613a43565b6140628161405c8454613e82565b84613fe9565b602080601f831160018114614095575f841561407e5750858301515b5f19600386901b1c1916600185901b1785556140ec565b5f85815260208120601f198616915b828110156140c3578886015182559484019460019091019084016140a4565b50858210156140e057878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b634e487b7160e01b5f52602160045260245ffd5b5f8251614119818460208701613902565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212207e373db0be4a6e756668501d4c4e0826cd14a846b891fa07cb5482cc0b477bdd64736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010097": { + "storage": {}, + "code": "0x6080604052600436106101e6575f3560e01c806367e828bf116101085780639dc29fac1161009d578063c87b56dd1161006d578063c87b56dd1461055b578063e30c39781461057a578063e985e9c514610597578063ef8c4ae6146105df578063f2fde38b146105fe575f80fd5b80639dc29fac146104df578063a22cb465146104fe578063a86f9d9e1461051d578063b88d4fde1461053c575f80fd5b80637cf8ed0d116100d85780637cf8ed0d1461047a5780638456cb591461049a5780638da5cb5b146104ae57806395d89b41146104cb575f80fd5b806367e828bf146103ef57806370a0823114610433578063715018a61461045257806379ba509714610466575f80fd5b80633f4ba83a1161017e5780634f1ef2861161014e5780634f1ef2861461038957806352d1902d1461039c5780635c975abb146103b05780636352211e146103d0575f80fd5b80633f4ba83a1461031357806340c10f191461032757806342842e0e1461034657806349d1260514610365575f80fd5b806323b872dd116101b957806323b872dd146102975780633659cfe6146102b65780633ab76e9f146102d55780633eb6b8cf146102f4575f80fd5b806301ffc9a7146101ea57806306fdde031461021e578063081812fc1461023f578063095ea7b314610276575b5f80fd5b3480156101f5575f80fd5b50610209610204366004612468565b61061d565b60405190151581526020015b60405180910390f35b348015610229575f80fd5b5061023261066e565b60405161021591906124d0565b34801561024a575f80fd5b5061025e6102593660046124e2565b610689565b6040516001600160a01b039091168152602001610215565b348015610281575f80fd5b5061029561029036600461250d565b6106af565b005b3480156102a2575f80fd5b506102956102b1366004612537565b6107c8565b3480156102c1575f80fd5b506102956102d0366004612575565b6107f9565b3480156102e0575f80fd5b5060975461025e906001600160a01b031681565b3480156102ff575f80fd5b5061025e61030e3660046125a4565b6108d6565b34801561031e575f80fd5b506102956108ec565b348015610332575f80fd5b5061029561034136600461250d565b61096b565b348015610351575f80fd5b50610295610360366004612537565b610a37565b348015610370575f80fd5b5061037b6101605481565b604051908152602001610215565b610295610397366004612688565b610a51565b3480156103a7575f80fd5b5061037b610b1c565b3480156103bb575f80fd5b5061020960c954610100900460ff1660021490565b3480156103db575f80fd5b5061025e6103ea3660046124e2565b610bcd565b3480156103fa575f80fd5b5061041461015f54610160546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610215565b34801561043e575f80fd5b5061037b61044d366004612575565b610c2d565b34801561045d575f80fd5b50610295610cb2565b348015610471575f80fd5b50610295610cc3565b348015610485575f80fd5b5061015f5461025e906001600160a01b031681565b3480156104a5575f80fd5b50610295610d3a565b3480156104b9575f80fd5b506033546001600160a01b031661025e565b3480156104d6575f80fd5b50610232610dab565b3480156104ea575f80fd5b506102956104f936600461250d565b610dbd565b348015610509575f80fd5b506102956105183660046126d5565b610eb3565b348015610528575f80fd5b5061025e610537366004612708565b610ebe565b348015610547575f80fd5b50610295610556366004612729565b610eca565b348015610566575f80fd5b506102326105753660046124e2565b610f02565b348015610585575f80fd5b506065546001600160a01b031661025e565b3480156105a2575f80fd5b506102096105b1366004612791565b6001600160a01b039182165f9081526101326020908152604080832093909416825291909152205460ff1690565b3480156105ea575f80fd5b506102956105f93660046127c8565b610f52565b348015610609575f80fd5b50610295610618366004612575565b61109d565b5f6001600160e01b031982166380ac58cd60e01b148061064d57506001600160e01b03198216635b5e139f60e01b145b8061066857506301ffc9a760e01b6001600160e01b03198316145b92915050565b606061068461067b61110e565b6101605461119f565b905090565b5f610693826111d3565b505f90815261013160205260409020546001600160a01b031690565b5f6106b982610bcd565b9050806001600160a01b0316836001600160a01b03160361072b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610747575061074781336105b1565b6107b95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610722565b6107c38383611232565b505050565b6107d233826112a0565b6107ee5760405162461bcd60e51b815260040161072290612866565b6107c383838361131e565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000100971630036108415760405162461bcd60e51b8152600401610722906128b3565b7f00000000000000000000000001670020000000000000000000000000000100976001600160a01b03166108895f80516020612d94833981519152546001600160a01b031690565b6001600160a01b0316146108af5760405162461bcd60e51b8152600401610722906128ff565b6108b881611490565b604080515f808252602082019092526108d391839190611498565b50565b5f6108e2848484611602565b90505b9392505050565b61090060c954610100900460ff1660021490565b61091d5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a161096933611490565b565b60026109756116f0565b60ff16036109965760405163dfc60d8560e01b815260040160405180910390fd5b6109a06002611729565b6109b460c954610100900460ff1660021490565b156109d25760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b6109ed816001610ebe565b6001600160a01b0316336001600160a01b031614610a1e57604051630d85cccf60e11b815260040160405180910390fd5b610a28838361176b565b50610a336001611729565b5050565b6107c383838360405180602001604052805f815250610eca565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000010097163003610a995760405162461bcd60e51b8152600401610722906128b3565b7f00000000000000000000000001670020000000000000000000000000000100976001600160a01b0316610ae15f80516020612d94833981519152546001600160a01b031690565b6001600160a01b031614610b075760405162461bcd60e51b8152600401610722906128ff565b610b1082611490565b610a3382826001611498565b5f306001600160a01b037f00000000000000000000000001670020000000000000000000000000000100971614610bbb5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610722565b505f80516020612d9483398151915290565b5f81815261012f60205260408120546001600160a01b0316806106685760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610722565b5f6001600160a01b038216610c965760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610722565b506001600160a01b03165f908152610130602052604090205490565b610cba611784565b6109695f6117de565b60655433906001600160a01b03168114610d315760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610722565b6108d3816117de565b610d4e60c954610100900460ff1660021490565b15610d6c5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610958565b6060610684610db86117f7565b611807565b6002610dc76116f0565b60ff1603610de85760405163dfc60d8560e01b815260040160405180910390fd5b610df26002611729565b610e0660c954610100900460ff1660021490565b15610e245760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b610e3f816001610ebe565b6001600160a01b0316336001600160a01b031614610e7057604051630d85cccf60e11b815260040160405180910390fd5b826001600160a01b0316610e8383610bcd565b6001600160a01b031614610eaa5760405163358bf3d960e01b815260040160405180910390fd5b610a288261181a565b610a333383836118bc565b5f6108e5468484611602565b610ed433836112a0565b610ef05760405162461bcd60e51b815260040161072290612866565b610efc8484848461198a565b50505050565b61015f5461016054606091610f22916001600160a01b03909116906119bd565b610f2b836119ed565b604051602001610f3c92919061294b565b6040516020818303038152906040529050919050565b5f54610100900460ff1615808015610f7057505f54600160ff909116105b80610f895750303b158015610f8957505f5460ff166001145b610fec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610722565b5f805460ff19166001179055801561100d575f805461ff0019166101001790555b61101985858585611a7d565b6110238787611acd565b61102d8284611b2c565b61015f80546001600160a01b0319166001600160a01b0387161790556101608490558015611094575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6110a5611784565b606580546001600160a01b0383166001600160a01b031990911681179091556110d66033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b606061012d805461111e90612979565b80601f016020809104026020016040519081016040528092919081815260200182805461114a90612979565b80156111955780601f1061116c57610100808354040283529160200191611195565b820191905f5260205f20905b81548152906001019060200180831161117857829003601f168201915b5050505050905090565b6060826111ab836119ed565b6040516020016111bc9291906129b1565b604051602081830303815290604052905092915050565b5f81815261012f60205260409020546001600160a01b03166108d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610722565b5f8181526101316020526040902080546001600160a01b0319166001600160a01b038416908117909155819061126782610bcd565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b5f806112ab83610bcd565b9050806001600160a01b0316846001600160a01b031614806112f257506001600160a01b038082165f908152610132602090815260408083209388168352929052205460ff165b806113165750836001600160a01b031661130b84610689565b6001600160a01b0316145b949350505050565b826001600160a01b031661133182610bcd565b6001600160a01b0316146113575760405162461bcd60e51b815260040161072290612a11565b6001600160a01b0382166113b95760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610722565b6113c68383836001611b5c565b826001600160a01b03166113d982610bcd565b6001600160a01b0316146113ff5760405162461bcd60e51b815260040161072290612a11565b5f8181526101316020908152604080832080546001600160a01b03199081169091556001600160a01b03878116808652610130855283862080545f190190559087168086528386208054600101905586865261012f90945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6108d3611784565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156114cb576107c383611bb7565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611525575060408051601f3d908101601f1916820190925261152291810190612a56565b60015b6115885760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610722565b5f80516020612d9483398151915281146115f65760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610722565b506107c3838383611c52565b6097545f906001600160a01b031661162d57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611684573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116a89190612a6d565b9050811580156116bf57506001600160a01b038116155b156108e557604051632b0d65db60e01b815267ffffffffffffffff8516600482015260248101849052604401610722565b5f4660010361171f57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361175757807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b610a33828260405180602001604052805f815250611c76565b6033546001600160a01b031633146109695760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610722565b606580546001600160a01b03191690556108d381611ca8565b606061012e805461111e90612979565b606081604051602001610f3c9190612a88565b5f61182482610bcd565b9050611833815f846001611b5c565b61183c82610bcd565b5f8381526101316020908152604080832080546001600160a01b03199081169091556001600160a01b038516808552610130845282852080545f1901905587855261012f909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b816001600160a01b0316836001600160a01b03160361191d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610722565b6001600160a01b038381165f8181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61199584848461131e565b6119a184848484611cf9565b610efc5760405162461bcd60e51b815260040161072290612aad565b60606119d3836001600160a01b03166014611df6565b6119dc836119ed565b6040516020016111bc929190612aff565b60605f6119f983611f8c565b60010190505f8167ffffffffffffffff811115611a1857611a186125eb565b6040519080825280601f01601f191660200182016040528015611a42576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611a4c57509392505050565b6001600160a01b0384161580611a91575082155b80611a9b57504683145b80611aa557508151155b80611aaf57508051155b15610efc5760405163c118d2f360e01b815260040160405180910390fd5b5f54610100900460ff16611af35760405162461bcd60e51b815260040161072290612b6e565b611afc82612063565b6001600160a01b038116611b23576040516375cabfef60e11b815260040160405180910390fd5b610a3381612093565b5f54610100900460ff16611b525760405162461bcd60e51b815260040161072290612b6e565b610a338282612104565b306001600160a01b03841603611b8557604051630183150560e21b815260040160405180910390fd5b611b9960c954610100900460ff1660021490565b15610efc5760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0381163b611c245760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610722565b5f80516020612d9483398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611c5b83612145565b5f82511180611c675750805b156107c357610efc8383612184565b611c8083836121a9565b611c8c5f848484611cf9565b6107c35760405162461bcd60e51b815260040161072290612aad565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f6001600160a01b0384163b15611deb57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611d3c903390899088908890600401612bb9565b6020604051808303815f875af1925050508015611d76575060408051601f3d908101601f19168201909252611d7391810190612beb565b60015b611dd1573d808015611da3576040519150601f19603f3d011682016040523d82523d5f602084013e611da8565b606091505b5080515f03611dc95760405162461bcd60e51b815260040161072290612aad565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611316565b506001949350505050565b60605f611e04836002612c1a565b611e0f906002612c31565b67ffffffffffffffff811115611e2757611e276125eb565b6040519080825280601f01601f191660200182016040528015611e51576020820181803683370190505b509050600360fc1b815f81518110611e6b57611e6b612c44565b60200101906001600160f81b03191690815f1a905350600f60fb1b81600181518110611e9957611e99612c44565b60200101906001600160f81b03191690815f1a9053505f611ebb846002612c1a565b611ec6906001612c31565b90505b6001811115611f3d576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110611efa57611efa612c44565b1a60f81b828281518110611f1057611f10612c44565b60200101906001600160f81b03191690815f1a90535060049490941c93611f3681612c58565b9050611ec9565b5083156108e55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610722565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611fca5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611ff6576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061201457662386f26fc10000830492506010015b6305f5e100831061202c576305f5e100830492506008015b612710831061204057612710830492506004015b60648310612052576064830492506002015b600a83106106685760010192915050565b6120816001600160a01b0382161561207b57816117de565b336117de565b5060c9805461ff001916610100179055565b5f54610100900460ff166120b95760405162461bcd60e51b815260040161072290612b6e565b67ffffffffffffffff4611156120e25760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f54610100900460ff1661212a5760405162461bcd60e51b815260040161072290612b6e565b61012d6121378382612cb8565b5061012e6107c38282612cb8565b61214e81611bb7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606108e58383604051806060016040528060278152602001612db460279139612342565b6001600160a01b0382166121ff5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610722565b5f81815261012f60205260409020546001600160a01b0316156122645760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610722565b6122715f83836001611b5c565b5f81815261012f60205260409020546001600160a01b0316156122d65760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610722565b6001600160a01b0382165f818152610130602090815260408083208054600101905584835261012f90915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60605f80856001600160a01b03168560405161235e9190612d78565b5f60405180830381855af49150503d805f8114612396576040519150601f19603f3d011682016040523d82523d5f602084013e61239b565b606091505b50915091506123ac868383876123b6565b9695505050505050565b606083156124245782515f0361241d576001600160a01b0385163b61241d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610722565b5081611316565b61131683838151156124395781518083602001fd5b8060405162461bcd60e51b815260040161072291906124d0565b6001600160e01b0319811681146108d3575f80fd5b5f60208284031215612478575f80fd5b81356108e581612453565b5f5b8381101561249d578181015183820152602001612485565b50505f910152565b5f81518084526124bc816020860160208601612483565b601f01601f19169290920160200192915050565b602081525f6108e560208301846124a5565b5f602082840312156124f2575f80fd5b5035919050565b6001600160a01b03811681146108d3575f80fd5b5f806040838503121561251e575f80fd5b8235612529816124f9565b946020939093013593505050565b5f805f60608486031215612549575f80fd5b8335612554816124f9565b92506020840135612564816124f9565b929592945050506040919091013590565b5f60208284031215612585575f80fd5b81356108e5816124f9565b8035801515811461259f575f80fd5b919050565b5f805f606084860312156125b6575f80fd5b833567ffffffffffffffff811681146125cd575f80fd5b9250602084013591506125e260408501612590565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f83011261260e575f80fd5b813567ffffffffffffffff80821115612629576126296125eb565b604051601f8301601f19908116603f01168101908282118183101715612651576126516125eb565b81604052838152866020858801011115612669575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215612699575f80fd5b82356126a4816124f9565b9150602083013567ffffffffffffffff8111156126bf575f80fd5b6126cb858286016125ff565b9150509250929050565b5f80604083850312156126e6575f80fd5b82356126f1816124f9565b91506126ff60208401612590565b90509250929050565b5f8060408385031215612719575f80fd5b823591506126ff60208401612590565b5f805f806080858703121561273c575f80fd5b8435612747816124f9565b93506020850135612757816124f9565b925060408501359150606085013567ffffffffffffffff811115612779575f80fd5b612785878288016125ff565b91505092959194509250565b5f80604083850312156127a2575f80fd5b82356127ad816124f9565b915060208301356127bd816124f9565b809150509250929050565b5f805f805f8060c087890312156127dd575f80fd5b86356127e8816124f9565b955060208701356127f8816124f9565b94506040870135612808816124f9565b935060608701359250608087013567ffffffffffffffff8082111561282b575f80fd5b6128378a838b016125ff565b935060a089013591508082111561284c575f80fd5b5061285989828a016125ff565b9150509295509295509295565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f835161295c818460208801612483565b835190830190612970818360208801612483565b01949350505050565b600181811c9082168061298d57607f821691505b6020821081036129ab57634e487b7160e01b5f52602260045260245ffd5b50919050565b670213934b233b2b2160c51b81525f83516129d3816008850160208801612483565b634051c55b60df1b60089184019182015283516129f781600d840160208801612483565b602960f81b600d9290910191820152600e01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b5f60208284031215612a66575f80fd5b5051919050565b5f60208284031215612a7d575f80fd5b81516108e5816124f9565b5f8251612a99818460208701612483565b610b9d60f21b920191825250600201919050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6832ba3432b932bab69d60b91b81525f8351612b22816009850160208801612483565b600160fe1b6009918401918201528351612b4381600a840160208801612483565b712f746f6b656e5552493f75696e743235363d60701b600a9290910191820152601c01949350505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03858116825284166020820152604081018390526080606082018190525f906123ac908301846124a5565b5f60208284031215612bfb575f80fd5b81516108e581612453565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761066857610668612c06565b8082018082111561066857610668612c06565b634e487b7160e01b5f52603260045260245ffd5b5f81612c6657612c66612c06565b505f190190565b601f8211156107c357805f5260205f20601f840160051c81016020851015612c925750805b601f840160051c820191505b81811015612cb1575f8155600101612c9e565b5050505050565b815167ffffffffffffffff811115612cd257612cd26125eb565b612ce681612ce08454612979565b84612c6d565b602080601f831160018114612d19575f8415612d025750858301515b5f19600386901b1c1916600185901b178555612d70565b5f85815260208120601f198616915b82811015612d4757888601518255948401946001909101908401612d28565b5085821015612d6457878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8251612d89818460208701612483565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c4486d9ca4840f96f11ee225b65f721fee7c79fc3710037edf9cc01522aac1a664736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010098": { + "storage": {}, + "code": "0x6080604052600436106101c4575f3560e01c8063715018a6116100f2578063a86f9d9e11610092578063ef8c4ae611610062578063ef8c4ae61461050a578063f242432a14610529578063f2fde38b14610548578063f5298aca14610567575f80fd5b8063a86f9d9e14610467578063d81d0a1514610486578063e30c3978146104a5578063e985e9c5146104c2575f80fd5b80638456cb59116100cd5780638456cb59146104035780638da5cb5b1461041757806395d89b4114610434578063a22cb46514610448575f80fd5b8063715018a6146103bb57806379ba5097146103cf5780637cf8ed0d146103e3575f80fd5b80633ab76e9f116101685780634e1273f4116101385780634e1273f4146103485780634f1ef2861461037457806352d1902d146103875780635c975abb1461039b575f80fd5b80633ab76e9f146102c85780633eb6b8cf146102ff5780633f4ba83a1461031e57806349d1260514610332575f80fd5b80630e89341c116101a35780630e89341c1461024a578063156e29f6146102695780632eb2c2d61461028a5780633659cfe6146102a9575f80fd5b8062fdd58e146101c857806301ffc9a7146101fa57806306fdde0314610229575b5f80fd5b3480156101d3575f80fd5b506101e76101e23660046127b0565b610586565b6040519081526020015b60405180910390f35b348015610205575f80fd5b506102196102143660046127ef565b610620565b60405190151581526020016101f1565b348015610234575f80fd5b5061023d61066f565b6040516101f19190612857565b348015610255575f80fd5b5061023d610264366004612869565b61070c565b348015610274575f80fd5b50610288610283366004612880565b61079f565b005b348015610295575f80fd5b506102886102a43660046129f6565b61087d565b3480156102b4575f80fd5b506102886102c3366004612a9c565b6108c9565b3480156102d3575f80fd5b506097546102e7906001600160a01b031681565b6040516001600160a01b0390911681526020016101f1565b34801561030a575f80fd5b506102e7610319366004612acb565b6109a6565b348015610329575f80fd5b506102886109bc565b34801561033d575f80fd5b506101e76101605481565b348015610353575f80fd5b50610367610362366004612b11565b610a3b565b6040516101f19190612c11565b610288610382366004612c23565b610b5a565b348015610392575f80fd5b506101e7610c29565b3480156103a6575f80fd5b5061021960c954610100900460ff1660021490565b3480156103c6575f80fd5b50610288610cdb565b3480156103da575f80fd5b50610288610cec565b3480156103ee575f80fd5b5061015f546102e7906001600160a01b031681565b34801561040e575f80fd5b50610288610d63565b348015610422575f80fd5b506033546001600160a01b03166102e7565b34801561043f575f80fd5b5061023d610dd4565b348015610453575f80fd5b50610288610462366004612c65565b610e68565b348015610472575f80fd5b506102e7610481366004612c98565b610e73565b348015610491575f80fd5b506102886104a0366004612cb9565b610e7f565b3480156104b0575f80fd5b506065546001600160a01b03166102e7565b3480156104cd575f80fd5b506102196104dc366004612d29565b6001600160a01b039182165f90815261012e6020908152604080832093909416825291909152205460ff1690565b348015610515575f80fd5b50610288610524366004612d60565b610f4d565b348015610534575f80fd5b50610288610543366004612dfd565b6110f2565b348015610553575f80fd5b50610288610562366004612a9c565b611137565b348015610572575f80fd5b50610288610581366004612880565b6111a8565b5f6001600160a01b0383166105f55760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b505f81815261012d602090815260408083206001600160a01b03861684529091529020545b92915050565b5f6001600160e01b03198216636cdb3d1360e11b148061065057506001600160e01b031982166303a24d0760e21b145b8061061a57506301ffc9a760e01b6001600160e01b031983161461061a565b6060610707610162805461068290612e60565b80601f01602080910402602001604051908101604052809291908181526020018280546106ae90612e60565b80156106f95780601f106106d0576101008083540402835291602001916106f9565b820191905f5260205f20905b8154815290600101906020018083116106dc57829003601f168201915b505050505061016054611267565b905090565b606061012f805461071c90612e60565b80601f016020809104026020016040519081016040528092919081815260200182805461074890612e60565b80156107935780601f1061076a57610100808354040283529160200191610793565b820191905f5260205f20905b81548152906001019060200180831161077657829003601f168201915b50505050509050919050565b60026107a961129b565b60ff16036107ca5760405163dfc60d8560e01b815260040160405180910390fd5b6107d460026112d4565b6107e860c954610100900460ff1660021490565b156108065760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b610822816001610e73565b6001600160a01b0316336001600160a01b03161461085357604051630d85cccf60e11b815260040160405180910390fd5b61086d84848460405180602001604052805f815250611316565b5061087860016112d4565b505050565b6001600160a01b038516331480610899575061089985336104dc565b6108b55760405162461bcd60e51b81526004016105ec90612e98565b6108c285858585856113f3565b5050505050565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000100981630036109115760405162461bcd60e51b81526004016105ec90612ee6565b7f00000000000000000000000001670020000000000000000000000000000100986001600160a01b03166109595f8051602061355a833981519152546001600160a01b031690565b6001600160a01b03161461097f5760405162461bcd60e51b81526004016105ec90612f32565b61098881611596565b604080515f808252602082019092526109a39183919061159e565b50565b5f6109b2848484611708565b90505b9392505050565b6109d060c954610100900460ff1660021490565b6109ed5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610a3933611596565b565b60608151835114610aa05760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016105ec565b5f83516001600160401b03811115610aba57610aba6128b2565b604051908082528060200260200182016040528015610ae3578160200160208202803683370190505b5090505f5b8451811015610b5257610b2d858281518110610b0657610b06612f7e565b6020026020010151858381518110610b2057610b20612f7e565b6020026020010151610586565b828281518110610b3f57610b3f612f7e565b6020908102919091010152600101610ae8565b509392505050565b6001600160a01b037f0000000000000000000000000167002000000000000000000000000000010098163003610ba25760405162461bcd60e51b81526004016105ec90612ee6565b7f00000000000000000000000001670020000000000000000000000000000100986001600160a01b0316610bea5f8051602061355a833981519152546001600160a01b031690565b6001600160a01b031614610c105760405162461bcd60e51b81526004016105ec90612f32565b610c1982611596565b610c258282600161159e565b5050565b5f306001600160a01b037f00000000000000000000000001670020000000000000000000000000000100981614610cc85760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016105ec565b505f8051602061355a8339815191525b90565b610ce36117f4565b610a395f61184e565b60655433906001600160a01b03168114610d5a5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105ec565b6109a38161184e565b610d7760c954610100900460ff1660021490565b15610d955760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610a28565b60606107076101618054610de790612e60565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1390612e60565b8015610e5e5780601f10610e3557610100808354040283529160200191610e5e565b820191905f5260205f20905b815481529060010190602001808311610e4157829003601f168201915b5050505050611867565b610c25338383611890565b5f6109b5468484611708565b6002610e8961129b565b60ff1603610eaa5760405163dfc60d8560e01b815260040160405180910390fd5b610eb460026112d4565b610ec860c954610100900460ff1660021490565b15610ee65760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b610f02816001610e73565b6001600160a01b0316336001600160a01b031614610f3357604051630d85cccf60e11b815260040160405180910390fd5b61086d84848460405180602001604052805f815250611970565b5f54610100900460ff1615808015610f6b57505f54600160ff909116105b80610f845750303b158015610f8457505f5460ff166001145b610fe75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016105ec565b5f805460ff191660011790558015611008575f805461ff0019166101001790555b61104a858560405180604001604052806003815260200162666f6f60e81b81525060405180604001604052806003815260200162666f6f60e81b815250611ab8565b6110548787611b0e565b6110666110618686611b6d565b611b9d565b61015f80546001600160a01b0319166001600160a01b0387161790556101608490556101616110958482612fd6565b506101626110a38382612fd6565b5080156110e9575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6001600160a01b03851633148061110e575061110e85336104dc565b61112a5760405162461bcd60e51b81526004016105ec90612e98565b6108c28585858585611bcc565b61113f6117f4565b606580546001600160a01b0383166001600160a01b031990911681179091556111706033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60026111b261129b565b60ff16036111d35760405163dfc60d8560e01b815260040160405180910390fd5b6111dd60026112d4565b6111f160c954610100900460ff1660021490565b1561120f5760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b61122b816001610e73565b6001600160a01b0316336001600160a01b03161461125c57604051630d85cccf60e11b815260040160405180910390fd5b61086d848484611d06565b60608261127383611e95565b604051602001611284929190613091565b604051602081830303815290604052905092915050565b5f466001036112ca57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361130257807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b6001600160a01b03841661133c5760405162461bcd60e51b81526004016105ec906130f1565b335f61134785611f24565b90505f61135385611f24565b9050611363835f89858589611f6d565b5f86815261012d602090815260408083206001600160a01b038b16845290915281208054879290611395908490613146565b909155505060408051878152602081018790526001600160a01b03808a16925f92918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46110e9835f89898989611fc8565b81518351146114145760405162461bcd60e51b81526004016105ec90613159565b6001600160a01b03841661143a5760405162461bcd60e51b81526004016105ec906131a1565b33611449818787878787611f6d565b5f5b8451811015611528575f85828151811061146757611467612f7e565b602002602001015190505f85838151811061148457611484612f7e565b6020908102919091018101515f84815261012d835260408082206001600160a01b038e1683529093529190912054909150818110156114d55760405162461bcd60e51b81526004016105ec906131e6565b5f83815261012d602090815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290611514908490613146565b90915550506001909301925061144b915050565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051611578929190613230565b60405180910390a461158e818787878787612122565b505050505050565b6109a36117f4565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156115d157610878836121dc565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561162b575060408051601f3d908101601f191682019092526116289181019061325d565b60015b61168e5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016105ec565b5f8051602061355a83398151915281146116fc5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016105ec565b50610878838383612277565b6097545f906001600160a01b031661173357604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611789573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ad9190613274565b9050811580156117c457506001600160a01b038116155b156109b557604051632b0d65db60e01b81526001600160401b0385166004820152602481018490526044016105ec565b6033546001600160a01b03163314610a395760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105ec565b606580546001600160a01b03191690556109a38161229b565b60608160405160200161187a919061328f565b6040516020818303038152906040529050919050565b816001600160a01b0316836001600160a01b0316036119035760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016105ec565b6001600160a01b038381165f81815261012e6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166119965760405162461bcd60e51b81526004016105ec906130f1565b81518351146119b75760405162461bcd60e51b81526004016105ec90613159565b336119c6815f87878787611f6d565b5f5b8451811015611a52578381815181106119e3576119e3612f7e565b602002602001015161012d5f878481518110611a0157611a01612f7e565b602002602001015181526020019081526020015f205f886001600160a01b03166001600160a01b031681526020019081526020015f205f828254611a459190613146565b90915550506001016119c8565b50846001600160a01b03165f6001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051611aa2929190613230565b60405180910390a46108c2815f87878787612122565b6001600160a01b0384161580611acc575082155b80611ad657504683145b80611ae057508151155b80611aea57508051155b15611b085760405163c118d2f360e01b815260040160405180910390fd5b50505050565b5f54610100900460ff16611b345760405162461bcd60e51b81526004016105ec906132b4565b611b3d826122ec565b6001600160a01b038116611b64576040516375cabfef60e11b815260040160405180910390fd5b610c258161231c565b6060611b83836001600160a01b0316601461238c565b611b8c83611e95565b6040516020016112849291906132ff565b5f54610100900460ff16611bc35760405162461bcd60e51b81526004016105ec906132b4565b6109a381612521565b6001600160a01b038416611bf25760405162461bcd60e51b81526004016105ec906131a1565b335f611bfd85611f24565b90505f611c0985611f24565b9050611c19838989858589611f6d565b5f86815261012d602090815260408083206001600160a01b038c16845290915290205485811015611c5c5760405162461bcd60e51b81526004016105ec906131e6565b5f87815261012d602090815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290611c9b908490613146565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611cfb848a8a8a8a8a611fc8565b505050505050505050565b6001600160a01b038316611d685760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b60648201526084016105ec565b335f611d7384611f24565b90505f611d7f84611f24565b9050611d9d83875f858560405180602001604052805f815250611f6d565b5f85815261012d602090815260408083206001600160a01b038a16845290915290205484811015611e1c5760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b60648201526084016105ec565b5f86815261012d602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a460408051602081019091525f90526110e9565b60605f611ea183612550565b60010190505f816001600160401b03811115611ebf57611ebf6128b2565b6040519080825280601f01601f191660200182016040528015611ee9576020820181803683370190505b5090508181016020015b5f19016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611ef357509392505050565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110611f5c57611f5c612f7e565b602090810291909101015292915050565b306001600160a01b03851603611f9657604051630183150560e21b815260040160405180910390fd5b611faa60c954610100900460ff1660021490565b1561158e5760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0384163b1561158e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e619061200c908990899088908890889060040161336e565b6020604051808303815f875af1925050508015612046575060408051601f3d908101601f19168201909252612043918101906133b2565b60015b6120f2576120526133cd565b806308c379a00361208b57506120666133e5565b80612071575061208d565b8060405162461bcd60e51b81526004016105ec9190612857565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016105ec565b6001600160e01b0319811663f23a6e6160e01b146110e95760405162461bcd60e51b81526004016105ec9061346d565b6001600160a01b0384163b1561158e5760405163bc197c8160e01b81526001600160a01b0385169063bc197c819061216690899089908890889088906004016134b5565b6020604051808303815f875af19250505080156121a0575060408051601f3d908101601f1916820190925261219d918101906133b2565b60015b6121ac576120526133cd565b6001600160e01b0319811663bc197c8160e01b146110e95760405162461bcd60e51b81526004016105ec9061346d565b6001600160a01b0381163b6122495760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016105ec565b5f8051602061355a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61228083612627565b5f8251118061228c5750805b1561087857611b088383612666565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b61230a6001600160a01b03821615612304578161184e565b3361184e565b5060c9805461ff001916610100179055565b5f54610100900460ff166123425760405162461bcd60e51b81526004016105ec906132b4565b6001600160401b0346111561236a5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60605f61239a836002613512565b6123a5906002613146565b6001600160401b038111156123bc576123bc6128b2565b6040519080825280601f01601f1916602001820160405280156123e6576020820181803683370190505b509050600360fc1b815f8151811061240057612400612f7e565b60200101906001600160f81b03191690815f1a905350600f60fb1b8160018151811061242e5761242e612f7e565b60200101906001600160f81b03191690815f1a9053505f612450846002613512565b61245b906001613146565b90505b60018111156124d2576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061248f5761248f612f7e565b1a60f81b8282815181106124a5576124a5612f7e565b60200101906001600160f81b03191690815f1a90535060049490941c936124cb81613529565b905061245e565b5083156109b55760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016105ec565b5f54610100900460ff166125475760405162461bcd60e51b81526004016105ec906132b4565b6109a38161268b565b5f8072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061258e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106125ba576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106125d857662386f26fc10000830492506010015b6305f5e10083106125f0576305f5e100830492506008015b612710831061260457612710830492506004015b60648310612616576064830492506002015b600a831061061a5760010192915050565b612630816121dc565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606109b5838360405180606001604052806027815260200161357a60279139612698565b61012f610c258282612fd6565b60605f80856001600160a01b0316856040516126b4919061353e565b5f60405180830381855af49150503d805f81146126ec576040519150601f19603f3d011682016040523d82523d5f602084013e6126f1565b606091505b50915091506127028683838761270c565b9695505050505050565b6060831561277a5782515f03612773576001600160a01b0385163b6127735760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105ec565b5081612784565b612784838361278c565b949350505050565b8151156120715781518083602001fd5b6001600160a01b03811681146109a3575f80fd5b5f80604083850312156127c1575f80fd5b82356127cc8161279c565b946020939093013593505050565b6001600160e01b0319811681146109a3575f80fd5b5f602082840312156127ff575f80fd5b81356109b5816127da565b5f5b8381101561282457818101518382015260200161280c565b50505f910152565b5f815180845261284381602086016020860161280a565b601f01601f19169290920160200192915050565b602081525f6109b5602083018461282c565b5f60208284031215612879575f80fd5b5035919050565b5f805f60608486031215612892575f80fd5b833561289d8161279c565b95602085013595506040909401359392505050565b634e487b7160e01b5f52604160045260245ffd5b601f8201601f191681016001600160401b03811182821017156128eb576128eb6128b2565b6040525050565b5f6001600160401b0382111561290a5761290a6128b2565b5060051b60200190565b5f82601f830112612923575f80fd5b81356020612930826128f2565b60405161293d82826128c6565b80915083815260208101915060208460051b870101935086841115612960575f80fd5b602086015b8481101561297c5780358352918301918301612965565b509695505050505050565b5f82601f830112612996575f80fd5b81356001600160401b038111156129af576129af6128b2565b6040516129c6601f8301601f1916602001826128c6565b8181528460208386010111156129da575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215612a0a575f80fd5b8535612a158161279c565b94506020860135612a258161279c565b935060408601356001600160401b0380821115612a40575f80fd5b612a4c89838a01612914565b94506060880135915080821115612a61575f80fd5b612a6d89838a01612914565b93506080880135915080821115612a82575f80fd5b50612a8f88828901612987565b9150509295509295909350565b5f60208284031215612aac575f80fd5b81356109b58161279c565b80358015158114612ac6575f80fd5b919050565b5f805f60608486031215612add575f80fd5b83356001600160401b0381168114612af3575f80fd5b925060208401359150612b0860408501612ab7565b90509250925092565b5f8060408385031215612b22575f80fd5b82356001600160401b0380821115612b38575f80fd5b818501915085601f830112612b4b575f80fd5b81356020612b58826128f2565b604051612b6582826128c6565b83815260059390931b8501820192828101915089841115612b84575f80fd5b948201945b83861015612bab578535612b9c8161279c565b82529482019490820190612b89565b96505086013592505080821115612bc0575f80fd5b50612bcd85828601612914565b9150509250929050565b5f815180845260208085019450602084015f5b83811015612c0657815187529582019590820190600101612bea565b509495945050505050565b602081525f6109b56020830184612bd7565b5f8060408385031215612c34575f80fd5b8235612c3f8161279c565b915060208301356001600160401b03811115612c59575f80fd5b612bcd85828601612987565b5f8060408385031215612c76575f80fd5b8235612c818161279c565b9150612c8f60208401612ab7565b90509250929050565b5f8060408385031215612ca9575f80fd5b82359150612c8f60208401612ab7565b5f805f60608486031215612ccb575f80fd5b8335612cd68161279c565b925060208401356001600160401b0380821115612cf1575f80fd5b612cfd87838801612914565b93506040860135915080821115612d12575f80fd5b50612d1f86828701612914565b9150509250925092565b5f8060408385031215612d3a575f80fd5b8235612d458161279c565b91506020830135612d558161279c565b809150509250929050565b5f805f805f8060c08789031215612d75575f80fd5b8635612d808161279c565b95506020870135612d908161279c565b94506040870135612da08161279c565b93506060870135925060808701356001600160401b0380821115612dc2575f80fd5b612dce8a838b01612987565b935060a0890135915080821115612de3575f80fd5b50612df089828a01612987565b9150509295509295509295565b5f805f805f60a08688031215612e11575f80fd5b8535612e1c8161279c565b94506020860135612e2c8161279c565b9350604086013592506060860135915060808601356001600160401b03811115612e54575f80fd5b612a8f88828901612987565b600181811c90821680612e7457607f821691505b602082108103612e9257634e487b7160e01b5f52602260045260245ffd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b5f52603260045260245ffd5b601f82111561087857805f5260205f20601f840160051c81016020851015612fb75750805b601f840160051c820191505b818110156108c2575f8155600101612fc3565b81516001600160401b03811115612fef57612fef6128b2565b61300381612ffd8454612e60565b84612f92565b602080601f831160018114613036575f841561301f5750858301515b5f19600386901b1c1916600185901b17855561158e565b5f85815260208120601f198616915b8281101561306457888601518255948401946001909101908401613045565b508582101561308157878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b670213934b233b2b2160c51b81525f83516130b381600885016020880161280a565b634051c55b60df1b60089184019182015283516130d781600d84016020880161280a565b602960f81b600d9290910191820152600e01949350505050565b60208082526021908201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736040820152607360f81b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561061a5761061a613132565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081525f6132426040830185612bd7565b82810360208401526132548185612bd7565b95945050505050565b5f6020828403121561326d575f80fd5b5051919050565b5f60208284031215613284575f80fd5b81516109b58161279c565b5f82516132a081846020870161280a565b610b9d60f21b920191825250600201919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6832ba3432b932bab69d60b91b81525f835161332281600985016020880161280a565b600160fe1b600991840191820152835161334381600a84016020880161280a565b712f746f6b656e5552493f75696e743235363d60701b600a9290910191820152601c01949350505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f906133a79083018461282c565b979650505050505050565b5f602082840312156133c2575f80fd5b81516109b5816127da565b5f60033d1115610cd85760045f803e505f5160e01c90565b5f60443d10156133f25790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561342157505050505090565b82850191508151818111156134395750505050505090565b843d87010160208285010111156134535750505050505090565b613462602082860101876128c6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a0604082018190525f906134e090830186612bd7565b82810360608401526134f28186612bd7565b90508281036080840152613506818561282c565b98975050505050505050565b808202811582820484141761061a5761061a613132565b5f8161353757613537613132565b505f190190565b5f825161354f81846020870161280a565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220bd3fdb4c6dc0647e883a48f490bd9cea420ea3e74a0fb4881a0592a16dd7031d64736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x60806040526004361061017b575f3560e01c8063715018a6116100cd5780639b527cfa11610087578063e30c397811610062578063e30c397814610479578063f09a401614610496578063f2fde38b146104b5578063fe9fbb80146104d4575f80fd5b80639b527cfa146103fd578063a86f9d9e1461041c578063dfc8ff1d1461043b575f80fd5b8063715018a61461036657806379ba50971461037a5780638456cb591461038e5780638da5cb5b146103a2578063910af6ed146103bf57806391f3f74b146103de575f80fd5b80633eb6b8cf116101385780634f90a674116101135780634f90a674146102e657806352d1902d146103135780635c975abb1461032757806366ca2bc014610347575f80fd5b80633eb6b8cf146102a05780633f4ba83a146102bf5780634f1ef286146102d3575f80fd5b80632d1fb3891461017f57806332676bc6146101a0578063355bcc3d146101d45780633659cfe61461022b5780633ab76e9f1461024a5780633ced0e0814610281575b5f80fd5b34801561018a575f80fd5b5061019e6101993660046135b4565b610502565b005b3480156101ab575f80fd5b506101bf6101ba3660046135e7565b6105a8565b60405190151581526020015b60405180910390f35b3480156101df575f80fd5b506102136101ee366004613627565b60fb60209081525f92835260408084209091529082529020546001600160401b031681565b6040516001600160401b0390911681526020016101cb565b348015610236575f80fd5b5061019e610245366004613641565b6105be565b348015610255575f80fd5b50609754610269906001600160a01b031681565b6040516001600160a01b0390911681526020016101cb565b34801561028c575f80fd5b506101bf61029b36600461365c565b6106a4565b3480156102ab575f80fd5b506102696102ba36600461369d565b6106eb565b3480156102ca575f80fd5b5061019e610701565b61019e6102e13660046137ad565b610780565b3480156102f1575f80fd5b5061030561030036600461365c565b61084f565b6040519081526020016101cb565b34801561031e575f80fd5b50610305610895565b348015610332575f80fd5b506101bf60c954610100900460ff1660021490565b348015610352575f80fd5b506103056103613660046137f9565b610946565b348015610371575f80fd5b5061019e610952565b348015610385575f80fd5b5061019e610963565b348015610399575f80fd5b5061019e6109da565b3480156103ad575f80fd5b506033546001600160a01b0316610269565b3480156103ca575f80fd5b5061019e6103d9366004613810565b610a4b565b3480156103e9575f80fd5b506103056103f83660046138a4565b610ce4565b348015610408575f80fd5b506103056104173660046138e0565b610d4f565b348015610427575f80fd5b50610269610436366004613910565b610d7b565b348015610446575f80fd5b5061045a6104553660046138e0565b610d87565b604080516001600160401b0390931683526020830191909152016101cb565b348015610484575f80fd5b506065546001600160a01b0316610269565b3480156104a1575f80fd5b5061019e6104b0366004613931565b610e1b565b3480156104c0575f80fd5b5061019e6104cf366004613641565b610f2a565b3480156104df575f80fd5b506101bf6104ee366004613641565b60fc6020525f908152604090205460ff1681565b61050a610f9b565b6001600160a01b0382165f90815260fc602052604090205481151560ff90911615150361054a576040516398f26f4560e01b815260040160405180910390fd5b6001600160a01b0382165f81815260fc6020908152604091829020805460ff191685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b5f6105b38383610ff5565b151590505b92915050565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000000000516300361060f5760405162461bcd60e51b815260040161060690613968565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000000056001600160a01b03166106575f80516020613fc7833981519152546001600160a01b031690565b6001600160a01b03161461067d5760405162461bcd60e51b8152600401610606906139b4565b61068681611057565b604080515f808252602082019092526106a19183919061105f565b50565b5f818082036106c657604051630426d36960e31b815260040160405180910390fd5b5f6106d2878787610d4f565b9050836106df3083610ff5565b14979650505050505050565b5f6106f78484846111c9565b90505b9392505050565b61071560c954610100900460ff1660021490565b6107325760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a161077e336112b5565b565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000000051630036107c85760405162461bcd60e51b815260040161060690613968565b7f00000000000000000000000001670020000000000000000000000000000000056001600160a01b03166108105f80516020613fc7833981519152546001600160a01b031690565b6001600160a01b0316146108365760405162461bcd60e51b8152600401610606906139b4565b61083f82611057565b61084b8282600161105f565b5050565b335f90815260fc602052604081205460ff1661087e57604051631f67751f60e01b815260040160405180910390fd5b61088a858585856112ce565b90505b949350505050565b5f306001600160a01b037f000000000000000000000000016700200000000000000000000000000000000516146109345760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610606565b505f80516020613fc783398151915290565b5f6105b83383846113b0565b61095a610f9b565b61077e5f611489565b60655433906001600160a01b031681146109d15760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610606565b6106a181611489565b6109ee60c954610100900460ff1660021490565b15610a0c5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161076d565b836001600160a01b038116610a73576040516327e0ab1560e21b815260040160405180910390fd5b835f819003610a9557604051630426d36960e31b815260040160405180910390fd5b5f610aa284860186613aaf565b905080515f03610ac557604051630b92daef60e21b815260040160405180910390fd5b878787805f610ae6856d7369676e616c5f7365727669636560901b836106eb565b9050610b206040805160c0810182525f80825260208201819052918101829052906060820190815260200160608152602001606081525090565b5f5b8751811015610c9f57878181518110610b3d57610b3d613bed565b602002602001015191505f610b568888888887896114a2565b90505f60018a51610b679190613c15565b831490508015610ba35783516001600160401b03164614610b9b576040516338bf822760e21b815260040160405180910390fd5b309450610c02565b83516001600160401b03161580610bc3575083516001600160401b031646145b15610be157604051637556223560e11b815260040160405180910390fd5b8351610bff906d7369676e616c5f7365727669636560901b5f6106eb565b94505b5f80856080015151119050610c1f858b8760200151868587611541565b5f81610c4b577fc6cdc4f2acf13acb10f410085b821f7b7113b303e9a4799023f928317396aaf5610c6d565b7f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da1695b9050610c7e8b828860200151610d4f565b985085604001519750855f01519a5086995050505050806001019050610b22565b50821580610cb65750610cb23085610ff5565b8314155b15610cd45760405163738afa0560e01b815260040160405180910390fd5b5050505050505050505050505050565b6040516514d251d3905360d21b60208201526001600160c01b031960c085901b1660268201526bffffffffffffffffffffffff19606084901b16602e820152604281018290525f906062015b6040516020818303038152906040528051906020012090509392505050565b604080516001600160401b03808616602083015291810184905290821660608201525f90608001610d30565b5f6106fa4684846111c9565b5f80826001600160401b03165f03610dc3576001600160401b038086165f90815260fb6020908152604080832088845290915290205416610dc5565b825b91506001600160401b03821615610e13575f610de2868685610d4f565b9050610dee3082610ff5565b91505f829003610e115760405163738afa0560e01b815260040160405180910390fd5b505b935093915050565b5f54610100900460ff1615808015610e3957505f54600160ff909116105b80610e525750303b158015610e5257505f5460ff166001145b610eb55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610606565b5f805460ff191660011790558015610ed6575f805461ff0019166101001790555b610ee08383611653565b8015610f25575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b610f32610f9b565b606580546001600160a01b0383166001600160a01b03199091168117909155610f636033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6033546001600160a01b0316331461077e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610606565b5f826001600160a01b03811661101e576040516327e0ab1560e21b815260040160405180910390fd5b825f81900361104057604051630426d36960e31b815260040160405180910390fd5b5f61104c468787610ce4565b549695505050505050565b6106a1610f9b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561109257610f25836116b2565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156110ec575060408051601f3d908101601f191682019092526110e991810190613c28565b60015b61114f5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610606565b5f80516020613fc783398151915281146111bd5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610606565b50610f2583838361174d565b6097545f906001600160a01b03166111f457604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801561124a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061126e9190613c3f565b90508115801561128557506001600160a01b038116155b156106fa57604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610606565b60405163198bb9dd60e11b815260040160405180910390fd5b5f6112da858585610d4f565b90506112e73082846113b0565b506001600160401b038581165f90815260fb6020908152604080832088845290915290205481851691161015611351576001600160401b038581165f90815260fb602090815260408083208884529091529020805467ffffffffffffffff19169185169190911790555b83836001600160401b0316866001600160401b03167fde247c825b1fb2d7ff9e0e771cba6f9e757ad04479fcdc135d88ae91fd50b37d85856040516113a0929190918252602082015260400190565b60405180910390a4949350505050565b5f836001600160a01b0381166113d9576040516327e0ab1560e21b815260040160405180910390fd5b835f8190036113fb57604051630426d36960e31b815260040160405180910390fd5b835f81900361141d57604051630426d36960e31b815260040160405180910390fd5b611428468888610ce4565b858155604080516001600160a01b038a16815260208101899052908101829052606081018790529094507f0ad2d108660a211f47bf7fb43a0443cae181624995d3d42b88ee6879d200e9739060800160405180910390a15050509392505050565b606580546001600160a01b03191690556106a181611777565b5f856001600160a01b0381166114cb576040516327e0ab1560e21b815260040160405180910390fd5b855f8190036114ed57604051630426d36960e31b815260040160405180910390fd5b855f81900361150f57604051630426d36960e31b815260040160405180910390fd5b6115338660400151866115238d8d8d610ce4565b8a8a608001518b60a001516117c8565b9a9950505050505050505050565b5f60038760600151600381111561155a5761155a613c5a565b148061157b575060028760600151600381111561157957611579613c5a565b145b90508080156115875750825b8015611591575081155b156115c8576115c6867f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da169878a604001516112ce565b505b5f6003886060015160038111156115e1576115e1613c5a565b1480611602575060018860600151600381111561160057611600613c5a565b145b905080801561161657508380611616575082155b1561164957611647877fc6cdc4f2acf13acb10f410085b821f7b7113b303e9a4799023f928317396aaf588886112ce565b505b5050505050505050565b5f54610100900460ff166116795760405162461bcd60e51b815260040161060690613c6e565b611682826118d5565b6001600160a01b0381166116a9576040516375cabfef60e11b815260040160405180910390fd5b61084b81611905565b6001600160a01b0381163b61171f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610606565b5f80516020613fc783398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61175683611975565b5f825111806117625750805b15610f255761177183836119b4565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f82515f14611870576040516bffffffffffffffffffffffff19606088901b1660208201525f9061180c90603401604051602081830303815290604052858a6119d9565b905080515f0361182f57604051630414cd5b60e31b815260040160405180910390fd5b5f611839826119fb565b905061185e8160028151811061185157611851613bed565b6020026020010151611a0e565b61186790613cb9565b92505050611873565b50855b5f6118aa8660405160200161188a91815260200190565b60408051601f198184030181529190526118a387611b2e565b8585611b41565b9050806118ca57604051638d9a4db360e01b815260040160405180910390fd5b509695505050505050565b6118f36001600160a01b038216156118ed5781611489565b33611489565b5060c9805461ff001916610100179055565b5f54610100900460ff1661192b5760405162461bcd60e51b815260040161060690613c6e565b6001600160401b034611156119535760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b61197e816116b2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b60606106fa8383604051806060016040528060278152602001613fe760279139611b64565b60605f6119e585611bce565b90506119f2818585611c00565b95945050505050565b60606105b8611a098361246d565b6124be565b60605f805f611a1c856126db565b919450925090505f816001811115611a3657611a36613c5a565b14611aa95760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d000000000000006064820152608401610606565b611ab38284613cdf565b855114611b1f5760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b6064820152608401610606565b6119f285602001518484612d82565b60606105b8611b3c83612e12565b612f2d565b5f80611b4c86611bce565b9050611b5a81868686612f85565b9695505050505050565b60605f80856001600160a01b031685604051611b809190613d14565b5f60405180830381855af49150503d805f8114611bb8576040519150601f19603f3d011682016040523d82523d5f602084013e611bbd565b606091505b5091509150611b5a86838387612fab565b60608180519060200120604051602001611bea91815260200190565b6040516020818303038152906040529050919050565b60605f845111611c4a5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b6044820152606401610606565b5f611c5484613023565b90505f611c608661310d565b90505f84604051602001611c7691815260200190565b60405160208183030381529060405290505f805b8451811015612416575f858281518110611ca657611ca6613bed565b602002602001015190508451831115611d185760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b6064820152608401610606565b825f03611db65780518051602091820120604051611d6592611d3f92910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b611db15760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f7420686173680000006044820152606401610606565b611eac565b805151602011611e3c5780518051602091820120604051611de092611d3f92910190815260200190565b611db15760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b6064820152608401610606565b805184516020808701919091208251919092012014611eac5760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b6064820152608401610606565b611eb860106001613cdf565b816020015151036120505784518303611fea57611ee5816020015160108151811061185157611851613bed565b96505f875111611f5d5760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e63682900000000006064820152608401610606565b60018651611f6b9190613c15565b8214611fdf5760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e6368290000000000006064820152608401610606565b5050505050506106fa565b5f858481518110611ffd57611ffd613bed565b602001015160f81c60f81b60f81c90505f82602001518260ff168151811061202757612027613bed565b6020026020010151905061203a8161316e565b9550612047600186613cdf565b9450505061240d565b6002816020015151036123b4575f61206782613192565b90505f815f8151811061207c5761207c613bed565b016020015160f81c90505f612092600283613d43565b61209d906002613d64565b90505f6120ad848360ff166131b5565b90505f6120ba8a896131b5565b90505f6120c783836131ea565b90508083511461213f5760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b65790000000000006064820152608401610606565b60ff851660021480612154575060ff85166003145b156122f457808251146121cf5760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e6465720000006064820152608401610606565b6121e9876020015160018151811061185157611851613bed565b9c505f8d51116122615760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c65616629000000000000006064820152608401610606565b60018c5161226f9190613c15565b88146122e35760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c6561662900000000000000006064820152608401610606565b5050505050505050505050506106fa565b60ff85161580612307575060ff85166001145b1561234657612333876020015160018151811061232657612326613bed565b602002602001015161316e565b995061233f818a613cdf565b98506123a9565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b6064820152608401610606565b50505050505061240d565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b6064820152608401610606565b50600101611c8a565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b6064820152608401610606565b604080518082019091525f80825260208201525f8251116124a05760405162461bcd60e51b815260040161060690613d7d565b50604080518082019091528151815260209182019181019190915290565b60605f805f6124cc856126db565b9194509250905060018160018111156124e7576124e7613c5a565b1461255a5760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d00000000000000006064820152608401610606565b84516125668385613cdf565b146125ce5760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b6064820152608401610606565b604080516020808252610420820190925290816020015b604080518082019091525f80825260208201528152602001906001900390816125e55790505093505f835b86518110156126cf575f806126546040518060400160405280858c5f01516126389190613c15565b8152602001858c6020015161264d9190613cdf565b90526126db565b5091509150604051806040016040528083836126709190613cdf565b8152602001848b602001516126859190613cdf565b81525088858151811061269a5761269a613bed565b60209081029190910101526126b0600185613cdf565b93506126bc8183613cdf565b6126c69084613cdf565b92505050612610565b50845250919392505050565b5f805f80845f0151116127005760405162461bcd60e51b815260040161060690613d7d565b602084015180515f1a607f8111612722575f60015f9450945094505050612d7b565b60b7811161287b575f612736608083613c15565b905080875f0151116127b45760405162461bcd60e51b815260206004820152604e60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a401610606565b6001838101516001600160f81b03191690821415806127e15750600160ff1b6001600160f81b0319821610155b6128695760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a401610606565b506001955093505f9250612d7b915050565b60bf8111612ab4575f61288f60b783613c15565b905080875f0151116129105760405162461bcd60e51b815260206004820152605160248201525f80516020613fa783398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a401610606565b60018301516001600160f81b0319165f8190036129955760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a401610606565b600184015160088302610100031c60378111612a175760405162461bcd60e51b815260206004820152604860248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a401610606565b612a218184613cdf565b895111612a985760405162461bcd60e51b815260206004820152604c60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a401610606565b612aa3836001613cdf565b975095505f9450612d7b9350505050565b60f78111612b53575f612ac860c083613c15565b905080875f015111612b425760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a401610606565b600195509350849250612d7b915050565b5f612b5f60f783613c15565b905080875f015111612bdc5760405162461bcd60e51b815260206004820152604d60248201525f80516020613fa783398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a401610606565b60018301516001600160f81b0319165f819003612c5f5760405162461bcd60e51b815260206004820152604860248201525f80516020613fa783398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a401610606565b600184015160088302610100031c60378111612cdf5760405162461bcd60e51b815260206004820152604660248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a401610606565b612ce98184613cdf565b895111612d5e5760405162461bcd60e51b815260206004820152604a60248201525f80516020613fa783398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a401610606565b612d69836001613cdf565b9750955060019450612d7b9350505050565b9193909250565b6060816001600160401b03811115612d9c57612d9c6136d6565b6040519080825280601f01601f191660200182016040528015612dc6576020820181803683370190505b50905081156106fa575f612dda8486613cdf565b9050602082015f5b84811015612dfa578281015182820152602001612de2565b84811115612e08575f858301525b5050509392505050565b60605f82604051602001612e2891815260200190565b60405160208183030381529060405290505f5b6020811015612e7357818181518110612e5657612e56613bed565b01602001516001600160f81b0319165f03612e7357600101612e3b565b612e7e816020613c15565b6001600160401b03811115612e9557612e956136d6565b6040519080825280601f01601f191660200182016040528015612ebf576020820181803683370190505b5092505f5b8351811015612f25578282612ed881613ded565b935081518110612eea57612eea613bed565b602001015160f81c60f81b848281518110612f0757612f07613bed565b60200101906001600160f81b03191690815f1a905350600101612ec4565b505050919050565b606081516001148015612f5957506080825f81518110612f4f57612f4f613bed565b016020015160f81c105b15612f62575090565b612f6e8251608061326d565b82604051602001611bea929190613e05565b919050565b5f61088a84612f95878686611c00565b8051602091820120825192909101919091201490565b606083156130195782515f03613012576001600160a01b0385163b6130125760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610606565b508161088d565b61088d8383613412565b8051606090806001600160401b03811115613040576130406136d6565b60405190808252806020026020018201604052801561308557816020015b604080518082019091526060808252602082015281526020019060019003908161305e5790505b5091505f5b818110156131065760405180604001604052808583815181106130af576130af613bed565b602002602001015181526020016130de8684815181106130d1576130d1613bed565b60200260200101516119fb565b8152508382815181106130f3576130f3613bed565b602090810291909101015260010161308a565b5050919050565b606080604051905082518060011b603f8101601f191683016040528083525060208401602083015f5b83811015613163578060011b8201818401515f1a8060041c8253600f811660018301535050600101613136565b509295945050505050565b60606020825f0151106131895761318482611a0e565b6105b8565b6105b88261343c565b60606105b86131b083602001515f8151811061185157611851613bed565b61310d565b6060825182106131d3575060408051602081019091525f81526105b8565b6106fa83838486516131e59190613c15565b613450565b5f8082518451106131fc5782516131ff565b83515b90505b8082108015613256575082828151811061321e5761321e613bed565b602001015160f81c60f81b6001600160f81b03191684838151811061324557613245613bed565b01602001516001600160f81b031916145b1561326657816001019150613202565b5092915050565b606060388310156132d157604080516001808252818301909252906020820181803683370190505090506132a18284613e33565b60f81b815f815181106132b6576132b6613bed565b60200101906001600160f81b03191690815f1a9053506105b8565b5f60015b6132df8186613e4c565b1561330557816132ee81613ded565b92506132fe905061010082613e5f565b90506132d5565b613310826001613cdf565b6001600160401b03811115613327576133276136d6565b6040519080825280601f01601f191660200182016040528015613351576020820181803683370190505b50925061335e8483613e33565b613369906037613e33565b60f81b835f8151811061337e5761337e613bed565b60200101906001600160f81b03191690815f1a905350600190505b81811161340a576101006133ad8284613c15565b6133b990610100613f56565b6133c39087613e4c565b6133cd9190613f61565b60f81b8382815181106133e2576133e2613bed565b60200101906001600160f81b03191690815f1a9053508061340281613ded565b915050613399565b505092915050565b8151156134225781518083602001fd5b8060405162461bcd60e51b81526004016106069190613f74565b60606105b882602001515f845f0151612d82565b60608182601f0110156134965760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610606565b8282840110156134d95760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610606565b818301845110156135205760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610606565b60608215801561353e5760405191505f825260208201604052613588565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561357757805183526020928301920161355f565b5050858452601f01601f1916604052505b50949350505050565b6001600160a01b03811681146106a1575f80fd5b80358015158114612f80575f80fd5b5f80604083850312156135c5575f80fd5b82356135d081613591565b91506135de602084016135a5565b90509250929050565b5f80604083850312156135f8575f80fd5b823561360381613591565b946020939093013593505050565b80356001600160401b0381168114612f80575f80fd5b5f8060408385031215613638575f80fd5b61360383613611565b5f60208284031215613651575f80fd5b81356106fa81613591565b5f805f806080858703121561366f575f80fd5b61367885613611565b93506020850135925061368d60408601613611565b9396929550929360600135925050565b5f805f606084860312156136af575f80fd5b6136b884613611565b9250602084013591506136cd604085016135a5565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b038111828210171561370c5761370c6136d6565b60405290565b604051601f8201601f191681016001600160401b038111828210171561373a5761373a6136d6565b604052919050565b5f82601f830112613751575f80fd5b81356001600160401b0381111561376a5761376a6136d6565b61377d601f8201601f1916602001613712565b818152846020838601011115613791575f80fd5b816020850160208301375f918101602001919091529392505050565b5f80604083850312156137be575f80fd5b82356137c981613591565b915060208301356001600160401b038111156137e3575f80fd5b6137ef85828601613742565b9150509250929050565b5f60208284031215613809575f80fd5b5035919050565b5f805f805f60808688031215613824575f80fd5b61382d86613611565b9450602086013561383d81613591565b93506040860135925060608601356001600160401b038082111561385f575f80fd5b818801915088601f830112613872575f80fd5b813581811115613880575f80fd5b896020828501011115613891575f80fd5b9699959850939650602001949392505050565b5f805f606084860312156138b6575f80fd5b6138bf84613611565b925060208401356138cf81613591565b929592945050506040919091013590565b5f805f606084860312156138f2575f80fd5b6138fb84613611565b9250602084013591506136cd60408501613611565b5f8060408385031215613921575f80fd5b823591506135de602084016135a5565b5f8060408385031215613942575f80fd5b823561394d81613591565b9150602083013561395d81613591565b809150509250929050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f6001600160401b03821115613a1857613a186136d6565b5060051b60200190565b803560048110612f80575f80fd5b5f82601f830112613a3f575f80fd5b81356020613a54613a4f83613a00565b613712565b82815260059290921b84018101918181019086841115613a72575f80fd5b8286015b848110156118ca5780356001600160401b03811115613a93575f80fd5b613aa18986838b0101613742565b845250918301918301613a76565b5f6020808385031215613ac0575f80fd5b82356001600160401b0380821115613ad6575f80fd5b818501915085601f830112613ae9575f80fd5b8135613af7613a4f82613a00565b81815260059190911b83018401908481019088831115613b15575f80fd5b8585015b83811015613be057803585811115613b2f575f80fd5b860160c0818c03601f19011215613b44575f80fd5b613b4c6136ea565b613b57898301613611565b81526040613b66818401613611565b8a8301526060808401358284015260809150613b83828501613a22565b9083015260a08381013589811115613b99575f80fd5b613ba78f8d83880101613a30565b838501525060c0840135915088821115613bbf575f80fd5b613bcd8e8c84870101613a30565b9083015250845250918601918601613b19565b5098975050505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156105b8576105b8613c01565b5f60208284031215613c38575f80fd5b5051919050565b5f60208284031215613c4f575f80fd5b81516106fa81613591565b634e487b7160e01b5f52602160045260245ffd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b80516020808301519190811015613cd9575f198160200360031b1b821691505b50919050565b808201808211156105b8576105b8613c01565b5f5b83811015613d0c578181015183820152602001613cf4565b50505f910152565b5f8251613d25818460208701613cf2565b9190910192915050565b634e487b7160e01b5f52601260045260245ffd5b5f60ff831680613d5557613d55613d2f565b8060ff84160691505092915050565b60ff82811682821603908111156105b8576105b8613c01565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b5f60018201613dfe57613dfe613c01565b5060010190565b5f8351613e16818460208801613cf2565b835190830190613e2a818360208801613cf2565b01949350505050565b60ff81811683821601908111156105b8576105b8613c01565b5f82613e5a57613e5a613d2f565b500490565b80820281158282048414176105b8576105b8613c01565b600181815b80851115613eb057815f1904821115613e9657613e96613c01565b80851615613ea357918102915b93841c9390800290613e7b565b509250929050565b5f82613ec6575060016105b8565b81613ed257505f6105b8565b8160018114613ee85760028114613ef257613f0e565b60019150506105b8565b60ff841115613f0357613f03613c01565b50506001821b6105b8565b5060208310610133831016604e8410600b8410161715613f31575081810a6105b8565b613f3b8383613e76565b805f1904821115613f4e57613f4e613c01565b029392505050565b5f6106fa8383613eb8565b5f82613f6f57613f6f613d2f565b500690565b602081525f8251806020840152613f92816040850160208701613cf2565b601f01601f1916919091016040019291505056fe524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220086245f267c0f9365ffe3853d097cbfffb98727240039a42f202338e33d37bc464736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x00000000000000000000000000000000000000000000000000000000000000c9": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000000006", + "0xbc2e0095be465e411e3dd16b362c4b34019fb4f63830e31f0f7f61874e707e22": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000000005" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x6080604052600436106101c5575f3560e01c80638551f41e116100f2578063c3f909d411610092578063f2fde38b11610062578063f2fde38b1461051f578063f535bd561461053e578063f940e3851461055e578063ff4d18151461057d575f80fd5b8063c3f909d414610490578063da69d3db146104cd578063dac5df78146104ec578063e30c397814610502575f80fd5b80638da5cb5b116100cd5780638da5cb5b146104105780639ee512f21461042d578063a7e022d114610452578063a86f9d9e14610471575f80fd5b80638551f41e146103985780638ae5449c146103c45780638aff87b2146103ea575f80fd5b80634f1ef28611610168578063715018a611610138578063715018a61461034957806379ba50971461035d5780637f07c947146103715780638456cb5914610384575f80fd5b80634f1ef286146102e357806352d1902d146102f65780635950f9f11461030a5780635c975abb14610329575f80fd5b80633659cfe6116101a35780633659cfe6146102585780633ab76e9f146102795780633eb6b8cf146102b05780633f4ba83a146102cf575f80fd5b806323ac7136146101c95780632f980473146101fb57806333d5ac9b14610219575b5f80fd5b3480156101d4575f80fd5b506101e86101e3366004612242565b61059c565b6040519081526020015b60405180910390f35b348015610206575f80fd5b505f5b60405190151581526020016101f2565b348015610224575f80fd5b5061012f5461024090600160401b90046001600160401b031681565b6040516001600160401b0390911681526020016101f2565b348015610263575f80fd5b50610277610272366004612271565b6105f9565b005b348015610284575f80fd5b50609754610298906001600160a01b031681565b6040516001600160a01b0390911681526020016101f2565b3480156102bb575f80fd5b506102986102ca366004612299565b6106df565b3480156102da575f80fd5b506102776106f5565b6102776102f1366004612374565b610774565b348015610301575f80fd5b506101e8610843565b348015610315575f80fd5b506102776103243660046123c0565b6108f4565b348015610334575f80fd5b5061020960c954610100900460ff1660021490565b348015610354575f80fd5b50610277610ab0565b348015610368575f80fd5b50610277610ac1565b61027761037f366004612419565b610b38565b34801561038f575f80fd5b50610277610dcf565b3480156103a3575f80fd5b506101e86103b2366004612484565b61012d6020525f908152604090205481565b3480156103cf575f80fd5b506103d8600581565b60405160ff90911681526020016101f2565b3480156103f5575f80fd5b5060fb5461024090600160401b90046001600160401b031681565b34801561041b575f80fd5b506033546001600160a01b0316610298565b348015610438575f80fd5b5061029871777735367b36bc9b61c50022d9d0700db4ec81565b34801561045d575f80fd5b506101e861046c3660046124b3565b610e40565b34801561047c575f80fd5b5061029861048b3660046124e6565b610e71565b34801561049b575f80fd5b5060408051808201825263039387008082526008602092830190815283519182525160ff1691810191909152016101f2565b3480156104d8575f80fd5b506102776104e7366004612514565b610e86565b3480156104f7575f80fd5b506101e861012e5481565b34801561050d575f80fd5b506065546001600160a01b0316610298565b34801561052a575f80fd5b50610277610539366004612271565b61118d565b348015610549575f80fd5b5061012f54610240906001600160401b031681565b348015610569575f80fd5b50610277610578366004612559565b6111fe565b348015610588575f80fd5b5060fb54610240906001600160401b031681565b5f43826001600160401b0316106105b457505f919050565b436105c183610100612599565b6001600160401b0316106105dd57506001600160401b03164090565b506001600160401b03165f90815261012d602052604090205490565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000001000116300361064a5760405162461bcd60e51b8152600401610641906125c0565b60405180910390fd5b7f00000000000000000000000001670020000000000000000000000000000100016001600160a01b03166106925f805160206128e9833981519152546001600160a01b031690565b6001600160a01b0316146106b85760405162461bcd60e51b81526004016106419061260c565b6106c1816113b9565b604080515f808252602082019092526106dc918391906113c1565b50565b5f6106eb84848461152b565b90505b9392505050565b61070960c954610100900460ff1660021490565b6107265760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1610772336113b9565b565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000100011630036107bc5760405162461bcd60e51b8152600401610641906125c0565b7f00000000000000000000000001670020000000000000000000000000000100016001600160a01b03166108045f805160206128e9833981519152546001600160a01b031690565b6001600160a01b03161461082a5760405162461bcd60e51b81526004016106419061260c565b610833826113b9565b61083f828260016113c1565b5050565b5f306001600160a01b037f000000000000000000000000016700200000000000000000000000000001000116146108e25760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610641565b505f805160206128e983398151915290565b5f54610100900460ff161580801561091257505f54600160ff909116105b8061092b5750303b15801561092b57505f5460ff166001145b61098e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610641565b5f805460ff1916600117905580156109af575f805461ff0019166101001790555b6109ba858585611617565b6001461115806109d057506001600160401b0346115b156109ee576040516306cffa2760e01b815260040160405180910390fd5b4315610a395743600103610a20575f610a08600143612658565b5f81815261012d602052604090209040905550610a39565b604051635a0f9e4160e11b815260040160405180910390fd5b61012f805467ffffffffffffffff19166001600160401b038416179055610a5f436116a8565b5061012e558015610aa9575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050565b610ab8611738565b6107725f611792565b60655433906001600160a01b03168114610b2f5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610641565b6106dc81611792565b610b4c60c954610100900460ff1660021490565b15610b6a5760405163bae6e2a960e01b815260040160405180910390fd5b6562726964676560d01b610b7f816001610e71565b6001600160a01b0316336001600160a01b031614610bb057604051630d85cccf60e11b815260040160405180910390fd5b5f80610bbe8486018661266b565b60fb5491935091506001600160401b03808416600160401b9092041614610bf8576040516339985e7960e11b815260040160405180910390fd5b5f336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015610c35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c599190612687565b60fb5460408201519192506001600160401b039182169116141580610c9f57506033546001600160a01b03166001600160a01b031681602001516001600160a01b031614155b15610cbd57604051632efb161b60e21b815260040160405180910390fd5b5f306001600160a01b031683604051610cd6919061270f565b5f604051808303815f865af19150503d805f8114610d0f576040519150601f19603f3d011682016040523d82523d5f602084013e610d14565b606091505b5050905080610d3657604051630103c9e160e11b815260040160405180910390fd5b610d3f8361272a565b60fb80546001600160e01b03199290921691600160401b90046001600160401b0316906008610d6d83612761565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167f3c5c4a24a5f3333977c7d675661b0611a16f3c611b9ea63c0be82f4ffa9174c560405160405180910390a350505050505050565b610de360c954610100900460ff1660021490565b15610e015760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610761565b5f610e69610e6260408051808201909152630393870081526008602082015290565b84846117ab565b509392505050565b5f610e7d46848461152b565b90505b92915050565b6002610e906118df565b60ff1603610eb15760405163dfc60d8560e01b815260040160405180910390fd5b610ebb6002611918565b831580610ec6575082155b80610ed857506001600160401b038216155b80610ef3575043600114158015610ef3575063ffffffff8116155b15610f115760405163053fd54760e01b815260040160405180910390fd5b3371777735367b36bc9b61c50022d9d0700db4ec14610f4357604051636494e9f760e01b815260040160405180910390fd5b5f1943015f80610f52836116a8565b915091508161012e5414610f795760405163d719258d60e01b815260040160405180910390fd5b5f610f9860408051808201909152630393870081526008602082015290565b90505f610fa68288886117ab565b61012f805467ffffffffffffffff19166001600160401b03929092169190911790559050488114610fea576040516336d54d4f60e11b815260040160405180910390fd5b61012f5461100a90600590600160401b90046001600160401b0316612599565b6001600160401b0316876001600160401b031611156111165761103e6d7369676e616c5f7365727669636560901b5f610e71565b60fb546040516313e4299d60e21b81526001600160401b0391821660048201527f73e6d340850343cc6f001515dc593377337c95a6ffe034fe1e844d4dab5da16960248201529089166044820152606481018a90526001600160a01b039190911690634f90a674906084016020604051808303815f875af11580156110c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e99190612786565b5061012f80546fffffffffffffffff00000000000000001916600160401b6001600160401b038a16021790555b5f85815261012d602090815260409182902087409081905561012e86905561012f5483519182526001600160401b0316918101919091527f41c3f410f5c8ac36bb46b1dccef0de0f964087c9e688795fa02ecfa2c20b3fe4910160405180910390a150505050506111876001611918565b50505050565b611195611738565b606580546001600160a01b0383166001600160a01b031990911681179091556111c66033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b693bb4ba34323930bbb2b960b11b61121e6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561125b5750611245816001610e71565b6001600160a01b0316336001600160a01b031614155b1561127957604051630d85cccf60e11b815260040160405180910390fd5b60026112836118df565b60ff16036112a45760405163dfc60d8560e01b815260040160405180910390fd5b6112ae6002611918565b6112c260c954610100900460ff1660021490565b156112e05760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0382166113075760405163053fd54760e01b815260040160405180910390fd5b6001600160a01b03831661132d576113286001600160a01b0383164761195a565b6113aa565b6040516370a0823160e01b81523060048201526113aa9083906001600160a01b038616906370a0823190602401602060405180830381865afa158015611375573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113999190612786565b6001600160a01b0386169190611965565b6113b46001611918565b505050565b6106dc611738565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156113f4576113b4836119b7565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561144e575060408051601f3d908101601f1916820190925261144b91810190612786565b60015b6114b15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610641565b5f805160206128e9833981519152811461151f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610641565b506113b4838383611a52565b6097545f906001600160a01b031661155657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa1580156115ac573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d0919061279d565b9050811580156115e757506001600160a01b038116155b156106ee57604051632b0d65db60e01b81526001600160401b038516600482015260248101849052604401610641565b5f54610100900460ff1661163d5760405162461bcd60e51b8152600401610641906127b8565b6116478383611a76565b6001600160401b0381161580611665575046816001600160401b0316145b156116835760405163f49a838160e01b815260040160405180910390fd5b60fb805467ffffffffffffffff19166001600160401b03929092169190911790555050565b5f806116b261220e565b5f5b60ff811080156116c75750806001018510155b156116f8575f198186030180408360ff830661010081106116ea576116ea612817565b6020020152506001016116b4565b5046611fe08201526120008120925083408161171560ff8761282b565b610100811061172657611726612817565b60200201526120009020919391925050565b6033546001600160a01b031633146107725760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610641565b606580546001600160a01b03191690556106dc81611ad5565b61012f545f9081906001600160401b0316156118cb5761012f545f906117e19063ffffffff8616906001600160401b031661283e565b61012f549091505f90600160401b90046001600160401b03161580159061181e575061012f546001600160401b03600160401b9091048116908716115b1561184d5761012f5461184190600160401b90046001600160401b031687612851565b6001600160401b031690505b80156118855786515f906118679063ffffffff1683612871565b9050808311611877576001611881565b6118818184612658565b9250505b611896826001600160401b03611b26565b92506118c6836001600160401b0316885f015163ffffffff16896020015160ff166118c19190612871565b611b3a565b935050505b815f036118d757600191505b935093915050565b5f4660010361190e57507fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5c90565b5060c95460ff1690565b4660010361194657807fa5054f728453d3dbe953bdc43e4d0cb97e662ea32d7958190f3dc2da31d9721a5d50565b60c9805460ff831660ff1990911617905550565b61083f82825a611b83565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526113b4908490611be7565b6001600160a01b0381163b611a245760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610641565b5f805160206128e983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611a5b83611cb8565b5f82511180611a675750805b156113b4576111878383611cf7565b5f54610100900460ff16611a9c5760405162461bcd60e51b8152600401610641906127b8565b611aa582611d1c565b6001600160a01b038116611acc576040516375cabfef60e11b815260040160405180910390fd5b61083f81611d4c565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b5f818311611b345782610e7d565b50919050565b5f815f03611b5b57604051636296f1b960e11b815260040160405180910390fd5b81670de0b6b3a7640000611b6f8585611dbc565b611b799190612888565b610e7d9190612888565b6001600160a01b038316611baa57604051634c67134d60e11b815260040160405180910390fd5b5f611bc68483856040805180602001604052805f815250611e0b565b5090508061118757604051634c67134d60e11b815260040160405180910390fd5b5f611c3b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611e909092919063ffffffff16565b8051909150156113b45780806020019051810190611c59919061289b565b6113b45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610641565b611cc1816119b7565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b6060610e7d838360405180606001604052806027815260200161290960279139611e9e565b611d3a6001600160a01b03821615611d345781611792565b33611792565b5060c9805461ff001916610100179055565b5f54610100900460ff16611d725760405162461bcd60e51b8152600401610641906127b8565b6001600160401b03461115611d9a5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b5f8082611dd1670de0b6b3a764000086612871565b611ddb9190612888565b9050680755bf798b4a1bf1e4811115611dfa5750680755bf798b4a1bf1e45b611e0381611f12565b949350505050565b5f60605f805f8661ffff166001600160401b03811115611e2d57611e2d6122d8565b6040519080825280601f01601f191660200182016040528015611e57576020820181803683370190505b5090505f808751602089018b8e8ef191503d925086831115611e77578692505b828152825f602083013e90999098509650505050505050565b60606106eb84845f8561209a565b60605f80856001600160a01b031685604051611eba919061270f565b5f60405180830381855af49150503d805f8114611ef2576040519150601f19603f3d011682016040523d82523d5f602084013e611ef7565b606091505b5091509150611f0886838387612171565b9695505050505050565b5f680248ce36a70cb26b3e198213611f2b57505f919050565b680755bf798b4a1bf1e58212611f5457604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b0591505f60606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b6060824710156120fb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610641565b5f80866001600160a01b03168587604051612116919061270f565b5f6040518083038185875af1925050503d805f8114612150576040519150601f19603f3d011682016040523d82523d5f602084013e612155565b606091505b509150915061216687838387612171565b979650505050505050565b606083156121df5782515f036121d8576001600160a01b0385163b6121d85760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610641565b5081611e03565b611e0383838151156121f45781518083602001fd5b8060405162461bcd60e51b815260040161064191906128b6565b604051806120000160405280610100906020820280368337509192915050565b6001600160401b03811681146106dc575f80fd5b5f60208284031215612252575f80fd5b81356106ee8161222e565b6001600160a01b03811681146106dc575f80fd5b5f60208284031215612281575f80fd5b81356106ee8161225d565b80151581146106dc575f80fd5b5f805f606084860312156122ab575f80fd5b83356122b68161222e565b92506020840135915060408401356122cd8161228c565b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126122fb575f80fd5b81356001600160401b0380821115612315576123156122d8565b604051601f8301601f19908116603f0116810190828211818310171561233d5761233d6122d8565b81604052838152866020858801011115612355575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215612385575f80fd5b82356123908161225d565b915060208301356001600160401b038111156123aa575f80fd5b6123b6858286016122ec565b9150509250929050565b5f805f80608085870312156123d3575f80fd5b84356123de8161225d565b935060208501356123ee8161225d565b925060408501356123fe8161222e565b9150606085013561240e8161222e565b939692955090935050565b5f806020838503121561242a575f80fd5b82356001600160401b0380821115612440575f80fd5b818501915085601f830112612453575f80fd5b813581811115612461575f80fd5b866020828501011115612472575f80fd5b60209290920196919550909350505050565b5f60208284031215612494575f80fd5b5035919050565b803563ffffffff811681146124ae575f80fd5b919050565b5f80604083850312156124c4575f80fd5b82356124cf8161222e565b91506124dd6020840161249b565b90509250929050565b5f80604083850312156124f7575f80fd5b8235915060208301356125098161228c565b809150509250929050565b5f805f8060808587031215612527575f80fd5b843593506020850135925060408501356125408161222e565b915061254e6060860161249b565b905092959194509250565b5f806040838503121561256a575f80fd5b82356125758161225d565b915060208301356125098161225d565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b038181168382160190808211156125b9576125b9612585565b5092915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b81810381811115610e8057610e80612585565b5f806040838503121561267c575f80fd5b82356123908161222e565b5f60608284031215612697575f80fd5b604051606081018181106001600160401b03821117156126b9576126b96122d8565b6040528251815260208301516126ce8161225d565b602082015260408301516126e18161222e565b60408201529392505050565b5f5b838110156127075781810151838201526020016126ef565b50505f910152565b5f82516127208184602087016126ed565b9190910192915050565b805160208201516001600160e01b031980821692919060048310156127595780818460040360031b1b83161693505b505050919050565b5f6001600160401b0380831681810361277c5761277c612585565b6001019392505050565b5f60208284031215612796575f80fd5b5051919050565b5f602082840312156127ad575f80fd5b81516106ee8161225d565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f8261283957612839612803565b500690565b80820180821115610e8057610e80612585565b6001600160401b038281168282160390808211156125b9576125b9612585565b8082028115828204841417610e8057610e80612585565b5f8261289657612896612803565b500490565b5f602082840312156128ab575f80fd5b81516106ee8161228c565b602081525f82518060208401526128d48160408501602087016126ed565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206294eebd0a1e2295f6326946d26a923ca45bc11d39d90a34f97088d8a49b0b1e64736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670020000000000000000000000000000010002", + "0x00000000000000000000000000000000000000000000000000000000000000fb": "0x0000000000000000000000000000000000000000000000000000000000007e7e", + "0x000000000000000000000000000000000000000000000000000000000000012f": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000012e": "0xb1cdc1a3b51cd0ae1113eb88f95dfd26aab10c50b39e31811e63cffc250b0da2", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000010001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff" + }, + "code": "0x6080604052600436106100fa575f3560e01c80635c975abb116100925780638da5cb5b116100625780638da5cb5b14610299578063a86f9d9e146102b6578063d8f4648f146102d5578063e30c3978146102f4578063f2fde38b14610311575f80fd5b80635c975abb1461022d578063715018a61461025d57806379ba5097146102715780638456cb5914610285575f80fd5b80633eb6b8cf116100cd5780633eb6b8cf146101c55780633f4ba83a146101e45780634f1ef286146101f857806352d1902d1461020b575f80fd5b806319ab453c146100fe57806328f713cc1461011f5780633659cfe6146101875780633ab76e9f146101a6575b5f80fd5b348015610109575f80fd5b5061011d610118366004610f4b565b610330565b005b34801561012a575f80fd5b5061016a610139366004610f82565b67ffffffffffffffff919091165f90815260fb6020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610192575f80fd5b5061011d6101a1366004610f4b565b610442565b3480156101b1575f80fd5b5060975461016a906001600160a01b031681565b3480156101d0575f80fd5b5061016a6101df366004610fb9565b61051f565b3480156101ef575f80fd5b5061011d610535565b61011d610206366004611006565b6105b4565b348015610216575f80fd5b5061021f61067f565b60405190815260200161017e565b348015610238575f80fd5b5061024d60c954610100900460ff1660021490565b604051901515815260200161017e565b348015610268575f80fd5b5061011d610730565b34801561027c575f80fd5b5061011d610741565b348015610290575f80fd5b5061011d6107b8565b3480156102a4575f80fd5b506033546001600160a01b031661016a565b3480156102c1575f80fd5b5061016a6102d03660046110c4565b610829565b3480156102e0575f80fd5b5061011d6102ef3660046110ee565b610835565b3480156102ff575f80fd5b506065546001600160a01b031661016a565b34801561031c575f80fd5b5061011d61032b366004610f4b565b610913565b5f54610100900460ff161580801561034e57505f54600160ff909116105b806103675750303b15801561036757505f5460ff166001145b6103cf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff1916600117905580156103f0575f805461ff0019166101001790555b6103f982610984565b801561043e575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b037f000000000000000000000000016700200000000000000000000000000001000216300361048a5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670020000000000000000000000000000100026001600160a01b03166104d25f80516020611265833981519152546001600160a01b031690565b6001600160a01b0316146104f85760405162461bcd60e51b81526004016103c690611177565b610501816109b4565b604080515f8082526020820190925261051c918391906109bc565b50565b5f61052b848484610b2b565b90505b9392505050565b61054960c954610100900460ff1660021490565b6105665760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a16105b233610c19565b565b6001600160a01b037f00000000000000000000000001670020000000000000000000000000000100021630036105fc5760405162461bcd60e51b81526004016103c69061112b565b7f00000000000000000000000001670020000000000000000000000000000100026001600160a01b03166106445f80516020611265833981519152546001600160a01b031690565b6001600160a01b03161461066a5760405162461bcd60e51b81526004016103c690611177565b610673826109b4565b61043e828260016109bc565b5f306001600160a01b037f0000000000000000000000000167002000000000000000000000000000010002161461071e5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016103c6565b505f8051602061126583398151915290565b610738610c31565b6105b25f610c8b565b60655433906001600160a01b031681146107af5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016103c6565b61051c81610c8b565b6107cc60c954610100900460ff1660021490565b156107ea5760405163bae6e2a960e01b815260040160405180910390fd5b60c9805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016105a1565b5f61052e468484610b2b565b61083d610c31565b67ffffffffffffffff83165f90815260fb602090815260408083208584529091529020546001600160a01b0390811690821681900361088f576040516327b026fb60e21b815260040160405180910390fd5b67ffffffffffffffff84165f81815260fb6020908152604080832087845282529182902080546001600160a01b0319166001600160a01b038781169182179092558351908152908516918101919091528592917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b61091b610c31565b606580546001600160a01b0383166001600160a01b0319909116811790915561094c6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6109a26001600160a01b0382161561099c5781610c8b565b33610c8b565b5060c9805461ff001916610100179055565b61051c610c31565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156109f4576109ef83610ca4565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610a4e575060408051601f3d908101601f19168201909252610a4b918101906111c3565b60015b610ab15760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016103c6565b5f805160206112658339815191528114610b1f5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016103c6565b506109ef838383610d3f565b6097545f906001600160a01b0316610b5657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015610bad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bd191906111da565b905081158015610be857506001600160a01b038116155b1561052e57604051632b0d65db60e01b815267ffffffffffffffff85166004820152602481018490526044016103c6565b60405162580a9560e71b815260040160405180910390fd5b6033546001600160a01b031633146105b25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103c6565b606580546001600160a01b031916905561051c81610d69565b6001600160a01b0381163b610d115760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016103c6565b5f8051602061126583398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610d4883610dba565b5f82511180610d545750805b156109ef57610d638383610df9565b50505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b610dc381610ca4565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a250565b606061052e83836040518060600160405280602781526020016112856027913960605f80856001600160a01b031685604051610e359190611217565b5f60405180830381855af49150503d805f8114610e6d576040519150601f19603f3d011682016040523d82523d5f602084013e610e72565b606091505b5091509150610e8386838387610e8d565b9695505050505050565b60608315610efb5782515f03610ef4576001600160a01b0385163b610ef45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c6565b5081610f05565b610f058383610f0d565b949350505050565b815115610f1d5781518083602001fd5b8060405162461bcd60e51b81526004016103c69190611232565b6001600160a01b038116811461051c575f80fd5b5f60208284031215610f5b575f80fd5b813561052e81610f37565b803567ffffffffffffffff81168114610f7d575f80fd5b919050565b5f8060408385031215610f93575f80fd5b610f9c83610f66565b946020939093013593505050565b80358015158114610f7d575f80fd5b5f805f60608486031215610fcb575f80fd5b610fd484610f66565b925060208401359150610fe960408501610faa565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611017575f80fd5b823561102281610f37565b9150602083013567ffffffffffffffff8082111561103e575f80fd5b818501915085601f830112611051575f80fd5b81358181111561106357611063610ff2565b604051601f8201601f19908116603f0116810190838211818310171561108b5761108b610ff2565b816040528281528860208487010111156110a3575f80fd5b826020860160208301375f6020848301015280955050505050509250929050565b5f80604083850312156110d5575f80fd5b823591506110e560208401610faa565b90509250929050565b5f805f60608486031215611100575f80fd5b61110984610f66565b925060208401359150604084013561112081610f37565b809150509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b5f602082840312156111d3575f80fd5b5051919050565b5f602082840312156111ea575f80fd5b815161052e81610f37565b5f5b8381101561120f5781810151838201526020016111f7565b50505f910152565b5f82516112288184602087016111f5565b9190910192915050565b602081525f82518060208401526112508160408501602087016111f5565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220cc98ce1f870c6bb16d1d5f2f7fbcc9dcf424754d8f8ecafbdf9491cb4cfd521764736f6c63430008180033", + "balance": "0x0" + }, + "0x1670020000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x000000000000000000000000e8b1ff302a740fd2c6e76b620d45508daec2ddff", + "0xfc9694a8343538ce007a3941bba4a8952c0d46b3a80d6bc5432a3731a9b3afbd": "0x0000000000000000000000001670020000000000000000000000000000010001", + "0x1f6e8365b88965465679d131196095b3fe883fdeef8915a26d29cc80b5f57057": "0x0000000000000000000000001670020000000000000000000000000000000001", + "0x3bd77107e0102c8f1a54b812ae852bf834e4d7d2e163cd6ad85e7fb146b8946b": "0x0000000000000000000000001670020000000000000000000000000000000005", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167002000000000000000000000000000010002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6057565b565b5f60527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156070573d5ff35b3d5ffdfea2646970667358221220d6ceb272ae2d4d61f9cc7a38749bb873b1073f8eb5767b833e88e4170acea6d564736f6c63430008180033", + "balance": "0x0" + }, + "0x0167002000000000000000000000000000010099": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000002710000", + "0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x215be5d23550ceb1beff54fb579a765903ba2ccc85b6f79bcf9bda4e8cb86034": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6d1035fce6503985ab075a4ff3f7ce2e57cd5a9c5e6a0589dccacfea7bcb0af4": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2a95ee547cef07a2fff0a68144824a0d9ded35ed87da118a53e1cda4aca8b944": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x7fcecd2a720442e9bc0cf1a8a6976f9fbddf6b996dc0d78af7e94dadf360d579": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x18bbf5fcf8fe870ecff419c4677497c08b2e6a5431bb94541d06c9da3f308e55": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6e3431b4e42570cb9e3d926eb26f9e54de2df536ae0741ae16350d17a6c16ddc": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xdb302bf24b1ad5f23949da8e6b05747dc699499a995361a7bf40ec7204696d6f": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xa1d47ef1a6916dfbe65888f77739da164feb3a9a6afc95ee57e8b3e85ea5e955": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x454340b1295f9ff1c0fb9192166d0215d33f84dc5f2dc3f3e5732a4b557186bf": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6a3bb1dada7c82a99b4a02d16da3fda07cb31d8887b9b99ec829ab67fd7a817e": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2fe2844d12634f5dce1e2be5be96b2ea1c573f8f25171997e2f4bd943dd32f92": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x3836a017087644fbf6925ae1aca14201ce898a35434d9dea9ebd03cea44e049a": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1c7a29f5a750951acb14fdf82a876085914eb17f15a162b054a3d2f8c92e2451": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x271927a243b678b7a071f19b4051ef93b16e397066e3fdef5bba26527e34a1a1": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x4663d660b5d810c9ab2f6dc64af7ff84ebae28a72342391622649a7fe87c93d4": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x352c3281a58937f04ef7cc7b88f3456b6ffd47f52a321c253dc083fb53a3a114": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x6d5faa5f4e671e6fe47b0eab51c62f8cebf354e21e8fdccf8cdfc0293dd341a3": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x673de83553dc3a2c0f59aa7193de392a4530feb73b9d6cd4fcef68802b8195c1": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x8b6a7148182c39c1ca0b052292befa83d09344947c23e47b300314fa8c2b8f7d": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xed4a23b4a030ee0d64ef69b276dee81d493e5efca01c0fa514e0c38f882af152": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x45124dfaa1716b8d229f646ff926377e17b887c2b2eab6a87ab0348ee1689eac": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x40f9c2870c16301e8614e56453fc5b838c4a153eb0b18c4c050efbf4f786518a": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xbd55c9294669a294e0c8fd07e2c07738e95be0123b62b752d782fe317f25ca97": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x52c0eeeba21034a69ad7cfa70f75c6fd127acd4084a4da80f30cc7540bdf990b": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x843a9befd317bdcee99c42a3adf6d00b789224beda1485c7f6e7bf327755328e": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xea09b20615ffad342fb450741e59ea6ba180fa93b8701b31fa639ef9ff50d2b0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x39cd5e5ec54ce41a5f5b2c13ce7133998dfef654caacfb44d5c517700c217d36": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xd46a4409ebc9fc47afedecdadc89dbc0d6f46be6bdb49fd822d5143daedc83f0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x5735d6fad3ea4f2328a1557ff1be7570df3d4c2630b448c1b7fe2781d018beb0": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x509c640066f1872118ec768fcb985c7bf4476690788ac7e112ab072ca82ab219": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xf9982658df503b792c55f860aefa42588712c9069523324d4b9ce4d9a10e2e9c": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x87d11160035f8424b7163a397fc780b278af3de5a6caa2cb71bb2b46825ce159": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1dde801acf032acf4b3151b5edb82e0e4d872a54d9efbf3809d75efcbfa2bf8f": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x01aad34cdf9f8f5fca811e2fab1411b08778be71f547894fa0d9fafa5c1f60b2": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x65cee0cf3d643c3f3402a40ddebed72cec3dd6bac66974bff967dc0ef9e2faed": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0xaf6cadccd3f046eeb282ec0b08e44adbe45784a23f41d76b096ccb8e7f238e2b": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x2589e1958c4e4f4a5f777b0b92a3170cc21771a8d3580331a71232f8624f7628": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x1f27de92fedf410197c8a09d0f2f03372d92b75c9889a6a61cf491395877fbcf": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c8063395093511161006e578063395093511461011f57806370a082311461013257806395d89b411461015a578063a457c2d714610162578063a9059cbb14610175578063dd62ed3e14610188575f80fd5b806306fdde03146100aa578063095ea7b3146100c857806318160ddd146100eb57806323b872dd146100fd578063313ce56714610110575b5f80fd5b6100b261019b565b6040516100bf919061068a565b60405180910390f35b6100db6100d63660046106f1565b61022b565b60405190151581526020016100bf565b6002545b6040519081526020016100bf565b6100db61010b366004610719565b610244565b604051601281526020016100bf565b6100db61012d3660046106f1565b610267565b6100ef610140366004610752565b6001600160a01b03165f9081526020819052604090205490565b6100b2610288565b6100db6101703660046106f1565b610297565b6100db6101833660046106f1565b610316565b6100ef610196366004610772565b610323565b6060600380546101aa906107a3565b80601f01602080910402602001604051908101604052809291908181526020018280546101d6906107a3565b80156102215780601f106101f857610100808354040283529160200191610221565b820191905f5260205f20905b81548152906001019060200180831161020457829003601f168201915b5050505050905090565b5f3361023881858561034d565b60019150505b92915050565b5f33610251858285610470565b61025c8585856104e8565b506001949350505050565b5f336102388185856102798383610323565b61028391906107db565b61034d565b6060600480546101aa906107a3565b5f33816102a48286610323565b9050838110156103095760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b61025c828686840361034d565b5f336102388185856104e8565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103af5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610300565b6001600160a01b0382166104105760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610300565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f61047b8484610323565b90505f1981146104e257818110156104d55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610300565b6104e2848484840361034d565b50505050565b6001600160a01b03831661054c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610300565b6001600160a01b0382166105ae5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610300565b6001600160a01b0383165f90815260208190526040902054818110156106255760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610300565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104e2565b5f602080835283518060208501525f5b818110156106b65785810183015185820160400152820161069a565b505f604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b03811681146106ec575f80fd5b919050565b5f8060408385031215610702575f80fd5b61070b836106d6565b946020939093013593505050565b5f805f6060848603121561072b575f80fd5b610734846106d6565b9250610742602085016106d6565b9150604084013590509250925092565b5f60208284031215610762575f80fd5b61076b826106d6565b9392505050565b5f8060408385031215610783575f80fd5b61078c836106d6565b915061079a602084016106d6565b90509250929050565b600181811c908216806107b757607f821691505b6020821081036107d557634e487b7160e01b5f52602260045260245ffd5b50919050565b8082018082111561023e57634e487b7160e01b5f52601160045260245ffdfea26469706673582212207d26eda1fafdb8ea119f090edcd559b9fd9deb2d3bf8c80b33e02459e52c64ef64736f6c63430008180033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/jolnir.json b/crates/primitives/res/genesis/taiko/jolnir.json new file mode 100644 index 000000000000..a00a31b05cca --- /dev/null +++ b/crates/primitives/res/genesis/taiko/jolnir.json @@ -0,0 +1,189 @@ +{ + "0x19B4F9C381C7927FE33D853e48b560141A380C44": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0xFa9d666c396c64d155BDc23a2AAA53984939A4Ee": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0xb631796561d587AeEF2Fdd09AD33b8DE4bc92510": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x8a9f79C3dc6158E58484ceEd46d93c4B0bAD0824": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c80636892abdc1461003a575b600080fd5b61004d61004836600461170f565b610061565b604051901515815260200160405180910390f35b600080806100718486018661185f565b6040516bffffffffffffffffffffffff1960608c901b166020820152919350915060009081906100b490603401604051602081830303815290604052858d610150565b91509150816100d657604051639dbcc1a760e01b815260040160405180910390fd5b60006100e182610179565b90506000610108826002815181106100fb576100fb6118c3565b60200260200101516101b2565b905061013f8b60405160200161012091815260200190565b6040516020818303038152906040526101388c6102ba565b87846102cd565b9d9c50505050505050505050505050565b60006060600061015f866102e7565b905061016c818686610319565b9250925050935093915050565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906101ac906103f4565b92915050565b600060218260000151111561020e5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064015b60405180910390fd5b600080600061021c856105e0565b919450925090506000816001811115610237576102376118d9565b146102845760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610205565b60008386602001516102969190611905565b805190915060208410156102b05760208490036101000a90045b9695505050505050565b60606101ac6102c88361092a565b610a5e565b6000806102d9866102e7565b90506102b081868686610acd565b6060818051906020012060405160200161030391815260200190565b6040516020818303038152906040529050919050565b60006060600061032885610b0a565b9050600080600061033a848a89610c03565b8151929550909350915015808061034e5750815b61039a5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610205565b6000816103b657604051806020016040528060008152506103e2565b6103e2866103c5600188611918565b815181106103d5576103d56118c3565b6020026020010151611023565b919b919a509098505050505050505050565b6060600080610402846105e0565b9193509091506001905081600181111561041e5761041e6118d9565b1461046b5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610205565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816104845790505090506000835b86518110156105d5576020821061051d5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b6064820152608401610205565b60008061055a6040518060400160405280858c6000015161053e9190611918565b8152602001858c602001516105539190611905565b90526105e0565b5091509150604051806040016040528083836105769190611905565b8152602001848b6020015161058b9190611905565b8152508585815181106105a0576105a06118c3565b60209081029190910101526105b6600185611905565b93506105c28183611905565b6105cc9084611905565b925050506104b1565b508152949350505050565b6000806000808460000151116106385760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610205565b6020840151805160001a607f811161065d576000600160009450945094505050610923565b60b781116106d9576000610672608083611918565b9050808760000151116106c75760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610205565b60019550935060009250610923915050565b60bf81116107c85760006106ee60b783611918565b9050808760000151116107435760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610205565b600183015160208290036101000a900461075d8183611905565b8851116107ac5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610205565b6107b7826001611905565b965094506000935061092392505050565b60f781116108435760006107dd60c083611918565b9050808760000151116108325760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610205565b600195509350849250610923915050565b600061085060f783611918565b9050808760000151116108a55760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610205565b600183015160208290036101000a90046108bf8183611905565b8851116109075760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b6044820152606401610205565b610912826001611905565b965094506001935061092392505050565b9193909250565b606060008260405160200161094191815260200190565b604051602081830303815290604052905060005b602081101561099657818181518110610970576109706118c3565b01602001516001600160f81b0319166000036109965761098f8161192b565b9050610955565b60006109a3826020611918565b67ffffffffffffffff8111156109bb576109bb6117bc565b6040519080825280601f01601f1916602001820160405280156109e5576020820181803683370190505b50905060005b8151811015610a555783836109ff8161192b565b945081518110610a1157610a116118c3565b602001015160f81c60f81b828281518110610a2e57610a2e6118c3565b60200101906001600160f81b031916908160001a905350610a4e8161192b565b90506109eb565b50949350505050565b60608082516001148015610a8c5750608083600081518110610a8257610a826118c3565b016020015160f81c105b15610a985750816101ac565b610aa48351608061104a565b83604051602001610ab6929190611974565b604051602081830303815290604052905092915050565b6000806000610add878686610319565b91509150818015610aff57508051602080830191909120875191880191909120145b979650505050505050565b60606000610b1783610179565b90506000815167ffffffffffffffff811115610b3557610b356117bc565b604051908082528060200260200182016040528015610b7a57816020015b6040805180820190915260608082526020820152815260200190600190039081610b535790505b50905060005b8251811015610bfb576000610bad848381518110610ba057610ba06118c3565b60200260200101516111f4565b90506040518060400160405280610bc383610179565b815260200182815250838381518110610bde57610bde6118c3565b60200260200101819052505080610bf49061192b565b9050610b80565b509392505050565b600060606000806000610c1587611284565b90506000869050600080610c3c604051806040016040528060608152602001606081525090565b60005b8c51811015610ffb578c8181518110610c5a57610c5a6118c3565b602002602001015191508284610c709190611905565b9350610c7d600188611905565b965083600003610cda578482602001518051906020012014610cd55760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b6044820152606401610205565b610d9c565b602082602001515110610d41578482602001518051906020012014610cd55760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610205565b84610d4f83602001516113bd565b14610d9c5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610205565b610da860106001611991565b60ff1682600001515103610e165785518414610ffb576000868581518110610dd257610dd26118c3565b01602001518351805160f89290921c925060009183908110610df657610df66118c3565b60200260200101519050610e09816113e5565b9650600194505050610feb565b81515160011901610fa3576000610e2c8361141b565b9050600081600081518110610e4357610e436118c3565b016020015160f81c90506000610e5a6002836119c0565b610e659060026119e2565b90506000610e76848360ff1661143f565b90506000610e848b8a61143f565b90506000610e928383611475565b905060ff851660021480610ea9575060ff85166003145b15610ee357808351148015610ebe5750808251145b15610ed057610ecd818b611905565b99505b50600160ff1b9950610ffb945050505050565b60ff85161580610ef6575060ff85166001145b15610f4c5782518114610f165750600160ff1b9950610ffb945050505050565b610f3d8860000151600181518110610f3057610f306118c3565b60200260200101516113e5565b9a509750610feb945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b6064820152608401610205565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610205565b610ff48161192b565b9050610c3f565b50600160ff1b84148661100e878661143f565b909e909d50909b509950505050505050505050565b805180516060916101ac9161103a90600190611918565b81518110610ba057610ba06118c3565b60608060388410156110b1576040805160018082528183019092529060208201818036833701905050905061107f8385611991565b60f81b81600081518110611095576110956118c3565b60200101906001600160f81b031916908160001a9053506111ed565b600060015b6110c081876119fb565b156110e3576110ce8261192b565b91506110dc61010082611a0f565b90506110b6565b6110ee826001611905565b67ffffffffffffffff811115611106576111066117bc565b6040519080825280601f01601f191660200182016040528015611130576020820181803683370190505b50925061113d8583611991565b611148906037611991565b60f81b8360008151811061115e5761115e6118c3565b60200101906001600160f81b031916908160001a905350600190505b8181116111ea5761010061118e8284611918565b61119a90610100611b0a565b6111a490886119fb565b6111ae9190611b16565b60f81b8382815181106111c3576111c36118c3565b60200101906001600160f81b031916908160001a9053506111e38161192b565b905061117a565b50505b9392505050565b60606000806000611204856105e0565b91945092509050600081600181111561121f5761121f6118d9565b1461126c5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610205565b61127b856020015184846114ef565b95945050505050565b60606000825160026112969190611a0f565b67ffffffffffffffff8111156112ae576112ae6117bc565b6040519080825280601f01601f1916602001820160405280156112d8576020820181803683370190505b50905060005b83518110156113b65760048482815181106112fb576112fb6118c3565b01602001516001600160f81b031916901c82611318836002611a0f565b81518110611328576113286118c3565b60200101906001600160f81b031916908160001a9053506010848281518110611353576113536118c3565b0160200151611365919060f81c6119c0565b60f81b82611374836002611a0f565b61137f906001611905565b8151811061138f5761138f6118c3565b60200101906001600160f81b031916908160001a9053506113af8161192b565b90506112de565b5092915050565b60006020825110156113d157506020015190565b818060200190518101906101ac9190611b2a565b60006060602083600001511015611406576113ff83611598565b9050611412565b61140f836111f4565b90505b6111ed816113bd565b60606101ac61143a8360000151600081518110610ba057610ba06118c3565b611284565b60608251821061145e57506040805160208101909152600081526101ac565b6111ed83838486516114709190611918565b6115a3565b6000805b8084511180156114895750808351115b80156114da57508281815181106114a2576114a26118c3565b602001015160f81c60f81b6001600160f81b0319168482815181106114c9576114c96118c3565b01602001516001600160f81b031916145b156111ed576114e88161192b565b9050611479565b606060008267ffffffffffffffff81111561150c5761150c6117bc565b6040519080825280601f01601f191660200182016040528015611536576020820181803683370190505b50905080516000036115495790506111ed565b8484016020820160005b8581101561156b578281015182820152602001611553565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606101ac826116f9565b6060816115b181601f611905565b10156115f05760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610205565b826115fb8382611905565b101561163a5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610205565b6116448284611905565b845110156116885760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610205565b6060821580156116a75760405191506000825260208201604052610a55565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156116e05780518352602092830192016116c8565b5050858452601f01601f19166040525050949350505050565b60606101ac8260200151600084600001516114ef565b60008060008060008060a0878903121561172857600080fd5b8635955060208701356001600160a01b038116811461174657600080fd5b94506040870135935060608701359250608087013567ffffffffffffffff8082111561177157600080fd5b818901915089601f83011261178557600080fd5b81358181111561179457600080fd5b8a60208285010111156117a657600080fd5b6020830194508093505050509295509295509295565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126117e357600080fd5b813567ffffffffffffffff808211156117fe576117fe6117bc565b604051601f8301601f19908116603f01168101908282118183101715611826576118266117bc565b8160405283815286602085880101111561183f57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561187257600080fd5b823567ffffffffffffffff8082111561188a57600080fd5b611896868387016117d2565b935060208501359150808211156118ac57600080fd5b506118b9858286016117d2565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b808201808211156101ac576101ac6118ef565b818103818111156101ac576101ac6118ef565b60006001820161193d5761193d6118ef565b5060010190565b6000815160005b81811015611965576020818501810151868301520161194b565b50600093019283525090919050565b60006119896119838386611944565b84611944565b949350505050565b60ff81811683821601908111156101ac576101ac6118ef565b634e487b7160e01b600052601260045260246000fd5b600060ff8316806119d3576119d36119aa565b8060ff84160691505092915050565b60ff82811682821603908111156101ac576101ac6118ef565b600082611a0a57611a0a6119aa565b500490565b80820281158282048414176101ac576101ac6118ef565b600181815b80851115611a61578160001904821115611a4757611a476118ef565b80851615611a5457918102915b93841c9390800290611a2b565b509250929050565b600082611a78575060016101ac565b81611a85575060006101ac565b8160018114611a9b5760028114611aa557611ac1565b60019150506101ac565b60ff841115611ab657611ab66118ef565b50506001821b6101ac565b5060208310610133831016604e8410600b8410161715611ae4575081810a6101ac565b611aee8383611a26565b8060001904821115611b0257611b026118ef565b029392505050565b60006111ed8383611a69565b600082611b2557611b256119aa565b500690565b600060208284031215611b3c57600080fd5b505191905056fea26469706673582212204875324a0ffbec2ef4b8b54e737ba4f199bc66a7bbc669362262c64003f5eb4964736f6c63430008140033", + "balance": "0x0" + }, + "0xb2Bcd028F53637a4FC4E06C52d247F38f44cBe4d": { + "storage": {}, + "code": "0x7300000000000000000000000000000000000000003014608060405260043610620000735760003560e01c80632c6a56af1462000078578063634da63a14620000a257806378adc0d614620000ab578063881107d914620000e957806393522e3e146200012c578063c0619cc21462000145575b600080fd5b6200008f6200008936600462000567565b6200015c565b6040519081526020015b60405180910390f35b6200008f600a81565b818015620000b857600080fd5b50620000d0620000ca36600462000622565b62000205565b6040516001600160a01b03909116815260200162000099565b62000100620000fa366004620006e9565b62000265565b60408051825181526020808401516001600160a01b031690820152918101519082015260600162000099565b620001436200013d3660046200071c565b620003a6565b005b6200014362000156366004620007c8565b6200041a565b6040516304c68c7960e31b815260009083906001600160a01b0382169063263463c8906200018f908890600401620008bb565b602060405180830381865afa158015620001ad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001d39190620009d1565b91506001600160a01b038316620001fd576040516303f8a7d360e01b815260040160405180910390fd5b509392505050565b60006001600160a01b038416620002205762000220620009eb565b83838360405162000231906200052e565b6200023f9392919062000a01565b604051809103906000f0801580156200025c573d6000803e3d6000fd5b50949350505050565b6040805160608101825260008082526020820181905291810191909152336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015620002c1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002e7919062000a6d565b6040818101519051633632b1fb60e11b8152600481019190915260248101859052600060448201529091506001600160a01b03831690636c6563f690606401602060405180830381865afa15801562000344573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200036a919062000ad5565b6001600160a01b031681602001516001600160a01b031614620003a057604051636659b9bb60e11b815260040160405180910390fd5b92915050565b6001600160a01b0382161580620003ce5750826001600160a01b0316826001600160a01b0316145b15620003ed5760405163def9481360e01b815260040160405180910390fd5b6001600160a01b03811662000415576040516303f8a7d360e01b815260040160405180910390fd5b505050565b82518251146200043d5760405163196e8a4160e31b815260040160405180910390fd5b600a82511115620004615760405163e4a4c1c760e01b815260040160405180910390fd5b8015620004ce5760005b8251811015620004c8578381815181106200048a576200048a62000afc565b6020026020010151600014620004b357604051634299323b60e11b815260040160405180910390fd5b80620004bf8162000b12565b9150506200046b565b50505050565b60005b8351811015620004c857838181518110620004f057620004f062000afc565b60200260200101516000036200051957604051634299323b60e11b815260040160405180910390fd5b80620005258162000b12565b915050620004d1565b610dcf8062000b3b83390190565b6001600160a01b03811681146200055257600080fd5b50565b803562000562816200053c565b919050565b6000806000606084860312156200057d57600080fd5b833567ffffffffffffffff8111156200059557600080fd5b84016101808187031215620005a957600080fd5b92506020840135620005bb816200053c565b91506040840135620005cd816200053c565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156200061a576200061a620005d8565b604052919050565b6000806000606084860312156200063857600080fd5b833562000645816200053c565b925060208481013562000658816200053c565b9250604085013567ffffffffffffffff808211156200067657600080fd5b818701915087601f8301126200068b57600080fd5b813581811115620006a057620006a0620005d8565b620006b4601f8201601f19168501620005ee565b91508082528884828501011115620006cb57600080fd5b80848401858401376000848284010152508093505050509250925092565b60008060408385031215620006fd57600080fd5b82359150602083013562000711816200053c565b809150509250929050565b6000806000606084860312156200073257600080fd5b8335620005a9816200053c565b600082601f8301126200075157600080fd5b8135602067ffffffffffffffff821115620007705762000770620005d8565b8160051b62000781828201620005ee565b92835284810182019282810190878511156200079c57600080fd5b83870192505b84831015620007bd57823582529183019190830190620007a2565b979650505050505050565b600080600060608486031215620007de57600080fd5b833567ffffffffffffffff80821115620007f757600080fd5b62000805878388016200073f565b945060208601359150808211156200081c57600080fd5b506200082b868287016200073f565b92505060408401358015158114620005cd57600080fd5b6000808335601e198436030181126200085a57600080fd5b830160208101925035905067ffffffffffffffff8111156200087b57600080fd5b8036038213156200088b57600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208152813560208201526000620008d66020840162000555565b6001600160a01b0381166040840152506040830135606083015260608301356080830152620009086080840162000555565b6001600160a01b03811660a0840152506200092660a0840162000555565b6001600160a01b03811660c0840152506200094460c0840162000555565b6001600160a01b03811660e08401525061010060e08401358184015261012081850135818501526101409150808501358285015250620009878185018562000842565b91506101806101608181870152620009a56101a08701858562000892565b9350620009b58188018862000842565b878603601f19018489015293509050620007bd84848362000892565b600060208284031215620009e457600080fd5b5051919050565b634e487b7160e01b600052600160045260246000fd5b600060018060a01b038086168352602081861681850152606060408501528451915081606085015260005b8281101562000a4a5785810182015185820160800152810162000a2c565b50506000608082850101526080601f19601f830116840101915050949350505050565b60006060828403121562000a8057600080fd5b6040516060810181811067ffffffffffffffff8211171562000aa65762000aa6620005d8565b60405282518152602083015162000abd816200053c565b60208201526040928301519281019290925250919050565b60006020828403121562000ae857600080fd5b815162000af5816200053c565b9392505050565b634e487b7160e01b600052603260045260246000fd5b60006001820162000b3357634e487b7160e01b600052601160045260246000fd5b506001019056fe608060405260405162000dcf38038062000dcf833981016040819052620000269162000424565b828162000036828260006200004d565b50620000449050826200007f565b50505062000557565b6200005883620000f1565b600082511180620000665750805b156200007a5762000078838362000133565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f620000c160008051602062000d88833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a1620000ee8162000162565b50565b620000fc8162000200565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200015b838360405180606001604052806027815260200162000da86027913962000297565b9392505050565b6001600160a01b038116620001cd5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b8060008051602062000d888339815191525b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b6200026f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401620001c4565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc620001df565b6060600080856001600160a01b031685604051620002b6919062000504565b600060405180830381855af49150503d8060008114620002f3576040519150601f19603f3d011682016040523d82523d6000602084013e620002f8565b606091505b5090925090506200030c8683838762000316565b9695505050505050565b606083156200038a57825160000362000382576001600160a01b0385163b620003825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620001c4565b508162000396565b6200039683836200039e565b949350505050565b815115620003af5781518083602001fd5b8060405162461bcd60e51b8152600401620001c4919062000522565b80516001600160a01b0381168114620003e357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200041b57818101518382015260200162000401565b50506000910152565b6000806000606084860312156200043a57600080fd5b6200044584620003cb565b92506200045560208501620003cb565b60408501519092506001600160401b03808211156200047357600080fd5b818601915086601f8301126200048857600080fd5b8151818111156200049d576200049d620003e8565b604051601f8201601f19908116603f01168101908382118183101715620004c857620004c8620003e8565b81604052828152896020848701011115620004e257600080fd5b620004f5836020830160208801620003fe565b80955050505050509250925092565b6000825162000518818460208701620003fe565b9190910192915050565b602081526000825180602084015262000543816040850160208701620003fe565b601f01601f19169190910160400192915050565b61082180620005676000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220f7eab1ca665847bc4018294f96a153d69cce361a3d5f12cfd1bc2273590d44a364736f6c63430008140033", + "balance": "0x0" + }, + "0x455B9Bc4d78992D3c215AA37dEa16820d407b4c3": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c21ca915ccc921edec3de901a4d0348cf4bc5bff9797f582b0cf946ba041f74364736f6c63430008140033", + "balance": "0x0" + }, + "0xe1f32A7D3C6C23aA32B903E6518C5cEDa1233dE1": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122035fc1d40b735b2ee73e7108c8c67c328cd61e0193243acbff8377126b576539064736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000006": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100625760003560e01c8063656b06a414610067578063715018a6146100b75780638da5cb5b146100c1578063decd8e39146100d2578063e1c7392a146100e5578063f2fde38b146100ed575b600080fd5b61009b610075366004610466565b60009182526065602090815260408084209284529190529020546001600160a01b031690565b6040516001600160a01b03909116815260200160405180910390f35b6100bf610100565b005b6033546001600160a01b031661009b565b6100bf6100e03660046104a4565b610114565b6100bf6101d4565b6100bf6100fb3660046104d9565b6102ea565b610108610360565b61011260006103ba565b565b61011c610360565b6001600160a01b0381163b15801561013c57506001600160a01b03811633145b1561015a57604051630532024960e01b815260040160405180910390fd5b600083815260656020908152604080832085845282529182902080546001600160a01b038581166001600160a01b0319831681179093558451928352169181018290529091849186917fe41a6e8584d6e19a0dfc5f9331be4ebe61b5f025d45da164c9ca6ee9b837cea9910160405180910390a350505050565b600054610100900460ff16158080156101f45750600054600160ff909116105b8061020e5750303b15801561020e575060005460ff166001145b6102765760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610299576000805461ff0019166101001790555b6102a161040c565b80156102e7576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6102f2610360565b6001600160a01b0381166103575760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161026d565b6102e7816103ba565b6033546001600160a01b031633146101125760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161026d565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166104335760405162461bcd60e51b815260040161026d906104fb565b610112600054610100900460ff1661045d5760405162461bcd60e51b815260040161026d906104fb565b610112336103ba565b6000806040838503121561047957600080fd5b50508035926020909101359150565b80356001600160a01b038116811461049f57600080fd5b919050565b6000806000606084860312156104b957600080fd5b83359250602084013591506104d060408501610488565b90509250925092565b6000602082840312156104eb57600080fd5b6104f482610488565b9392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212209632508c2a715b76d0a2d3aa58ee92c804730127c9ce52ca1746b6dd53e3493564736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0xb1e89ee2bb78a419041fe24e740013159340b56d268f604f33f3c055e32347b5": "0x0000000000000000000000001000777700000000000000000000000000000001", + "0x13f577b9913c89bd350f4a404ebd8d505e1c9a69978cbcc8529fdd540bc949f3": "0x0000000000000000000000001000777700000000000000000000000000000004", + "0xd38903d6274a6db84688a349e4b3b67ae5c236d486bf6a62bd09314bf30ba140": "0x0000000000000000000000001000777700000000000000000000000000000002", + "0xbafc6b13b2f0c6eb23ba53cc40dafc5b57926d1acd46063721f26d168d8ac8e6": "0x0000000000000000000000001000777700000000000000000000000000000008", + "0xc278a37e264ab267ad37b6ee48041a93f8cea8fcfcaf9b7fd59d772e0ec551f1": "0x0000000000000000000000001000777700000000000000000000000000000009", + "0x72e9081aff0e8fea1bb15ead8a2c76d8049574549467dd79a558ba6534aacfed": "0x0000000000000000000000001000777700000000000000000000000000000003", + "0x03daec7c59de2c9cb8db9482af6aa07e46780a7bf4f7aa548e6a50a0b38b544d": "0x0000000000000000000000001000777700000000000000000000000000000007", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000006" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000001": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106101375760003560e01c8063715018a6116100b8578063bdd6bc361161007c578063bdd6bc36146102f3578063c7b9690814610306578063da69d3db14610320578063dac5df7814610333578063f2fde38b1461033c578063f535bd561461034f57600080fd5b8063715018a61461029b5780638da5cb5b146102a35780639ee512f2146102b4578063a7e022d1146102cd578063a86f9d9e146102e057600080fd5b80634e755573116100ff5780634e755573146101d6578063539b8ade14610218578063591aad8a146102435780635c82e9c2146102755780636c6563f61461028857600080fd5b80630599d2941461013c5780630652b57a1461016257806310da37381461017757806323ac71361461019e5780633ab76e9f146101b1575b600080fd5b61014f61014a36600461171c565b610369565b6040519081526020015b60405180910390f35b61017561017036600461174c565b6103b7565b005b61014f7f92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce3881565b61014f6101ac36600461171c565b610430565b6097546001600160a01b03165b6040516001600160a01b039091168152602001610159565b6101de6104aa565b6040805182516001600160801b031681526020808401516001600160401b0316908201529181015163ffffffff1690820152606001610159565b60cd5461022b906001600160401b031681565b6040516001600160401b039091168152602001610159565b610256610251366004611769565b61050d565b6040805160ff9094168452602084019290925290820152606001610159565b61017561028336600461179f565b610748565b6101be6102963660046117f0565b610b04565b610175610b1b565b6065546001600160a01b03166101be565b6101be71777735367b36bc9b61c50022d9d0700db4ec81565b61014f6102db366004611839565b610b2f565b6101be6102ee36600461186c565b610b54565b61014f61030136600461171c565b610b6a565b60cd5461022b90600160401b90046001600160401b031681565b61017561032e36600461188f565b610bb5565b61014f60cb5481565b61017561034a36600461174c565b610e1e565b60cd5461022b90600160801b90046001600160401b031681565b6000806001600160401b038316156103815782610395565b60cd54600160401b90046001600160401b03165b6001600160401b0316600090815260ca60205260409020600101549392505050565b6103bf610e97565b6001600160a01b0381166103e657604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600043826001600160401b03161061044a57506000919050565b43826001600160401b03161080156104765750610469610100436118eb565b826001600160401b031610155b1561048957506001600160401b03164090565b506001600160401b0316600090815260c9602052604090205490565b919050565b6040805160608101825260008082526020820181905291810191909152506040805160608101825260cc546001600160801b0381168252600160801b81046001600160401b03166020830152600160c01b900463ffffffff169181019190915290565b60008060008360ff1660011415801561052a57508360ff16600214155b156105485760405163bcd2d90d60e01b815260040160405180910390fd5b8360ff16600114610579577fc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee561059b565b7f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817985b915060008460ff166001146105d0577fad77eceea844778cb4376153fc8f06f12f1695df4585bf75bfb17ec19ce908186105f2565b7fb4a95509ce05fe8d45987859a067780d16a367c0e2cacf79cd301b93fb7179405b905060008560ff16600114610627577f71620584f61c57e688bbd3fd7a39a036e588d962c4c830f3dacbc15c917e02f2610649565b7f45b59254b0320fd853f3f38ac574999e91bd75fd5e6cab9c22c5e71fc6d276e45b82880192831001905060ff86166001036106835761067c8282600170014551231950b75fc4402da1732fc9bebe19610ef1565b92506106f2565b6106cb7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a16106c68484600170014551231950b75fc4402da1732fc9bebe19610ef1565b610f40565b90925090506106ef8282600170014551231950b75fc4402da1732fc9bebe19610ef1565b92505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561073f576107368370014551231950b75fc4402da1732fc9bebe196118eb565b92506001851894505b50509250925092565b600054610100900460ff16158080156107685750600054600160ff909116105b806107825750303b158015610782575060005460ff166001145b6107ea5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561080d576000805461ff0019166101001790555b600146111580610821575063ffffffff4610155b1561083f576040516306cffa2760e01b815260040160405180910390fd5b600143111561086157604051635a0f9e4160e11b815260040160405180910390fd5b61087160408301602084016118fe565b63ffffffff1615610a6057610889602083018361171c565b6001600160401b031615806108b457506108a9606083016040840161171c565b6001600160401b0316155b806108d557506108ca608083016060840161171c565b6001600160401b0316155b806108f657506108eb60a083016080840161171c565b6001600160401b0316155b1561091457604051639cc448b560e01b815260040160405180910390fd5b60008061095c61092a606086016040870161171c565b610937602087018761171c565b610947608088016060890161171c565b61095760a0890160808a0161171c565b610f5f565b91509150816001600160801b03166000148061098857506001600160401b036001600160801b03831610155b8061099a57506001600160801b038116155b156109b857604051639cc448b560e01b815260040160405180910390fd5b60cc80546001600160401b038416600160801b026001600160c01b03199091166001600160801b038416171790556109f660408501602086016118fe565b60cc805463ffffffff92909216600160c01b0263ffffffff60c01b199092169190911790556002610a2d606086016040870161171c565b610a37919061192f565b60cd60106101000a8154816001600160401b0302191690836001600160401b0316021790555050505b60cd805467ffffffffffffffff1916426001600160401b0316179055610a858361105e565b610a8e43611077565b5060cb554315610ab9576000610aa56001436118eb565b600081815260c96020526040902090409055505b8015610aff576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b6000610b1184848461110a565b90505b9392505050565b610b23610e97565b610b2d60006111be565b565b6000610b4c610b3c6104aa565b846001600160401b031684611210565b509392505050565b6000610b6146848461110a565b90505b92915050565b6000806001600160401b03831615610b825782610b96565b60cd54600160401b90046001600160401b03165b6001600160401b0316600090815260ca60205260409020549392505050565b3371777735367b36bc9b61c50022d9d0700db4ec14610be757604051636494e9f760e01b815260040160405180910390fd5b6000610bf46001436118eb565b90508040600080610c0484611077565b915091508160cb5414610c385760cb54604051636340d9fb60e11b81526004810191909152602481018390526044016107e1565b60cb819055600084815260c96020908152604080832086905560cd80546fffffffffffffffff00000000000000001916600160401b6001600160401b038c1690810291909117909155815180830183528c81528084018c815282865260ca8552948390209051815593516001949094019390935580518b81529182018a90527e4ce985b8852a486571d0545799251fd671adcf33b7854a5f0f6a6a2431a555910160405180910390a2600080610cec6104aa565b9050806040015163ffffffff16600014610d505760cd54610d22908290610d1c906001600160401b0316426118eb565b89611210565b60cd80546001600160401b03909216600160801b0267ffffffffffffffff60801b1990921691909117905591505b814814610d8357604051634083acad60e01b81526001600160401b038084166004830152481660248201526044016107e1565b60cd80546001600160401b0342811667ffffffffffffffff19909216821790925560408051438416815292851660208401524563ffffffff908116848301526060840192909252608083018890524460a08401524160c08401524690911660e0830152517ff5e89a4a67ffebdbc23df567479d3096c1dba4169c6bbf20ffc6b24d7f6e6e70918190036101000190a150505050505050505050565b610e26610e97565b6001600160a01b038116610e8b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016107e1565b610e94816111be565b50565b6065546001600160a01b03163314610b2d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016107e1565b600060405160408152602080820152602060408201528460608201528560808201528360a08201528260c082015260208160e08360056107d05a03fa610f3657600080fd5b5195945050505050565b6000806000198385098385029250828110838203039150509250929050565b600080856001600160401b0316600003610f7b57610f7b611955565b6000610f8860028861192f565b9050610fa66001600160401b038816680755bf798b4a1bf1e461196b565b9250610fc5610fc084886001600160401b031684896112ad565b61136c565b91506000610fd5848484896112ad565b90506000610fef858585610fea8b6002611985565b6112ad565b9050600082611000836127106119b0565b61100a91906119c7565b9050806001600160401b0316876001600160401b03161461105157604051631530943760e11b81526001600160401b038089166004830152821660248201526044016107e1565b5050505094509492505050565b6110666113d9565b61106e611408565b610e9481611437565b6000806110826116e5565b60005b60ff811080156110985750806001018510155b156110ca576000198186030180408360ff830661010081106110bc576110bc6119db565b602002015250600101611085565b5046611fe0820152612000812092508340816110e760ff876119f1565b61010081106110f8576110f86119db565b60200201526120009020919391925050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa15801561115b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117f9190611a05565b90508115801561119657506001600160a01b038116155b15610b1457604051631467050360e21b815260048101859052602481018490526044016107e1565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000806000856040015163ffffffff1685029050600061125f828663ffffffff1660cd60109054906101000a90046001600160401b03166001600160401b03160161148090919063ffffffff16565b90506112748282036001600160401b03611496565b9250505061129685602001516001600160401b031686600001518360006112ad565b9150816000036112a557600191505b935093915050565b60006001600160801b038516158015906112cf57506001600160801b03841615155b6112db576112db611955565b60006001600160401b038316156112f257826112f5565b60015b9050600061130c856001600160401b0316886114ab565b9050600061132c61131d8488611a22565b6001600160401b0316896114ab565b90506001600160801b0387166001600160401b03841661134c84846118eb565b61135691906119c7565b61136091906119c7565b98975050505050505050565b60006001600160801b038211156113d55760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016107e1565b5090565b600054610100900460ff166114005760405162461bcd60e51b81526004016107e190611a49565b610b2d6114fd565b600054610100900460ff1661142f5760405162461bcd60e51b81526004016107e190611a49565b610b2d61152a565b6001600160a01b03811661145e57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600081831161148f5781610b61565b5090919050565b60008183116114a55782610b61565b50919050565b6000806114c16001600160801b038416856119b0565b9050680755bf798b4a1bf1e481106114ec5760405163576ff4f160e01b815260040160405180910390fd5b6114f58161155a565b949350505050565b600054610100900460ff166115245760405162461bcd60e51b81526004016107e190611a49565b60018055565b600054610100900460ff166115515760405162461bcd60e51b81526004016107e190611a49565b610b2d336111be565b6000680248ce36a70cb26b3e19821361157557506000919050565b680755bf798b4a1bf1e5821261159e57604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b604051806120000160405280610100906020820280368337509192915050565b80356001600160401b03811681146104a557600080fd5b60006020828403121561172e57600080fd5b610b6182611705565b6001600160a01b0381168114610e9457600080fd5b60006020828403121561175e57600080fd5b8135610b1481611737565b6000806040838503121561177c57600080fd5b82359150602083013560ff8116811461179457600080fd5b809150509250929050565b60008082840360c08112156117b357600080fd5b83356117be81611737565b925060a0601f19820112156117d257600080fd5b506020830190509250929050565b803580151581146104a557600080fd5b60008060006060848603121561180557600080fd5b833592506020840135915061181c604085016117e0565b90509250925092565b803563ffffffff811681146104a557600080fd5b6000806040838503121561184c57600080fd5b61185583611705565b915061186360208401611825565b90509250929050565b6000806040838503121561187f57600080fd5b82359150611863602084016117e0565b600080600080608085870312156118a557600080fd5b84359350602085013592506118bc60408601611705565b91506118ca60608601611825565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b81810381811115610b6457610b646118d5565b60006020828403121561191057600080fd5b610b6182611825565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b038084168061194957611949611919565b92169190910492915050565b634e487b7160e01b600052600160045260246000fd5b60006001600160801b038084168061194957611949611919565b6001600160401b038181168382160280821691908281146119a8576119a86118d5565b505092915050565b8082028115828204841417610b6457610b646118d5565b6000826119d6576119d6611919565b500490565b634e487b7160e01b600052603260045260246000fd5b600082611a0057611a00611919565b500690565b600060208284031215611a1757600080fd5b8151610b1481611737565b6001600160401b03818116838216019080821115611a4257611a426118d5565b5092915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212205f4efdbc77034498385a78f6fb0b8114f654cc25350f8d3ca6d3701f54f91fd464736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000001": { + "storage": { + "0x00000000000000000000000000000000000000000000000000000000000000cb": "0x39d135ad4110ebf27f74d4b2e044581f2a2c91345cd1f81f6c0f3ab5e769f35f", + "0x00000000000000000000000000000000000000000000000000000000000000cc": "0x000000000028b0aa000000019fe2e7a60000001532d76dedb5e5af7fbea79f5e", + "0x00000000000000000000000000000000000000000000000000000000000000cd": "0x00000000000000000000000241ed2e8800000000000000000000000065001f60", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000001" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000004": { + "storage": {}, + "code": "0x60806040526004361061012e5760003560e01c8063620c23fb116100ab578063a86f9d9e1161006f578063a86f9d9e14610354578063ce70f39b14610374578063d0496d6a14610394578063ec9b312114610403578063f21be36f14610423578063f2fde38b1461044357600080fd5b8063620c23fb146102c15780636c6563f6146102e1578063715018a6146103015780638da5cb5b14610316578063a4444efd1461033457600080fd5b80634f5f9772116100f25780634f5f9772146101f45780635075a9d414610234578063540be6a3146102615780635d0bd98614610281578063606b5b74146102a157600080fd5b80630652b57a1461013a57806319ab453c1461015c578063263463c81461017c5780633ab76e9f146101af5780634c1888bc146101e157600080fd5b3661013557005b600080fd5b34801561014657600080fd5b5061015a610155366004612a0c565b610463565b005b34801561016857600080fd5b5061015a610177366004612a0c565b6104dc565b34801561018857600080fd5b5061019c610197366004612a42565b6105f4565b6040519081526020015b60405180910390f35b3480156101bb57600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020016101a6565b61019c6101ef366004612a42565b61060d565b34801561020057600080fd5b5061022461020f366004612a76565b600090815260cd602052604090205460ff1690565b60405190151581526020016101a6565b34801561024057600080fd5b5061025461024f366004612a76565b61063b565b6040516101a69190612ac7565b34801561026d57600080fd5b5061022461027c366004612a76565b610646565b34801561028d57600080fd5b5061022461029c366004612a76565b610652565b3480156102ad57600080fd5b5061019c6102bc366004612a76565b610665565b3480156102cd57600080fd5b5061015a6102dc366004612b1d565b610670565b3480156102ed57600080fd5b506101c96102fc366004612b93565b610696565b34801561030d57600080fd5b5061015a6106ad565b34801561032257600080fd5b506065546001600160a01b03166101c9565b34801561034057600080fd5b5061022461034f366004612bcc565b6106c1565b34801561036057600080fd5b506101c961036f366004612c1e565b6106d9565b34801561038057600080fd5b5061022461038f366004612bcc565b6106e6565b3480156103a057600080fd5b50604080516060808201835260008083526020808401829052928401528251808201845260ca5480825260cb546001600160a01b0390811683860190815260cc5493870193845286519283525116938101939093525192820192909252016101a6565b34801561040f57600080fd5b5061015a61041e366004612b1d565b6106f5565b34801561042f57600080fd5b5061015a61043e366004612c4e565b61070d565b34801561044f57600080fd5b5061015a61045e366004612a0c565b61072b565b61046b6107a4565b6001600160a01b03811661049257604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff16158080156104fc5750600054600160ff909116105b806105165750303b158015610516575060005460ff166001145b61057e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156105a1576000805461ff0019166101001790555b6105aa826107fe565b80156105f0576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061060761060283612da4565b610817565b92915050565b6000610617610847565b61062b60c93061062685612da4565b6108a0565b905061063660018055565b919050565b600061060782610b71565b60006106073083610b9c565b600061065e3083610c7d565b5092915050565b600061060782610d06565b610678610847565b61068860c9308585856001610d41565b61069160018055565b505050565b60006106a3848484610fbe565b90505b9392505050565b6106b56107a4565b6106bf6000611072565b565b60006106d030868686866110c4565b95945050505050565b60006106a6468484610fbe565b60006106d03086868686611227565b6106fd610847565b61068860c93085858560016114ac565b610715610847565b61072260c930848461197f565b6105f060018055565b6107336107a4565b6001600160a01b0381166107985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610575565b6107a181611072565b50565b6065546001600160a01b031633146106bf5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610575565b610806611b55565b61080e611b84565b6107a181611bb3565b60008160405160200161082a9190612eea565b604051602081830303815290604052805190602001209050919050565b6002600154036108995760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610575565b6002600155565b60808101516000906001600160a01b03166108ce576040516398fc91f160e01b815260040160405180910390fd5b6000806108df858560600151610c7d565b915091508115806108f35750468460600151145b156109115760405163e822b48d60e01b815260040160405180910390fd5b60a08401516001600160a01b031615806109405750806001600160a01b03168460a001516001600160a01b0316145b1561095e5760405163b9ad6a0f60e01b815260040160405180910390fd5b60008461010001518560e001516109759190612fed565b905034811461099757604051632609a19760e21b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0388169063a86f9d9e906109c790600190600401613000565b602060405180830381865afa1580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061301f565b9050610a1d6001600160a01b03821683611bfc565b8754886000610a2b8361303c565b909155508652336020870152466040870152610a4686610817565b604051635437cecf60e11b81529095506001600160a01b0388169063a86f9d9e90610a7690600090600401613055565b602060405180830381865afa158015610a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab7919061301f565b6001600160a01b03166366ca2bc0866040518263ffffffff1660e01b8152600401610ae491815260200190565b6020604051808303816000875af1158015610b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b279190613077565b50847f238646a410b383b664b8d2fe57d2895c1ecd3464a3159cae73a93a9f21a4335587604051610b589190612eea565b60405180910390a2505050509392505050565b60018055565b600080610b7d83610d06565b8054909150806003811115610b9457610b94612a8f565b949350505050565b604051635437cecf60e11b81526000906001600160a01b0384169063a86f9d9e90610bcb908490600401613055565b602060405180830381865afa158015610be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0c919061301f565b604051631933b5e360e11b8152306004820152602481018490526001600160a01b0391909116906332676bc690604401602060405180830381865afa158015610c59573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a69190613090565b600080836001600160a01b0316636c6563f68460016040518363ffffffff1660e01b8152600401610caf9291906130ad565b602060405180830381865afa158015610ccc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf0919061301f565b6001600160a01b03811615159590945092505050565b60006040518060400160405280600e81526020016d4d4553534147455f53544154555360901b8152508260405160200161082a9291906130cc565b6000610d4f61060286612da4565b600081815260048901602052604090205490915060ff1615610d845760405163bd7e9a9d60e01b815260040160405180910390fd5b818015610d9f5750610d9d868287606001358787611227565b155b15610dbd5760405163498b0b1d60e01b815260040160405180910390fd5b600081815260048089016020526040808320805460ff191660019081179091559051635437cecf60e11b81526001600160a01b038a169263a86f9d9e92610e0692909101613000565b602060405180830381865afa158015610e23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e47919061301f565b90506001600160a01b03811615610ebc5760405163ba0bbd9560e01b815230600482015260e087013560248201526001600160a01b0382169063ba0bbd9590604401600060405180830381600087803b158015610ea357600080fd5b505af1158015610eb7573d6000803e3d6000fd5b505050505b610ee6631953216560e11b610ed76040890160208a01612a0c565b6001600160a01b031690611cb2565b15610f6257610efb6040870160208801612a0c565b6001600160a01b03166332a642ca8760e00135886040518363ffffffff1660e01b8152600401610f2b919061315c565b6000604051808303818588803b158015610f4457600080fd5b505af1158015610f58573d6000803e3d6000fd5b5050505050610f89565b610f8960e0870135610f7a60a0890160808a01612a0c565b6001600160a01b031690611bfc565b60405182907fc6fbc1fa0145a394c9c414b2ae7bd634eb50dd888938bcd75692ae427b680fa290600090a25050505050505050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa15801561100f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611033919061301f565b90508115801561104a57506001600160a01b038116155b156106a657604051631467050360e21b81526004810185905260248101849052604401610575565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080866001600160a01b0316636c6563f68660006040518363ffffffff1660e01b81526004016110f69291906130ad565b602060405180830381865afa158015611113573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611137919061301f565b604051635437cecf60e11b81529091506001600160a01b0388169063a86f9d9e9061116790600090600401613055565b602060405180830381865afa158015611184573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a8919061301f565b6001600160a01b0316635221f61386838988886040518663ffffffff1660e01b81526004016111db959493929190613262565b602060405180830381865afa1580156111f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121c9190613090565b979650505050505050565b60004684036112495760405163e822b48d60e01b815260040160405180910390fd5b600085900361126b5760405163a6407c9360e01b815260040160405180910390fd5b60006112798385018561332b565b604051635437cecf60e11b8152647461696b6f60d81b60048201526000602482018190529192506001600160a01b0389169063a86f9d9e90604401602060405180830381865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f5919061301f565b82516101000151604051635eeb5e1b60e11b81526001600160401b0390911660048201526001600160a01b03919091169063bdd6bc3690602401602060405180830381865afa15801561134c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113709190613077565b90508015806113895750815161138590611d2b565b8114155b15611399576000925050506106d0565b815160600151604051633632b1fb60e11b8152738a9f79C3dc6158E58484ceEd46d93c4B0bAD082491636892abdc916001600160a01b038c1690636c6563f6906113ea908c906000906004016130ad565b602060405180830381865afa158015611407573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142b919061301f565b6114348b610d06565b602087015160405160e086901b6001600160e01b031916815261145f949392916003916004016134cf565b602060405180830381865af415801561147c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a09190613090565b98975050505050505050565b6101208401351580156114e057506114ca60a0850160808601612a0c565b6001600160a01b0316336001600160a01b031614155b156114fe5760405163398b635960e21b815260040160405180910390fd5b468460600135146115225760405163e822b48d60e01b815260040160405180910390fd5b600061153061060286612da4565b9050600061153d82610b71565b600381111561154e5761154e612a8f565b1461156c57604051630cfafbf960e01b815260040160405180910390fd5b6000866001600160a01b0316636c6563f6876040013560006040518363ffffffff1660e01b81526004016115a19291906130ad565b602060405180830381865afa1580156115be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e2919061301f565b90508280156116d45750604051635437cecf60e11b81526001600160a01b0388169063a86f9d9e9061161990600090600401613055565b602060405180830381865afa158015611636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061165a919061301f565b6001600160a01b0316635221f6138760400135838589896040518663ffffffff1660e01b8152600401611691959493929190613262565b602060405180830381865afa1580156116ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d29190613090565b155b156116f2576040516314504c7360e31b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0389169063a86f9d9e9061172290600190600401613000565b602060405180830381865afa15801561173f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611763919061301f565b90506001600160a01b038116156117f6576001600160a01b03811663ba0bbd95306117976101008b013560e08c0135612fed565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156117dd57600080fd5b505af11580156117f1573d6000803e3d6000fd5b505050505b6000803061180a60c08b0160a08c01612a0c565b6001600160a01b031614806118375750600061182c60c08b0160a08c01612a0c565b6001600160a01b0316145b1561184b57506002905060e08801356118c1565b600061185d60a08b0160808c01612a0c565b6001600160a01b0316336001600160a01b03161461188057896101200135611882565b5a5b905060006118928d8c8985611d50565b905080156118a357600293506118be565b600193506118be6001600160a01b03861660e08d0135611bfc565b50505b6118cb8583611ea7565b6000806118de60e08c0160c08d01612a0c565b6001600160a01b031614611901576118fc60e08b0160c08c01612a0c565b611911565b61191160a08b0160808c01612a0c565b90506001600160a01b038116330361194f576000611934836101008d0135612fed565b90506119496001600160a01b03831682611bfc565b50611971565b61195e336101008c0135611bfc565b6119716001600160a01b03821683611bfc565b505050505050505050505050565b610120820135158061198e5750805b156119d4576119a360a0830160808401612a0c565b6001600160a01b0316336001600160a01b0316146119d45760405163d7f4fc9f60e01b815260040160405180910390fd5b60006119e261060284612da4565b905060016119ef82610b71565b6003811115611a0057611a00612a8f565b14611a1e57604051631f6646b560e01b815260040160405180910390fd5b604051635437cecf60e11b81526000906001600160a01b0386169063a86f9d9e90611a4e90600190600401613000565b602060405180830381865afa158015611a6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8f919061301f565b90506001600160a01b03811615611b045760405163ba0bbd9560e01b815230600482015260e085013560248201526001600160a01b0382169063ba0bbd9590604401600060405180830381600087803b158015611aeb57600080fd5b505af1158015611aff573d6000803e3d6000fd5b505050505b6000611b128786855a611d50565b90508015611b2a57611b25836002611ea7565b611b4c565b611b35836003611ea7565b611b4c6001600160a01b03831660e0870135611bfc565b50505050505050565b600054610100900460ff16611b7c5760405162461bcd60e51b815260040161057590613502565b6106bf611f20565b600054610100900460ff16611bab5760405162461bcd60e51b815260040161057590613502565b6106bf611f47565b6001600160a01b038116611bda57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b801580611c1057506001600160a01b038216155b15611c19575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611c66576040519150601f19603f3d011682016040523d82523d6000602084013e611c6b565b606091505b50509050806106915760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401610575565b6040516301ffc9a760e01b81526001600160e01b0319821660048201526000906001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015611d1f575060408051601f3d908101601f19168201909252611d1c91810190613090565b60015b15610607579392505050565b600080611d41611d3c846000611f77565b612398565b80516020909101209392505050565b600081600003611d7357604051637f0e960960e11b815260040160405180910390fd5b6040518060600160405280848152602001856020016020810190611d979190612a0c565b6001600160a01b039081168252604087810135602093840152835160018a0155918301516002890180546001600160a01b0319169190921617905501516003860155611de960c0850160a08601612a0c565b6001600160a01b03168260e0860135611e0661014088018861354d565b604051611e14929190613593565b600060405180830381858888f193505050503d8060008114611e52576040519150601f19603f3d011682016040523d82523d6000602084013e611e57565b606091505b505060408051606081018252600180825260208201819052600019919092018190528782018290556002880180546001600160a01b03191690921790915560039096019590955550929392505050565b806003811115611eb957611eb9612a8f565b611ec283610b71565b6003811115611ed357611ed3612a8f565b146105f057611ee282826123dc565b817f0af4d5247f6a4028d6699afb62871a76b398da1d1a626c8a9b90e0bd5f54c73c8233604051611f149291906135a3565b60405180910390a25050565b600054610100900460ff16610b6b5760405162461bcd60e51b815260040161057590613502565b600054610100900460ff16611f6e5760405162461bcd60e51b815260040161057590613502565b6106bf33611072565b61020082015160609015611fe257611f90826011612fed565b6001600160401b03811115611fa757611fa7612c94565b604051908082528060200260200182016040528015611fda57816020015b6060815260200190600190039081611fc55790505b509050612051565b6101e083015115611ff857611f90826010612fed565b61200382600f612fed565b6001600160401b0381111561201a5761201a612c94565b60405190808252806020026020018201604052801561204d57816020015b60608152602001906001900390816120385790505b5090505b825161205c90612405565b8160008151811061206f5761206f6135c9565b60200260200101819052506120878360200151612405565b8160018151811061209a5761209a6135c9565b60200260200101819052506120b28360400151612418565b816002815181106120c5576120c56135c9565b60200260200101819052506120dd8360600151612405565b816003815181106120f0576120f06135c9565b60200260200101819052506121088360800151612405565b8160048151811061211b5761211b6135c9565b60200260200101819052506121338360a00151612405565b81600581518110612146576121466135c9565b602002602001018190525061217d8360c0015160405160200161216991906135df565b604051602081830303815290604052612441565b81600681518110612190576121906135c9565b60200260200101819052506121a88360e001516124b0565b816007815181106121bb576121bb6135c9565b60200260200101819052506121dd8361010001516001600160801b03166124b0565b816008815181106121f0576121f06135c9565b60200260200101819052506122098361012001516124be565b8160098151811061221c5761221c6135c9565b60200260200101819052506122358361014001516124be565b81600a81518110612248576122486135c9565b60200260200101819052506122618361016001516124be565b81600b81518110612274576122746135c9565b602002602001018190525061228d836101800151612441565b81600c815181106122a0576122a06135c9565b60200260200101819052506122b9836101a00151612405565b81600d815181106122cc576122cc6135c9565b6020026020010181905250612303836101c00151604051602001612169919060c09190911b6001600160c01b031916815260080190565b81600e81518110612316576123166135c9565b6020026020010181905250826101e0015160001461235b5761233c836101e001516124b0565b81600f8151811061234f5761234f6135c9565b60200260200101819052505b6102008301511561060757612374836102000151612405565b81601081518110612387576123876135c9565b602002602001018190525092915050565b606060006123a5836124d5565b90506123b3815160c061260a565b816040516020016123c5929190613614565b604051602081830303815290604052915050919050565b60006123e783610d06565b905060008260038111156123fd576123fd612a8f565b909155505050565b6060610607612413836127b3565b612441565b604051606082811b6bffffffffffffffffffffffff191660208301529061060790603401612169565b6060808251600114801561246f5750608083600081518110612465576124656135c9565b016020015160f81c105b1561247b575081610607565b6124878351608061260a565b83604051602001612499929190613614565b604051602081830303815290604052905092915050565b606061060761241383612865565b6060610607612413836001600160401b0316612865565b606081516000036124f657604080516000808252602082019092529061065e565b6000805b835181101561253b57838181518110612515576125156135c9565b602002602001015151826125299190612fed565b91506125348161303c565b90506124fa565b6000826001600160401b0381111561255557612555612c94565b6040519080825280601f01601f19166020018201604052801561257f576020820181803683370190505b50600092509050602081015b85518310156126015760008684815181106125a8576125a86135c9565b6020026020010151905060006020820190506125c68382845161298f565b8785815181106125d8576125d86135c9565b602002602001015151836125ec9190612fed565b92505050826125fa9061303c565b925061258b565b50949350505050565b6060806038841015612671576040805160018082528183019092529060208201818036833701905050905061263f8385613643565b60f81b81600081518110612655576126556135c9565b60200101906001600160f81b031916908160001a9053506106a6565b600060015b6126808187613672565b156126a35761268e8261303c565b915061269c61010082613686565b9050612676565b6126ae826001612fed565b6001600160401b038111156126c5576126c5612c94565b6040519080825280601f01601f1916602001820160405280156126ef576020820181803683370190505b5092506126fc8583613643565b612707906037613643565b60f81b8360008151811061271d5761271d6135c9565b60200101906001600160f81b031916908160001a905350600190505b8181116127a95761010061274d828461369d565b61275990610100613794565b6127639088613672565b61276d91906137a0565b60f81b838281518110612782576127826135c9565b60200101906001600160f81b031916908160001a9053506127a28161303c565b9050612739565b5050905092915050565b60606000826040516020016127ca91815260200190565b60408051808303601f1901815260208084528383019092529250600091829160208201818036833701905050905060005b815181101561260157838361280f8161303c565b945081518110612821576128216135c9565b602001015160f81c60f81b82828151811061283e5761283e6135c9565b60200101906001600160f81b031916908160001a90535061285e8161303c565b90506127fb565b606060008260405160200161287c91815260200190565b604051602081830303815290604052905060005b60208110156128d1578181815181106128ab576128ab6135c9565b01602001516001600160f81b0319166000036128d1576128ca8161303c565b9050612890565b60006128de82602061369d565b6001600160401b038111156128f5576128f5612c94565b6040519080825280601f01601f19166020018201604052801561291f576020820181803683370190505b50905060005b81518110156126015783836129398161303c565b94508151811061294b5761294b6135c9565b602001015160f81c60f81b828281518110612968576129686135c9565b60200101906001600160f81b031916908160001a9053506129888161303c565b9050612925565b8282825b602081106129cb57815183526129aa602084612fed565b92506129b7602083612fed565b91506129c460208261369d565b9050612993565b905182516020929092036101000a6000190180199091169116179052505050565b6001600160a01b03811681146107a157600080fd5b8035610636816129ec565b600060208284031215612a1e57600080fd5b81356106a6816129ec565b60006101808284031215612a3c57600080fd5b50919050565b600060208284031215612a5457600080fd5b81356001600160401b03811115612a6a57600080fd5b610b9484828501612a29565b600060208284031215612a8857600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60048110612ac357634e487b7160e01b600052602160045260246000fd5b9052565b602081016106078284612aa5565b60008083601f840112612ae757600080fd5b5081356001600160401b03811115612afe57600080fd5b602083019150836020828501011115612b1657600080fd5b9250929050565b600080600060408486031215612b3257600080fd5b83356001600160401b0380821115612b4957600080fd5b612b5587838801612a29565b94506020860135915080821115612b6b57600080fd5b50612b7886828701612ad5565b9497909650939450505050565b80151581146107a157600080fd5b600080600060608486031215612ba857600080fd5b83359250602084013591506040840135612bc181612b85565b809150509250925092565b60008060008060608587031215612be257600080fd5b843593506020850135925060408501356001600160401b03811115612c0657600080fd5b612c1287828801612ad5565b95989497509550505050565b60008060408385031215612c3157600080fd5b823591506020830135612c4381612b85565b809150509250929050565b60008060408385031215612c6157600080fd5b82356001600160401b03811115612c7757600080fd5b612c8385828601612a29565b9250506020830135612c4381612b85565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b0381118282101715612ccd57612ccd612c94565b60405290565b604080519081016001600160401b0381118282101715612ccd57612ccd612c94565b60405161022081016001600160401b0381118282101715612ccd57612ccd612c94565b600082601f830112612d2957600080fd5b81356001600160401b0380821115612d4357612d43612c94565b604051601f8301601f19908116603f01168101908282118183101715612d6b57612d6b612c94565b81604052838152866020858801011115612d8457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101808236031215612db757600080fd5b612dbf612caa565b82358152612dcf60208401612a01565b60208201526040830135604082015260608301356060820152612df460808401612a01565b6080820152612e0560a08401612a01565b60a0820152612e1660c08401612a01565b60c082015260e0838101359082015261010080840135908201526101208084013590820152610140808401356001600160401b0380821115612e5757600080fd5b612e6336838801612d18565b83850152610160925082860135915080821115612e7f57600080fd5b50612e8c36828701612d18565b918301919091525092915050565b60005b83811015612eb5578181015183820152602001612e9d565b50506000910152565b60008151808452612ed6816020860160208601612e9a565b601f01601f19169290920160200192915050565b602081528151602082015260006020830151612f1160408401826001600160a01b03169052565b5060408301516060830152606083015160808301526080830151612f4060a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610180610160808501829052612fb16101a0860184612ebe565b90860151858203601f190183870152909250612fcd8382612ebe565b9695505050505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561060757610607612fd7565b6a195d1a195c97dd985d5b1d60aa1b8152901515602082015260400190565b60006020828403121561303157600080fd5b81516106a6816129ec565b60006001820161304e5761304e612fd7565b5060010190565b6d7369676e616c5f7365727669636560901b8152901515602082015260400190565b60006020828403121561308957600080fd5b5051919050565b6000602082840312156130a257600080fd5b81516106a681612b85565b9182526562726964676560d01b60208301521515604082015260600190565b600083516130de818460208801612e9a565b9190910191825250602001919050565b6000808335601e1984360301811261310557600080fd5b83016020810192503590506001600160401b0381111561312457600080fd5b803603821315612b1657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815281356020820152600061317560208401612a01565b6001600160a01b03811660408401525060408301356060830152606083013560808301526131a560808401612a01565b6001600160a01b03811660a0840152506131c160a08401612a01565b6001600160a01b03811660c0840152506131dd60c08401612a01565b6001600160a01b03811660e08401525061010060e0840135818401526101208185013581850152610140915080850135828501525061321e818501856130ee565b9150610180610160818187015261323a6101a087018585613133565b9350613248818801886130ee565b878603601f1901848901529350905061121c848483613133565b85815260018060a01b038516602082015283604082015260806060820152600061121c608083018486613133565b600082601f8301126132a157600080fd5b6040516101008082018281106001600160401b03821117156132c5576132c5612c94565b604052830181858211156132d857600080fd5b845b828110156132f25780358252602091820191016132da565b509195945050505050565b80356001600160801b038116811461063657600080fd5b80356001600160401b038116811461063657600080fd5b60006020828403121561333d57600080fd5b81356001600160401b038082111561335457600080fd5b908301906040828603121561336857600080fd5b613370612cd3565b82358281111561337f57600080fd5b8301610300818803121561339257600080fd5b61339a612cf5565b81358152602082013560208201526133b460408301612a01565b6040820152606082013560608201526080820135608082015260a082013560a08201526133e48860c08401613290565b60c08201526101c08083013560e08301526101e06134038185016132fd565b610100840152610200613417818601613314565b61012085015261342a6102208601613314565b61014085015261343d6102408601613314565b6101608501526102608501358781111561345657600080fd5b6134628c828801612d18565b610180860152506102808501356101a08501526134826102a08601613314565b838501526102c0850135828501526102e08501358185015250505080835250506020830135828111156134b457600080fd5b6134c087828601612d18565b60208301525095945050505050565b85815260018060a01b038516602082015283604082015282606082015260a06080820152600061121c60a0830184612ebe565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000808335601e1984360301811261356457600080fd5b8301803591506001600160401b0382111561357e57600080fd5b602001915036819003821315612b1657600080fd5b8183823760009101908152919050565b604081016135b18285612aa5565b6001600160a01b039290921660209190910152919050565b634e487b7160e01b600052603260045260246000fd5b60008183825b60088110156136045781518352602092830192909101906001016135e5565b5050506101008201905092915050565b60008351613626818460208801612e9a565b83519083019061363a818360208801612e9a565b01949350505050565b60ff818116838216019081111561060757610607612fd7565b634e487b7160e01b600052601260045260246000fd5b6000826136815761368161365c565b500490565b808202811582820484141761060757610607612fd7565b8181038181111561060757610607612fd7565b600181815b808511156136eb5781600019048211156136d1576136d1612fd7565b808516156136de57918102915b93841c93908002906136b5565b509250929050565b60008261370257506001610607565b8161370f57506000610607565b8160018114613725576002811461372f5761374b565b6001915050610607565b60ff84111561374057613740612fd7565b50506001821b610607565b5060208310610133831016604e8410600b841016171561376e575081810a610607565b61377883836136b0565b806000190482111561378c5761378c612fd7565b029392505050565b60006106a683836136f3565b6000826137af576137af61365c565b50069056fea26469706673582212204997777a1031b83fdf2e825630d2f95588a7e236b52b64399419b4df680ff6ee64736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000004" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000002": { + "storage": {}, + "code": "0x608060405260043610620000fb5760003560e01c8063715018a61162000095578063c287e5781162000060578063c287e57814620002e0578063cb03d23c1462000314578063e2dc9033146200032b578063f2fde38b146200034257600080fd5b8063715018a6146200024b5780638da5cb5b14620002635780639aa8605c1462000283578063a86f9d9e14620002bb57600080fd5b806332a642ca11620000d657806332a642ca14620001965780633ab76e9f14620001ad57806367090ccf14620001e15780636c6563f6146200022657600080fd5b806301ffc9a714620001005780630652b57a146200014a57806319ab453c1462000171575b600080fd5b3480156200010d57600080fd5b50620001356200011f36600462002156565b6001600160e01b031916631953216560e11b1490565b60405190151581526020015b60405180910390f35b3480156200015757600080fd5b506200016f62000169366004620021a5565b62000367565b005b3480156200017e57600080fd5b506200016f62000190366004620021a5565b620003e3565b6200016f620001a7366004620021c5565b62000503565b348015620001ba57600080fd5b506097546001600160a01b03165b6040516001600160a01b03909116815260200162000141565b348015620001ee57600080fd5b50620001c86200020036600462002204565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200023357600080fd5b50620001c86200024536600462002246565b620007b5565b3480156200025857600080fd5b506200016f620007ce565b3480156200027057600080fd5b506065546001600160a01b0316620001c8565b3480156200029057600080fd5b50620002a8620002a2366004620021a5565b620007e6565b60405162000141959493929190620022d6565b348015620002c857600080fd5b50620001c8620002da3660046200232b565b62000947565b348015620002ed57600080fd5b5062000135620002ff366004620021a5565b60c96020526000908152604090205460ff1681565b6200016f6200032536600462002353565b6200095f565b6200016f6200033c366004620023c9565b62000c0f565b3480156200034f57600080fd5b506200016f62000361366004620021a5565b62000fb4565b6200037162001030565b6001600160a01b0381166200039957604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff1615808015620004045750600054600160ff909116105b80620004205750303b15801562000420575060005460ff166001145b620004895760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620004ad576000805461ff0019166101001790555b620004b8826200108c565b8015620004ff576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6200050d620010ab565b6562726964676560d01b6200052481600162000947565b6001600160a01b0316336001600160a01b0316146200055657604051630d85cccf60e11b815260040160405180910390fd5b60006200056e6562726964676560d01b600062000947565b90506000816001600160a01b031663263463c8856040518263ffffffff1660e01b8152600401620005a0919062002481565b602060405180830381865afa158015620005be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005e49190620025a2565b9050600080620005f9610140870187620025bc565b6200060991600490829062002606565b8101906200061891906200273f565b919450909250506001600160a01b038316905062000649576040516303f8a7d360e01b815260040160405180910390fd5b801562000739576001600160a01b038216600090815260c9602052604090205460ff1680620006a357506200068e6a3a30b4b5b7afba37b5b2b760a91b600162000947565b6001600160a01b0316826001600160a01b0316145b156200071157604051632770a7eb60e21b8152306004820152602481018290526001600160a01b03831690639dc29fac90604401600060405180830381600087803b158015620006f257600080fd5b505af115801562000707573d6000803e3d6000fd5b5050505062000739565b620007396200072760a0880160808901620021a5565b6001600160a01b038416908362001106565b6200074b60a0870160808801620021a5565b6001600160a01b0316837f75c5fedbd5fff6123ad9b70827e9742ea1eee996583d6e14249f1429fc4fd99384846040516200079b9291906001600160a01b03929092168252602082015260400190565b60405180910390a35050505050620007b260018055565b50565b6000620007c484848462001165565b90505b9392505050565b620007d862001030565b620007e460006200121f565b565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b03831693600160a01b90930460ff169290919062000828906200282d565b80601f016020809104026020016040519081016040528092919081815260200182805462000856906200282d565b8015620008a75780601f106200087b57610100808354040283529160200191620008a7565b820191906000526020600020905b8154815290600101906020018083116200088957829003601f168201915b505050505090806003018054620008be906200282d565b80601f0160208091040260200160405190810160405280929190818152602001828054620008ec906200282d565b80156200093d5780601f1062000911576101008083540402835291602001916200093d565b820191906000526020600020905b8154815290600101906020018083116200091f57829003601f168201915b5050505050905085565b60006200095646848462001165565b90505b92915050565b62000969620010ab565b6562726964676560d01b6200098081600162000947565b6001600160a01b0316336001600160a01b031614620009b257604051630d85cccf60e11b815260040160405180910390fd5b60405163881107d960e01b81526a195c98cc8c17dd985d5b1d60aa1b600482015230602482015260009073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d9063881107d990604401606060405180830381865af415801562000a19573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a3f919062002869565b905060004687350362000b1a5762000a5e6040880160208901620021a5565b905062000a7b6a3a30b4b5b7afba37b5b2b760a91b600162000947565b6001600160a01b0316816001600160a01b03160362000afe576040516340c10f1960e01b81526001600160a01b038681166004830152602482018690528216906340c10f1990604401600060405180830381600087803b15801562000adf57600080fd5b505af115801562000af4573d6000803e3d6000fd5b5050505062000b8e565b62000b146001600160a01b038216868662001106565b62000b8e565b62000b258762001271565b6040516340c10f1960e01b81526001600160a01b03878116600483015260248201879052919250908216906340c10f1990604401600060405180830381600087803b15801562000b7457600080fd5b505af115801562000b89573d6000803e3d6000fd5b505050505b62000ba36001600160a01b03861634620012d0565b815160408084015181519081526001600160a01b0384811660208301529181018790528188169291891691907f883b72735ca0ee2cdd2a462a393658b1a0b36ebd8756e4c22b7509a92ff86a029060600160405180910390a450505062000c0960018055565b50505050565b62000c19620010ab565b80356a195c98cc8c17dd985d5b1d60aa1b62000c3c6040840160208501620021a5565b62000c4e6060850160408601620021a5565b6001600160a01b038216158062000c83575062000c6e84846000620007b5565b6001600160a01b0316826001600160a01b0316145b1562000ca25760405163def9481360e01b815260040160405180910390fd5b6001600160a01b03811662000cca576040516303f8a7d360e01b815260040160405180910390fd5b846060013560000362000cf057604051634299323b60e11b815260040160405180910390fd5b600062000d7b6040518061018001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160608152602001606081525090565b608081015162000db49062000d9760608a0160408b01620021a5565b62000da960408b0160208c01620021a5565b8a606001356200138c565b61014083019190915287356060830181905233608084015290925062000deb906a195c98cc8c17dd985d5b1d60aa1b6000620007b5565b6001600160a01b031660a080830191909152608088013561012083015262000e179088013534620028d1565b60e08083019190915260a088013561010083015262000e3c90880160c08901620021a5565b6001600160a01b031660c082015262000e5960e0880188620025bc565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101608601949094525062000eac91506562726964676560d01b90508262000947565b6001600160a01b0316634c1888bc34846040518363ffffffff1660e01b815260040162000eda9190620028f3565b60206040518083038185885af115801562000ef9573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062000f209190620025a2565b905062000f346040890160208a01620021a5565b60808301516001600160a01b039182169116827f91462591aed3d13dcadac8ed73fdc175ec6e79b798ca205822e7ec33dc019e888b3562000f7c60608e0160408f01620021a5565b604080519283526001600160a01b039091166020830152810188905260600160405180910390a450505050505050620007b260018055565b62000fbe62001030565b6001600160a01b038116620010255760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000480565b620007b2816200121f565b6065546001600160a01b03163314620007e45760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000480565b62001096620019db565b620010a062001a0f565b620007b28162001a43565b600260015403620010ff5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000480565b6002600155565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526200115a90849062001a8d565b505050565b60018055565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015620011b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011dd9190620029e6565b905081158015620011f557506001600160a01b038116155b15620007c757604051631467050360e21b8152600481018590526024810184905260440162000480565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8035600090815260cb602090815260408083209183916200129891908601908601620021a5565b6001600160a01b03908116825260208201929092526040016000205416905080620012cb57620012c88262001b66565b90505b919050565b801580620012e557506001600160a01b038216155b15620012ef575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146200133e576040519150601f19603f3d011682016040523d82523d6000602084013e62001343565b606091505b50509050806200115a5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015260640162000480565b60606000620013cf6040518060a001604052806000815260200160006001600160a01b03168152602001600060ff16815260200160608152602001606081525090565b6001600160a01b038616600090815260c9602052604090205460ff161562001603576001600160a01b03868116600090815260ca6020908152604091829020825160a08101845281548152600182015494851692810192909252600160a01b90930460ff169181019190915260028201805491929160608401919062001455906200282d565b80601f016020809104026020016040519081016040528092919081815260200182805462001483906200282d565b8015620014d45780601f10620014a857610100808354040283529160200191620014d4565b820191906000526020600020905b815481529060010190602001808311620014b657829003601f168201915b50505050508152602001600382018054620014ef906200282d565b80601f01602080910402602001604051908101604052809291908181526020018280546200151d906200282d565b80156200156e5780601f1062001542576101008083540402835291602001916200156e565b820191906000526020600020905b8154815290600101906020018083116200155057829003601f168201915b5050509190925250505060208101519091506001600160a01b031662001598576200159862002a06565b604051632770a7eb60e21b8152336004820152602481018590526001600160a01b03871690639dc29fac90604401600060405180830381600087803b158015620015e157600080fd5b505af1158015620015f6573d6000803e3d6000fd5b505050508391506200197a565b60008690506040518060a00160405280468152602001886001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001667573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200168d919062002a1c565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620016d4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620016fe919081019062002a3c565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001742573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200176c919081019062002a3c565b905291506200178b6a3a30b4b5b7afba37b5b2b760a91b600162000947565b6001600160a01b0316876001600160a01b0316036200180f57604051632770a7eb60e21b8152336004820152602481018690526001600160a01b03881690639dc29fac90604401600060405180830381600087803b158015620017ed57600080fd5b505af115801562001802573d6000803e3d6000fd5b5050505084925062001978565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa15801562001857573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200187d9190620025a2565b6040516323b872dd60e01b8152336004820152306024820152604481018890529091506001600160a01b038316906323b872dd906064016020604051808303816000875af1158015620018d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018fa919062002abc565b506040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa15801562001942573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620019689190620025a2565b620019749190620028d1565b9350505b505b6040516332c0f48f60e21b906200199c9083908a908990879060240162002adc565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091529791965090945050505050565b600054610100900460ff1662001a055760405162461bcd60e51b8152600401620004809062002b79565b620007e462001e42565b600054610100900460ff1662001a395760405162461bcd60e51b8152600401620004809062002b79565b620007e462001e6c565b6001600160a01b03811662001a6b57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600062001ae4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662001ea19092919063ffffffff16565b8051909150156200115a578080602001905181019062001b05919062002abc565b6200115a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000480565b60008062001bc360008460405160200162001b82919062002bc4565b604051602081830303815290604052805190602001206040518060200162001baa9062002148565b601f1982820381018352601f9091011660405262001eb2565b905073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d6378adc0d68262001bf36065546001600160a01b031690565b609754636c0db62b60e01b906001600160a01b031662001c1a60408a0160208b01620021a5565b893562001c2e60608c0160408d0162002c5c565b62001c3d60608d018d620025bc565b62001c4c60808f018f620025bc565b60405160200162001c6598979695949392919062002c7c565b60408051601f198184030181529082905262001c85929160200162002cdf565b6040516020818303038152906040526040518463ffffffff1660e01b815260040162001cb49392919062002d12565b602060405180830381865af415801562001cd2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001cf89190620029e6565b6001600160a01b038116600090815260c960209081526040808320805460ff1916600117905560ca9091529020909250839062001d36828262002e60565b50508235600090815260cb6020908152604080832085939092909162001d6291908801908801620021a5565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031683602001602081019062001dc59190620021a5565b6001600160a01b031684357fb6b427556e8cb0ebf9175da4bc48c64c4f56e44cfaf8c3ab5ebf8e2ea130907962001e006060880188620025bc565b62001e0f60808a018a620025bc565b62001e2160608c0160408d0162002c5c565b60405162001e3495949392919062002ef3565b60405180910390a450919050565b600054610100900460ff166200115f5760405162461bcd60e51b8152600401620004809062002b79565b600054610100900460ff1662001e965760405162461bcd60e51b8152600401620004809062002b79565b620007e4336200121f565b6060620007c4848460008562001fbc565b60008347101562001f065760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640162000480565b815160000362001f595760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640162000480565b8282516020840186f590506001600160a01b038116620007c75760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640162000480565b6060824710156200201f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000480565b600080866001600160a01b031685876040516200203d919062002f34565b60006040518083038185875af1925050503d80600081146200207c576040519150601f19603f3d011682016040523d82523d6000602084013e62002081565b606091505b50915091506200209487838387620020a1565b925050505b949350505050565b60608315620021155782516000036200210d576001600160a01b0385163b6200210d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000480565b508162002099565b6200209983838151156200212c5781518083602001fd5b8060405162461bcd60e51b815260040162000480919062002f52565b6119788062002f6883390190565b6000602082840312156200216957600080fd5b81356001600160e01b031981168114620007c757600080fd5b6001600160a01b0381168114620007b257600080fd5b8035620012cb8162002182565b600060208284031215620021b857600080fd5b8135620007c78162002182565b600060208284031215620021d857600080fd5b813567ffffffffffffffff811115620021f057600080fd5b82016101808185031215620007c757600080fd5b600080604083850312156200221857600080fd5b8235915060208301356200222c8162002182565b809150509250929050565b8015158114620007b257600080fd5b6000806000606084860312156200225c57600080fd5b83359250602084013591506040840135620022778162002237565b809150509250925092565b60005b838110156200229f57818101518382015260200162002285565b50506000910152565b60008151808452620022c281602086016020860162002282565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260ff8416604082015260a0606082018190526000906200230b90830185620022a8565b82810360808401526200231f8185620022a8565b98975050505050505050565b600080604083850312156200233f57600080fd5b8235915060208301356200222c8162002237565b600080600080608085870312156200236a57600080fd5b843567ffffffffffffffff8111156200238257600080fd5b850160a081880312156200239557600080fd5b93506020850135620023a78162002182565b92506040850135620023b98162002182565b9396929550929360600135925050565b600060208284031215620023dc57600080fd5b813567ffffffffffffffff811115620023f457600080fd5b82016101008185031215620007c757600080fd5b6000808335601e198436030181126200242057600080fd5b830160208101925035905067ffffffffffffffff8111156200244157600080fd5b8036038213156200245157600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b602081528135602082015260006200249c6020840162002198565b6001600160a01b0381166040840152506040830135606083015260608301356080830152620024ce6080840162002198565b6001600160a01b03811660a084015250620024ec60a0840162002198565b6001600160a01b03811660c0840152506200250a60c0840162002198565b6001600160a01b03811660e08401525061010060e084013581840152610120818501358185015261014091508085013582850152506200254d8185018562002408565b915061018061016081818701526200256b6101a08701858562002458565b93506200257b8188018862002408565b878603601f190184890152935090506200259784848362002458565b979650505050505050565b600060208284031215620025b557600080fd5b5051919050565b6000808335601e19843603018112620025d457600080fd5b83018035915067ffffffffffffffff821115620025f057600080fd5b6020019150368190038213156200245157600080fd5b600080858511156200261757600080fd5b838611156200262557600080fd5b5050820193919092039150565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156200266e576200266e62002632565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715620026a057620026a062002632565b604052919050565b60ff81168114620007b257600080fd5b600067ffffffffffffffff821115620026d557620026d562002632565b50601f01601f191660200190565b600082601f830112620026f557600080fd5b81356200270c6200270682620026b8565b62002674565b8181528460208386010111156200272257600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080608085870312156200275657600080fd5b843567ffffffffffffffff808211156200276f57600080fd5b9086019060a082890312156200278457600080fd5b6200278e62002648565b823581526020830135620027a28162002182565b60208201526040830135620027b781620026a8565b6040820152606083013582811115620027cf57600080fd5b620027dd8a828601620026e3565b606083015250608083013582811115620027f657600080fd5b620028048a828601620026e3565b60808301525095506200281d9150506020860162002198565b9250620023b96040860162002198565b600181811c908216806200284257607f821691505b6020821081036200286357634e487b7160e01b600052602260045260246000fd5b50919050565b6000606082840312156200287c57600080fd5b6040516060810181811067ffffffffffffffff82111715620028a257620028a262002632565b604052825181526020830151620028b98162002182565b60208201526040928301519281019290925250919050565b818103818111156200095957634e487b7160e01b600052601160045260246000fd5b6020815281516020820152600060208301516200291b60408401826001600160a01b03169052565b50604083015160608301526060830151608083015260808301516200294b60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610180610160808501829052620029be6101a0860184620022a8565b90860151858203601f190183870152909250620029dc8382620022a8565b9695505050505050565b600060208284031215620029f957600080fd5b8151620007c78162002182565b634e487b7160e01b600052600160045260246000fd5b60006020828403121562002a2f57600080fd5b8151620007c781620026a8565b60006020828403121562002a4f57600080fd5b815167ffffffffffffffff81111562002a6757600080fd5b8201601f8101841362002a7957600080fd5b805162002a8a6200270682620026b8565b81815285602083850101111562002aa057600080fd5b62002ab382602083016020860162002282565b95945050505050565b60006020828403121562002acf57600080fd5b8151620007c78162002237565b60808152845160808201526000602086015160018060a01b0380821660a085015260ff60408901511660c08501526060880151915060a060e085015262002b28610120850183620022a8565b91506080880151607f198584030161010086015262002b488382620022a8565b9188166020860152506001600160a01b0386166040850152915062002b6a9050565b82606083015295945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60208152813560208201526000602083013562002be18162002182565b6001600160a01b031660408381019190915283013562002c0181620026a8565b60ff811660608401525062002c1a606084018462002408565b60a0608085015262002c3160c08501828462002458565b91505062002c43608085018562002408565b848303601f190160a0860152620029dc83828462002458565b60006020828403121562002c6f57600080fd5b8135620007c781620026a8565b6001600160a01b038981168252881660208201526040810187905260ff8616606082015260c06080820181905260009062002cbb908301868862002458565b82810360a084015262002cd081858762002458565b9b9a5050505050505050505050565b6001600160e01b031983168152815160009062002d0481600485016020870162002282565b919091016004019392505050565b6001600160a01b0384811682528316602082015260606040820181905260009062002ab390830184620022a8565b601f8211156200115a57600081815260208120601f850160051c8101602086101562002d695750805b601f850160051c820191505b8181101562002d8a5782815560010162002d75565b505050505050565b67ffffffffffffffff83111562002dad5762002dad62002632565b62002dc58362002dbe83546200282d565b8362002d40565b6000601f84116001811462002dfc576000851562002de35750838201355b600019600387901b1c1916600186901b17835562002e59565b600083815260209020601f19861690835b8281101562002e2f578685013582556020948501946001909201910162002e0d565b508682101562002e4d5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8135815560018101602083013562002e788162002182565b8154604085013562002e8a81620026a8565b60ff60a01b60a09190911b166001600160a01b03929092166001600160a81b0319919091161717905562002ec26060830183620025bc565b62002ed281836002860162002d92565b505062002ee36080830183620025bc565b62000c0981836003860162002d92565b60608152600062002f0960608301878962002458565b828103602084015262002f1e81868862002458565b91505060ff831660408301529695505050505050565b6000825162002f4881846020870162002282565b9190910192915050565b602081526000620009566020830184620022a856fe608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61188b806100ed6000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80636c6563f6116100c35780639dc29fac1161007c5780639dc29fac146102fa578063a457c2d71461030d578063a86f9d9e14610320578063a9059cbb14610333578063dd62ed3e14610346578063f2fde38b1461035957600080fd5b80636c6563f61461028a57806370a082311461029d578063715018a6146102c65780637cf8ed0d146102ce5780638da5cb5b146102e157806395d89b41146102f257600080fd5b8063313ce56711610115578063313ce5671461020e57806339509351146102235780633ab76e9f1461023657806340c10f191461025b57806349d126051461026e5780636c0db62b1461027757600080fd5b80630652b57a1461015d57806306fdde0314610172578063095ea7b31461019057806318160ddd146101b357806323b872dd146101c557806326afaadd146101d8575b600080fd5b61017061016b366004611349565b61036c565b005b61017a6103e5565b604051610187919061138a565b60405180910390f35b6101a361019e3660046113bd565b61041f565b6040519015158152602001610187565b60cb545b604051908152602001610187565b6101a36101d33660046113e9565b610439565b6101ef60fb5460fc546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610187565b60fd5460405160ff9091168152602001610187565b6101a36102313660046113bd565b610479565b6097546001600160a01b03165b6040516001600160a01b039091168152602001610187565b6101706102693660046113bd565b61049b565b6101b760fc5481565b6101706102853660046114cd565b610558565b61024361029836600461158c565b6106fe565b6101b76102ab366004611349565b6001600160a01b0316600090815260c9602052604090205490565b61017061070b565b60fb54610243906001600160a01b031681565b6065546001600160a01b0316610243565b61017a61071f565b6101706103083660046113bd565b6107b1565b6101a361031b3660046113bd565b61083b565b61024361032e3660046115c1565b6108c1565b6101a36103413660046113bd565b6108ce565b6101b76103543660046115ed565b610903565b610170610367366004611349565b61092e565b6103746109a7565b6001600160a01b03811661039b57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b60606103ef610a01565b6103fa60fc54610a10565b60405160200161040b929190611626565b604051602081830303815290604052905090565b60003361042d818585610aa3565b60019150505b92915050565b6000306001600160a01b0384160361046457604051636cfe544760e01b815260040160405180910390fd5b61046f848484610bbf565b90505b9392505050565b60003361042d81858561048c8383610903565b6104969190611664565b610aa3565b6a195c98cc8c17dd985d5b1d60aa1b647461696b6f60d81b6104be8260016108c1565b6001600160a01b0316336001600160a01b0316141580156104fb57506104e58160016108c1565b6001600160a01b0316336001600160a01b031614155b1561051957604051630d85cccf60e11b815260040160405180910390fd5b6105238484610bd8565b6040518381526001600160a01b038516906000906000805160206118368339815191529060200160405180910390a350505050565b600054610100900460ff16158080156105785750600054600160ff909116105b806105925750303b158015610592575060005460ff166001145b6105fa5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561061d576000805461ff0019166101001790555b6001600160a01b0386161580610631575084155b8061063b57504685145b8061064557508251155b8061064f57508151155b1561066d57604051635d061ab760e11b815260040160405180910390fd5b61067687610c88565b6106808284610ca1565b60fb80546001600160a01b0319166001600160a01b03881617905560fc85905560fd805460ff191660ff861617905580156106f5576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b600061046f848484610cd2565b6107136109a7565b61071d6000610d86565b565b606060cd805461072e90611685565b80601f016020809104026020016040519081016040528092919081815260200182805461075a90611685565b80156107a75780601f1061077c576101008083540402835291602001916107a7565b820191906000526020600020905b81548152906001019060200180831161078a57829003601f168201915b5050505050905090565b6a195c98cc8c17dd985d5b1d60aa1b6107cb8160016108c1565b6001600160a01b0316336001600160a01b0316146107fc57604051630d85cccf60e11b815260040160405180910390fd5b6108068383610dd8565b6040518281526000906001600160a01b03851690600080516020611836833981519152906020015b60405180910390a3505050565b600033816108498286610903565b9050838110156108a95760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016105f1565b6108b68286868403610aa3565b506001949350505050565b6000610472468484610cd2565b6000306001600160a01b038416036108f957604051636cfe544760e01b815260040160405180910390fd5b6104728383610ef7565b6001600160a01b03918216600090815260ca6020908152604080832093909416825291909152205490565b6109366109a7565b6001600160a01b03811661099b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105f1565b6109a481610d86565b50565b6065546001600160a01b0316331461071d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105f1565b606060cc805461072e90611685565b60606000610a1d83610f05565b600101905060008167ffffffffffffffff811115610a3d57610a3d61142a565b6040519080825280601f01601f191660200182016040528015610a67576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610a7157509392505050565b6001600160a01b038316610b055760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016105f1565b6001600160a01b038216610b665760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016105f1565b6001600160a01b03838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910161082e565b600033610bcd858285610fdd565b6108b6858585611057565b6001600160a01b038216610c2e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016105f1565b8060cb6000828254610c409190611664565b90915550506001600160a01b038216600081815260c96020908152604080832080548601905551848152600080516020611836833981519152910160405180910390a35b5050565b610c906111f0565b610c9861121f565b6109a48161124e565b600054610100900460ff16610cc85760405162461bcd60e51b81526004016105f1906116bf565b610c848282611297565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610d23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d47919061170a565b905081158015610d5e57506001600160a01b038116155b1561047257604051631467050360e21b815260048101859052602481018490526044016105f1565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216610e385760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016105f1565b6001600160a01b038216600090815260c9602052604090205481811015610eac5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016105f1565b6001600160a01b038316600081815260c960209081526040808320868603905560cb8054879003905551858152919291600080516020611836833981519152910161082e565b505050565b60003361042d818585611057565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610f445772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610f70576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610f8e57662386f26fc10000830492506010015b6305f5e1008310610fa6576305f5e100830492506008015b6127108310610fba57612710830492506004015b60648310610fcc576064830492506002015b600a83106104335760010192915050565b6000610fe98484610903565b9050600019811461105157818110156110445760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016105f1565b6110518484848403610aa3565b50505050565b6001600160a01b0383166110bb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016105f1565b6001600160a01b03821661111d5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016105f1565b6001600160a01b038316600090815260c96020526040902054818110156111955760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016105f1565b6001600160a01b03808516600081815260c960205260408082208686039055928616808252908390208054860190559151600080516020611836833981519152906111e39086815260200190565b60405180910390a3611051565b600054610100900460ff166112175760405162461bcd60e51b81526004016105f1906116bf565b61071d6112d7565b600054610100900460ff166112465760405162461bcd60e51b81526004016105f1906116bf565b61071d611304565b6001600160a01b03811661127557604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166112be5760405162461bcd60e51b81526004016105f1906116bf565b60cc6112ca8382611775565b5060cd610ef28282611775565b600054610100900460ff166112fe5760405162461bcd60e51b81526004016105f1906116bf565b60018055565b600054610100900460ff1661132b5760405162461bcd60e51b81526004016105f1906116bf565b61071d33610d86565b6001600160a01b03811681146109a457600080fd5b60006020828403121561135b57600080fd5b813561047281611334565b60005b83811015611381578181015183820152602001611369565b50506000910152565b60208152600082518060208401526113a9816040850160208701611366565b601f01601f19169190910160400192915050565b600080604083850312156113d057600080fd5b82356113db81611334565b946020939093013593505050565b6000806000606084860312156113fe57600080fd5b833561140981611334565b9250602084013561141981611334565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261145157600080fd5b813567ffffffffffffffff8082111561146c5761146c61142a565b604051601f8301601f19908116603f011681019082821181831017156114945761149461142a565b816040528381528660208588010111156114ad57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060c087890312156114e657600080fd5b86356114f181611334565b9550602087013561150181611334565b945060408701359350606087013560ff8116811461151e57600080fd5b9250608087013567ffffffffffffffff8082111561153b57600080fd5b6115478a838b01611440565b935060a089013591508082111561155d57600080fd5b5061156a89828a01611440565b9150509295509295509295565b8035801515811461158757600080fd5b919050565b6000806000606084860312156115a157600080fd5b83359250602084013591506115b860408501611577565b90509250925092565b600080604083850312156115d457600080fd5b823591506115e460208401611577565b90509250929050565b6000806040838503121561160057600080fd5b823561160b81611334565b9150602083013561161b81611334565b809150509250929050565b60008351611638818460208801611366565b6241c55b60e71b9083019081528351611658816004840160208801611366565b01600401949350505050565b8082018082111561043357634e487b7160e01b600052601160045260246000fd5b600181811c9082168061169957607f821691505b6020821081036116b957634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60006020828403121561171c57600080fd5b815161047281611334565b601f821115610ef257600081815260208120601f850160051c8101602086101561174e5750805b601f850160051c820191505b8181101561176d5782815560010161175a565b505050505050565b815167ffffffffffffffff81111561178f5761178f61142a565b6117a38161179d8454611685565b84611727565b602080601f8311600181146117d857600084156117c05750858301515b600019600386901b1c1916600185901b17855561176d565b600085815260208120601f198616915b82811015611807578886015182559484019460019091019084016117e8565b50858210156118255787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122084c55b31f1ca31a63eb2f494abc3a7a53871a4d74e8f1a0d4a8487fc410374b564736f6c63430008140033a2646970667358221220fb6838adab59caf0c87ea98c1d46d8afdd628bcbc80e276935e7eb4856c7485964736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000002" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000008": { + "storage": {}, + "code": "0x6080604052600436106200011f5760003560e01c80636c6563f611620000a15780639aa8605c116200006c5780639aa8605c1462000342578063a86f9d9e1462000379578063a9976baf146200039e578063c287e57814620003b5578063f2fde38b14620003e957600080fd5b80636c6563f614620002ce578063715018a614620002f357806373339643146200030b5780638da5cb5b146200032257600080fd5b80632ca069a511620000ee5780632ca069a5146200020457806332a642ca14620002215780633ab76e9f146200023857806359f4a907146200026c57806367090ccf146200028957600080fd5b806301ffc9a714620001245780630652b57a146200016e578063150b7a02146200019557806319ab453c14620001df575b600080fd5b3480156200013157600080fd5b50620001596200014336600462002112565b6001600160e01b031916631953216560e11b1490565b60405190151581526020015b60405180910390f35b3480156200017b57600080fd5b50620001936200018d36600462002161565b6200040e565b005b348015620001a257600080fd5b50620001c5620001b436600462002181565b630a85bd0160e11b95945050505050565b6040516001600160e01b0319909116815260200162000165565b348015620001ec57600080fd5b5062000193620001fe36600462002161565b6200048a565b3480156200021157600080fd5b50620001c5636cdb3d1360e11b81565b620001936200023236600462002228565b620005aa565b3480156200024557600080fd5b506097546001600160a01b03165b6040516001600160a01b03909116815260200162000165565b3480156200027957600080fd5b50620001c56380ac58cd60e01b81565b3480156200029657600080fd5b5062000253620002a836600462002266565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b348015620002db57600080fd5b5062000253620002ed366004620022a8565b620009cd565b3480156200030057600080fd5b5062000193620009e6565b620001936200031c366004620022e4565b620009fe565b3480156200032f57600080fd5b506065546001600160a01b031662000253565b3480156200034f57600080fd5b50620003676200036136600462002161565b62000eaa565b60405162000165949392919062002376565b3480156200038657600080fd5b506200025362000398366004620023c1565b62000ffd565b62000193620003af366004620024af565b62001015565b348015620003c257600080fd5b5062000159620003d436600462002161565b60c96020526000908152604090205460ff1681565b348015620003f657600080fd5b50620001936200040836600462002161565b62001336565b62000418620013b2565b6001600160a01b0381166200044057604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff1615808015620004ab5750600054600160ff909116105b80620004c75750303b158015620004c7575060005460ff166001145b620005305760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562000554576000805461ff0019166101001790555b6200055f826200140e565b8015620005a6576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b620005b46200142d565b6562726964676560d01b620005cb81600162000ffd565b6001600160a01b0316336001600160a01b031614620005fd57604051630d85cccf60e11b815260040160405180910390fd5b60006200061160a084016080850162002161565b6001600160a01b031603620006395760405163016a294f60e41b815260040160405180910390fd5b468260400135146200065e57604051630a15fbb960e01b815260040160405180910390fd5b600080620006716101408501856200254d565b620006819160049082906200259d565b81019062000690919062002704565b935050509150600073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d632c6a56af86620006c96562726964676560d01b600062000ffd565b86602001516040518463ffffffff1660e01b8152600401620006ee93929190620027c6565b602060405180830381865af41580156200070c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000732919062002920565b6020808501516001600160a01b0316600090815260c9909152604090205490915060ff1615620008245760005b82518110156200081d5760208401516001600160a01b03166340c10f196200078e60a0890160808a0162002161565b858481518110620007a357620007a36200293a565b60200260200101516040518363ffffffff1660e01b8152600401620007dd9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b158015620007f857600080fd5b505af11580156200080d573d6000803e3d6000fd5b505050508060010190506200075f565b50620008ee565b60005b8251811015620008ec5760208401516001600160a01b03166342842e0e306200085760a08a0160808b0162002161565b8685815181106200086c576200086c6200293a565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b158015620008c757600080fd5b505af1158015620008dc573d6000803e3d6000fd5b5050505080600101905062000827565b505b6200091960e08601356200090960a088016080890162002161565b6001600160a01b03169062001488565b6200092b60a086016080870162002161565b6001600160a01b0316817fe8449897bd3c926a272780c39ba13e77bf7a2c823479a75bfbc13ef631183dfd85602001518560006001600160401b03811115620009785762000978620023e9565b604051908082528060200260200182016040528015620009a2578160200160208202803683370190505b50604051620009b4939291906200298d565b60405180910390a350505050620009ca60018055565b50565b6000620009dc8484846200154f565b90505b9392505050565b620009f0620013b2565b620009fc600062001609565b565b62000a086200142d565b73b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d63c0619cc262000a316080840184620029d1565b62000a406060860186620029d1565b60016040518663ffffffff1660e01b815260040162000a6495949392919062002a50565b60006040518083038186803b15801562000a7d57600080fd5b505af415801562000a92573d6000803e3d6000fd5b5050505073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d6393522e3e62000ad183600001356b195c98cdcc8c57dd985d5b1d60a21b6000620009cd565b62000ae3604085016020860162002161565b62000af5606086016040870162002161565b60405160e085901b6001600160e01b03191681526001600160a01b0393841660048201529183166024830152909116604482015260640160006040518083038186803b15801562000b4557600080fd5b505af415801562000b5a573d6000803e3d6000fd5b5062000b8f92506380ac58cd60e01b915062000b7f9050606084016040850162002161565b6001600160a01b0316906200165b565b62000bad57604051633ee915f560e11b815260040160405180910390fd5b600062000bbe6080830183620029d1565b80806020026020016040519081016040528093929190818152602001838360200280828437600092018290525093945062000c0492505050606084016040850162002161565b9050600062000c176060850185620029d1565b80806020026020016040519081016040528093929190818152602001838360200280828437600092018290525060408051610180810182528281526020810183905290810182905260608082018390526080820183905260a0820183905260c0820183905260e082018390526101008201839052610120820192909252610140810182905261016081019190915293945062000cb292505050565b8435606082015262000cc53386620016d8565b610140820152336080820152606081015162000cf3906b195c98cdcc8c57dd985d5b1d60a21b6000620009cd565b6001600160a01b031660a08083019190915285013561012082015262000d1e60c08601353462002a90565b60e08083019190915260c08601356101008084019190915262000d479190870190870162002161565b6001600160a01b031660c082015262000d656101008601866200254d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101608601949094525062000db891506562726964676560d01b90508262000ffd565b6001600160a01b0316634c1888bc34846040518363ffffffff1660e01b815260040162000de6919062002ab2565b60206040518083038185885af115801562000e05573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062000e2c919062002920565b905062000e40604087016020880162002161565b6001600160a01b031682608001516001600160a01b0316827f5e54276405062454e6226625b28a6fea0a838d6b054e38955667234afb3345a3856060015188888b60405162000e93949392919062002b9b565b60405180910390a45050505050620009ca60018055565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b039092169262000ede9062002bdb565b80601f016020809104026020016040519081016040528092919081815260200182805462000f0c9062002bdb565b801562000f5d5780601f1062000f315761010080835404028352916020019162000f5d565b820191906000526020600020905b81548152906001019060200180831162000f3f57829003601f168201915b50505050509080600301805462000f749062002bdb565b80601f016020809104026020016040519081016040528092919081815260200182805462000fa29062002bdb565b801562000ff35780601f1062000fc75761010080835404028352916020019162000ff3565b820191906000526020600020905b81548152906001019060200180831162000fd557829003601f168201915b5050505050905084565b60006200100c4684846200154f565b90505b92915050565b6200101f6200142d565b6562726964676560d01b6200103681600162000ffd565b6001600160a01b0316336001600160a01b0316146200106857604051630d85cccf60e11b815260040160405180910390fd5b60405163881107d960e01b81526b195c98cdcc8c57dd985d5b1d60a21b600482015230602482015260009073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d9063881107d990604401606060405180830381865af4158015620010d0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010f6919062002c17565b9050600046873503620011d15762001115604088016020890162002161565b905060005b8451811015620011ca57816001600160a01b03166323b872dd30888885815181106200114a576200114a6200293a565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b158015620011a557600080fd5b505af1158015620011ba573d6000803e3d6000fd5b505050508060010190506200111a565b506200128c565b620011dc8762001c07565b905060005b84518110156200128a57816001600160a01b03166340c10f19878784815181106200121057620012106200293a565b60200260200101516040518363ffffffff1660e01b81526004016200124a9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b1580156200126557600080fd5b505af11580156200127a573d6000803e3d6000fd5b50505050806001019050620011e1565b505b620012a16001600160a01b0386163462001488565b815160408301516001600160a01b0380881692908916917f0f60c37489e435ed8490c30b01c1fa57e62510e88b351b75796ad3d95babe6b1908589600060405190808252806020026020018201604052801562001308578160200160208202803683370190505b506040516200131b949392919062002b9b565b60405180910390a45050506200133060018055565b50505050565b62001340620013b2565b6001600160a01b038116620013a75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000527565b620009ca8162001609565b6065546001600160a01b03163314620009fc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000527565b6200141862001c70565b6200142262001ca4565b620009ca8162001cd8565b600260015403620014815760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000527565b6002600155565b8015806200149d57506001600160a01b038216155b15620014a7575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114620014f6576040519150601f19603f3d011682016040523d82523d6000602084013e620014fb565b606091505b5050905080620015445760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b604482015260640162000527565b505050565b60018055565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015620015a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015c7919062002c7e565b905081158015620015df57506001600160a01b038116155b15620009df57604051631467050360e21b8152600481018590526024810184905260440162000527565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516301ffc9a760e01b81526001600160e01b0319821660048201526000906001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015620016cb575060408051601f3d908101601f19168201909252620016c89181019062002c9e565b60015b156200100f579392505050565b6040805160808101825260008082526020820152606091810182905280820182905260c9600062001710606086016040870162002161565b6001600160a01b0316815260208101919091526040016000205460ff1615620019985760ca600062001749606086016040870162002161565b6001600160a01b0390811682526020808301939093526040918201600020825160808101845281548152600182015490921693820193909352600283018054919392840191620017999062002bdb565b80601f0160208091040260200160405190810160405280929190818152602001828054620017c79062002bdb565b8015620018185780601f10620017ec5761010080835404028352916020019162001818565b820191906000526020600020905b815481529060010190602001808311620017fa57829003601f168201915b50505050508152602001600382018054620018339062002bdb565b80601f0160208091040260200160405190810160405280929190818152602001828054620018619062002bdb565b8015620018b25780601f106200188657610100808354040283529160200191620018b2565b820191906000526020600020905b8154815290600101906020018083116200189457829003601f168201915b505050505081525050905060005b620018cf6060850185620029d1565b90508110156200199157620018eb606085016040860162002161565b6001600160a01b0316639dc29fac86620019096060880188620029d1565b858181106200191c576200191c6200293a565b6040516001600160e01b031960e087901b1681526001600160a01b0390941660048501526020029190910135602483015250604401600060405180830381600087803b1580156200196c57600080fd5b505af115801562001981573d6000803e3d6000fd5b50505050806001019050620018c0565b5062001b8c565b6000620019ac606085016040860162002161565b90506040518060800160405280468152602001856040016020810190620019d4919062002161565b6001600160a01b03168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001a21573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001a4b919081019062002cbe565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001a8f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001ab9919081019062002cbe565b9052915060005b62001acf6060860186620029d1565b905081101562001b89576001600160a01b0382166323b872dd873062001af960608a018a620029d1565b8681811062001b0c5762001b0c6200293a565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801562001b6457600080fd5b505af115801562001b79573d6000803e3d6000fd5b5050505080600101905062001ac0565b50505b63a9976baf60e01b818562001ba8604087016020880162002161565b62001bb76060880188620029d1565b60405160240162001bcd95949392919062002d8b565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152949350505050565b8035600090815260cb6020908152604080832091839162001c2e9190860190860162002161565b6001600160a01b0390811682526020820192909252604001600020541690508062001c6b5762001c6862001c628362002dd8565b62001d22565b90505b919050565b600054610100900460ff1662001c9a5760405162461bcd60e51b8152600401620005279062002de6565b620009fc62001f9b565b600054610100900460ff1662001cce5760405162461bcd60e51b8152600401620005279062002de6565b620009fc62001fc5565b6001600160a01b03811662001d0057604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60008062001d7f60008460405160200162001d3e919062002e31565b604051602081830303815290604052805190602001206040518060200162001d669062002104565b601f1982820381018352601f9091011660405262001ffa565b905073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d6378adc0d68262001daf6065546001600160a01b031690565b60975460208089015189516040808c015160608d0151915163689ccd8d60e11b9662001deb966001600160a01b03909116959493910162002e46565b60408051601f198184030181529082905262001e0b929160200162002e8f565b6040516020818303038152906040526040518463ffffffff1660e01b815260040162001e3a9392919062002ec2565b602060405180830381865af415801562001e58573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001e7e919062002c7e565b6001600160a01b03818116600090815260c9602090815260408083208054600160ff19909116811790915560ca835292819020885181559188015192820180546001600160a01b03191693909416929092179092558501519193508491600282019062001eec908262002f42565b506060820151600382019062001f03908262002f42565b50508351600090815260cb6020908152604080832082880180516001600160a01b039081168652919093529281902080546001600160a01b031916878516908117909155915187518289015160608a015193519496509190941693927f2da3c4d305298f6df3653c23d98b4c055f72f7e6f981b2c477ccbec92b1ee5799262001f8d92916200300e565b60405180910390a450919050565b600054610100900460ff16620015495760405162461bcd60e51b8152600401620005279062002de6565b600054610100900460ff1662001fef5760405162461bcd60e51b8152600401620005279062002de6565b620009fc3362001609565b6000834710156200204e5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640162000527565b8151600003620020a15760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640162000527565b8282516020840186f590506001600160a01b038116620009df5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640162000527565b611f55806200303883390190565b6000602082840312156200212557600080fd5b81356001600160e01b0319811681146200100c57600080fd5b6001600160a01b0381168114620009ca57600080fd5b803562001c6b816200213e565b6000602082840312156200217457600080fd5b81356200100c816200213e565b6000806000806000608086880312156200219a57600080fd5b8535620021a7816200213e565b94506020860135620021b9816200213e565b93506040860135925060608601356001600160401b0380821115620021dd57600080fd5b818801915088601f830112620021f257600080fd5b8135818111156200220257600080fd5b8960208285010111156200221557600080fd5b9699959850939650602001949392505050565b6000602082840312156200223b57600080fd5b81356001600160401b038111156200225257600080fd5b820161018081850312156200100c57600080fd5b600080604083850312156200227a57600080fd5b8235915060208301356200228e816200213e565b809150509250929050565b8015158114620009ca57600080fd5b600080600060608486031215620022be57600080fd5b83359250602084013591506040840135620022d98162002299565b809150509250925092565b600060208284031215620022f757600080fd5b81356001600160401b038111156200230e57600080fd5b820161012081850312156200100c57600080fd5b60005b838110156200233f57818101518382015260200162002325565b50506000910152565b600081518084526200236281602086016020860162002322565b601f01601f19169290920160200192915050565b8481526001600160a01b0384166020820152608060408201819052600090620023a29083018562002348565b8281036060840152620023b6818562002348565b979650505050505050565b60008060408385031215620023d557600080fd5b8235915060208301356200228e8162002299565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200242a576200242a620023e9565b604052919050565b600082601f8301126200244457600080fd5b813560206001600160401b03821115620024625762002462620023e9565b8160051b62002473828201620023ff565b92835284810182019282810190878511156200248e57600080fd5b83870192505b84831015620023b65782358252918301919083019062002494565b60008060008060808587031215620024c657600080fd5b84356001600160401b0380821115620024de57600080fd5b9086019060808289031215620024f357600080fd5b90945060208601359062002507826200213e565b9093506040860135906200251b826200213e565b909250606086013590808211156200253257600080fd5b50620025418782880162002432565b91505092959194509250565b6000808335601e198436030181126200256557600080fd5b8301803591506001600160401b038211156200258057600080fd5b6020019150368190038213156200259657600080fd5b9250929050565b60008085851115620025ae57600080fd5b83861115620025bc57600080fd5b5050820193919092039150565b60006001600160401b03821115620025e557620025e5620023e9565b50601f01601f191660200190565b600082601f8301126200260557600080fd5b81356200261c6200261682620025c9565b620023ff565b8181528460208386010111156200263257600080fd5b816020850160208301376000918101602001919091529392505050565b6000608082840312156200266257600080fd5b604051608081016001600160401b038282108183111715620026885762002688620023e9565b816040528293508435835260208501359150620026a5826200213e565b8160208401526040850135915080821115620026c057600080fd5b620026ce86838701620025f3565b60408401526060850135915080821115620026e857600080fd5b50620026f785828601620025f3565b6060830152505092915050565b600080600080608085870312156200271b57600080fd5b84356001600160401b03808211156200273357600080fd5b62002741888389016200264f565b95506020870135915062002507826200213e565b6000808335601e198436030181126200276d57600080fd5b83016020810192503590506001600160401b038111156200278d57600080fd5b8036038213156200259657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60608152833560608201526000620027e16020860162002154565b6001600160a01b038116608084015250604085013560a0830152606085013560c0830152620028136080860162002154565b6001600160a01b031660e08301526200282f60a0860162002154565b61010062002847818501836001600160a01b03169052565b6200285560c0880162002154565b91506101206200286f818601846001600160a01b03169052565b610140925060e088013583860152610160828901358187015261018092508189013583870152620028a3848a018a62002755565b94509150826101a0870152620028bf6101e0870185846200279d565b9350620028cf818a018a62002755565b9350915050605f19858403016101c0860152620028ee8383836200279d565b93505050506200290960208301856001600160a01b03169052565b6001600160a01b0383166040830152949350505050565b6000602082840312156200293357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015620029825781518752958201959082019060010162002964565b509495945050505050565b6001600160a01b0384168152606060208201819052600090620029b39083018562002950565b8281036040840152620029c7818562002950565b9695505050505050565b6000808335601e19843603018112620029e957600080fd5b8301803591506001600160401b0382111562002a0457600080fd5b6020019150600581901b36038213156200259657600080fd5b81835260006001600160fb1b0383111562002a3757600080fd5b8260051b80836020870137939093016020019392505050565b60608152600062002a6660608301878962002a1d565b828103602084015262002a7b81868862002a1d565b91505082151560408301529695505050505050565b818103818111156200100f57634e487b7160e01b600052601160045260246000fd5b60208152815160208201526000602083015162002ada60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015162002b0a60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083810191909152830151610120808401919091528301516101408084019190915283015161018061016080850182905262002b7d6101a086018462002348565b90860151858203601f190183870152909250620029c7838262002348565b8481526001600160a01b038416602082015260806040820181905260009062002bc79083018562002950565b8281036060840152620023b6818562002950565b600181811c9082168062002bf057607f821691505b60208210810362002c1157634e487b7160e01b600052602260045260246000fd5b50919050565b60006060828403121562002c2a57600080fd5b604051606081018181106001600160401b038211171562002c4f5762002c4f620023e9565b60405282518152602083015162002c66816200213e565b60208201526040928301519281019290925250919050565b60006020828403121562002c9157600080fd5b81516200100c816200213e565b60006020828403121562002cb157600080fd5b81516200100c8162002299565b60006020828403121562002cd157600080fd5b81516001600160401b0381111562002ce857600080fd5b8201601f8101841362002cfa57600080fd5b805162002d0b6200261682620025c9565b81815285602083850101111562002d2157600080fd5b62002d3482602083016020860162002322565b95945050505050565b8051825260018060a01b036020820151166020830152600060408201516080604085015262002d70608085018262002348565b90506060830151848203606086015262002d34828262002348565b60808152600062002da0608083018862002d3d565b6001600160a01b03878116602085015286166040840152828103606084015262002dcc81858762002a1d565b98975050505050505050565b600062001c6836836200264f565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260006200100c602083018462002d3d565b6001600160a01b038681168252851660208201526040810184905260a06060820181905260009062002e7b9083018562002348565b828103608084015262002dcc818562002348565b6001600160e01b031983168152815160009062002eb481600485016020870162002322565b919091016004019392505050565b6001600160a01b0384811682528316602082015260606040820181905260009062002d349083018462002348565b601f8211156200154457600081815260208120601f850160051c8101602086101562002f195750805b601f850160051c820191505b8181101562002f3a5782815560010162002f25565b505050505050565b81516001600160401b0381111562002f5e5762002f5e620023e9565b62002f768162002f6f845462002bdb565b8462002ef0565b602080601f83116001811462002fae576000841562002f955750858301515b600019600386901b1c1916600185901b17855562002f3a565b600085815260208120601f198616915b8281101562002fdf5788860151825594840194600190910190840162002fbe565b508582101562002ffe5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600062003023604083018562002348565b828103602084015262002d3481856200234856fe608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611e68806100ed6000396000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c806370a08231116100de578063a22cb46511610097578063c87b56dd11610071578063c87b56dd14610377578063d1399b1a14610398578063e985e9c5146103ab578063f2fde38b146103e857600080fd5b8063a22cb4651461033e578063a86f9d9e14610351578063b88d4fde1461036457600080fd5b806370a08231146102e3578063715018a6146102f65780637cf8ed0d146102fe5780638da5cb5b1461031257806395d89b41146103235780639dc29fac1461032b57600080fd5b80633ab76e9f1161014b57806349d126051161012557806349d126051461026d5780636352211e1461028557806367e828bf146102985780636c6563f6146102d057600080fd5b80633ab76e9f1461023657806340c10f191461024757806342842e0e1461025a57600080fd5b806301ffc9a7146101935780630652b57a146101bb57806306fdde03146101d0578063081812fc146101e5578063095ea7b31461021057806323b872dd14610223575b600080fd5b6101a66101a136600461171c565b6103fb565b60405190151581526020015b60405180910390f35b6101ce6101c936600461174e565b61044d565b005b6101d86104c6565b6040516101b291906117bb565b6101f86101f33660046117ce565b610501565b6040516001600160a01b0390911681526020016101b2565b6101ce61021e3660046117e7565b610528565b6101ce610231366004611813565b610642565b6097546001600160a01b03166101f8565b6101ce6102553660046117e7565b610676565b6101ce610268366004611813565b6106f7565b61027761012e5481565b6040519081526020016101b2565b6101f86102933660046117ce565b610712565b6102b161012d5461012e546001600160a01b0390911691565b604080516001600160a01b0390931683526020830191909152016101b2565b6101f86102de366004611869565b610772565b6102776102f136600461174e565b610789565b6101ce61080f565b61012d546101f8906001600160a01b031681565b6065546001600160a01b03166101f8565b6101d8610823565b6101ce6103393660046117e7565b6108b5565b6101ce61034c36600461189e565b61096f565b6101f861035f3660046118d3565b61097e565b6101ce610372366004611982565b61098b565b6101d86103853660046117ce565b5060408051602081019091526000815290565b6101ce6103a6366004611a22565b6109c3565b6101a66103b9366004611ab5565b6001600160a01b0391821660009081526101006020908152604080832093909416825291909152205460ff1690565b6101ce6103f636600461174e565b610b56565b60006001600160e01b031982166380ac58cd60e01b148061042c57506001600160e01b03198216635b5e139f60e01b145b8061044757506301ffc9a760e01b6001600160e01b03198316145b92915050565b610455610bcf565b6001600160a01b03811661047c57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b60606104d0610c29565b6104dc61012e54610c38565b6040516020016104ed929190611aee565b604051602081830303815290604052905090565b600061050c82610ccb565b50600090815260ff60205260409020546001600160a01b031690565b600061053382610712565b9050806001600160a01b0316836001600160a01b0316036105a55760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806105c157506105c181336103b9565b6106335760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000606482015260840161059c565b61063d8383610d2a565b505050565b306001600160a01b0383160361066b57604051636cfe544760e01b815260040160405180910390fd5b61063d838383610d98565b6b195c98cdcc8c57dd985d5b1d60a21b61069181600161097e565b6001600160a01b0316336001600160a01b0316146106c257604051630d85cccf60e11b815260040160405180910390fd5b6106cc8383610dc9565b60405182906001600160a01b03851690600090600080516020611e13833981519152908290a4505050565b61063d8383836040518060200160405280600081525061098b565b600081815260fd60205260408120546001600160a01b0316806104475760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161059c565b600061077f848484610f42565b90505b9392505050565b60006001600160a01b0382166107f35760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840161059c565b506001600160a01b0316600090815260fe602052604090205490565b610817610bcf565b6108216000610ff6565b565b606060fc805461083290611b2c565b80601f016020809104026020016040519081016040528092919081815260200182805461085e90611b2c565b80156108ab5780601f10610880576101008083540402835291602001916108ab565b820191906000526020600020905b81548152906001019060200180831161088e57829003601f168201915b5050505050905090565b6b195c98cdcc8c57dd985d5b1d60a21b6108d081600161097e565b6001600160a01b0316336001600160a01b03161461090157604051630d85cccf60e11b815260040160405180910390fd5b826001600160a01b031661091483610712565b6001600160a01b03161461093b576040516302dca79760e41b815260040160405180910390fd5b61094482611048565b60405182906000906001600160a01b03861690600080516020611e13833981519152908390a4505050565b61097a3383836110cb565b5050565b6000610782468484610f42565b610995338361119a565b6109b15760405162461bcd60e51b815260040161059c90611b66565b6109bd8484848461121a565b50505050565b600054610100900460ff16158080156109e35750600054600160ff909116105b806109fd5750303b1580156109fd575060005460ff166001145b610a605760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161059c565b6000805460ff191660011790558015610a83576000805461ff0019166101001790555b6001600160a01b0385161580610a97575083155b80610aa157504684145b80610aab57508251155b80610ab557508151155b15610ad357604051635d061ab760e11b815260040160405180910390fd5b610adc8661124d565b610ae68284611266565b61012d80546001600160a01b0319166001600160a01b03871617905561012e8490558015610b4e576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b610b5e610bcf565b6001600160a01b038116610bc35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161059c565b610bcc81610ff6565b50565b6065546001600160a01b031633146108215760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161059c565b606060fb805461083290611b2c565b60606000610c4583611297565b600101905060008167ffffffffffffffff811115610c6557610c656118f6565b6040519080825280601f01601f191660200182016040528015610c8f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610c9957509392505050565b600081815260fd60205260409020546001600160a01b0316610bcc5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b604482015260640161059c565b600081815260ff6020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610d5f82610712565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b610da2338261119a565b610dbe5760405162461bcd60e51b815260040161059c90611b66565b61063d83838361136f565b6001600160a01b038216610e1f5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161059c565b600081815260fd60205260409020546001600160a01b031615610e845760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161059c565b600081815260fd60205260409020546001600160a01b031615610ee95760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161059c565b6001600160a01b038216600081815260fe602090815260408083208054600101905584835260fd90915280822080546001600160a01b031916841790555183929190600080516020611e13833981519152908290a45050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610f93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb79190611bb3565b905081158015610fce57506001600160a01b038116155b1561078257604051631467050360e21b8152600481018590526024810184905260440161059c565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600061105382610712565b905061105e82610712565b600083815260ff6020908152604080832080546001600160a01b03199081169091556001600160a01b03851680855260fe8452828520805460001901905587855260fd90935281842080549091169055519293508492600080516020611e13833981519152908390a45050565b816001600160a01b0316836001600160a01b03160361112c5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161059c565b6001600160a01b0383811660008181526101006020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6000806111a683610712565b9050806001600160a01b0316846001600160a01b031614806111ee57506001600160a01b038082166000908152610100602090815260408083209388168352929052205460ff165b806112125750836001600160a01b031661120784610501565b6001600160a01b0316145b949350505050565b61122584848461136f565b611231848484846114c1565b6109bd5760405162461bcd60e51b815260040161059c90611bd0565b6112556115c2565b61125d6115f1565b610bcc81611620565b600054610100900460ff1661128d5760405162461bcd60e51b815260040161059c90611c22565b61097a8282611669565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106112d65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611302576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061132057662386f26fc10000830492506010015b6305f5e1008310611338576305f5e100830492506008015b612710831061134c57612710830492506004015b6064831061135e576064830492506002015b600a83106104475760010192915050565b826001600160a01b031661138282610712565b6001600160a01b0316146113a85760405162461bcd60e51b815260040161059c90611c6d565b6001600160a01b03821661140a5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161059c565b826001600160a01b031661141d82610712565b6001600160a01b0316146114435760405162461bcd60e51b815260040161059c90611c6d565b600081815260ff6020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260fe855283862080546000190190559087168086528386208054600101905586865260fd9094528285208054909216841790915590518493600080516020611e1383398151915291a4505050565b60006001600160a01b0384163b156115b757604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611505903390899088908890600401611cb2565b6020604051808303816000875af1925050508015611540575060408051601f3d908101601f1916820190925261153d91810190611cef565b60015b61159d573d80801561156e576040519150601f19603f3d011682016040523d82523d6000602084013e611573565b606091505b5080516000036115955760405162461bcd60e51b815260040161059c90611bd0565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611212565b506001949350505050565b600054610100900460ff166115e95760405162461bcd60e51b815260040161059c90611c22565b6108216116a9565b600054610100900460ff166116185760405162461bcd60e51b815260040161059c90611c22565b6108216116d6565b6001600160a01b03811661164757604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166116905760405162461bcd60e51b815260040161059c90611c22565b60fb61169c8382611d52565b5060fc61063d8282611d52565b600054610100900460ff166116d05760405162461bcd60e51b815260040161059c90611c22565b60018055565b600054610100900460ff166116fd5760405162461bcd60e51b815260040161059c90611c22565b61082133610ff6565b6001600160e01b031981168114610bcc57600080fd5b60006020828403121561172e57600080fd5b813561078281611706565b6001600160a01b0381168114610bcc57600080fd5b60006020828403121561176057600080fd5b813561078281611739565b60005b8381101561178657818101518382015260200161176e565b50506000910152565b600081518084526117a781602086016020860161176b565b601f01601f19169290920160200192915050565b602081526000610782602083018461178f565b6000602082840312156117e057600080fd5b5035919050565b600080604083850312156117fa57600080fd5b823561180581611739565b946020939093013593505050565b60008060006060848603121561182857600080fd5b833561183381611739565b9250602084013561184381611739565b929592945050506040919091013590565b8035801515811461186457600080fd5b919050565b60008060006060848603121561187e57600080fd5b833592506020840135915061189560408501611854565b90509250925092565b600080604083850312156118b157600080fd5b82356118bc81611739565b91506118ca60208401611854565b90509250929050565b600080604083850312156118e657600080fd5b823591506118ca60208401611854565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115611927576119276118f6565b604051601f8501601f19908116603f0116810190828211818310171561194f5761194f6118f6565b8160405280935085815286868601111561196857600080fd5b858560208301376000602087830101525050509392505050565b6000806000806080858703121561199857600080fd5b84356119a381611739565b935060208501356119b381611739565b925060408501359150606085013567ffffffffffffffff8111156119d657600080fd5b8501601f810187136119e757600080fd5b6119f68782356020840161190c565b91505092959194509250565b600082601f830112611a1357600080fd5b6107828383356020850161190c565b600080600080600060a08688031215611a3a57600080fd5b8535611a4581611739565b94506020860135611a5581611739565b935060408601359250606086013567ffffffffffffffff80821115611a7957600080fd5b611a8589838a01611a02565b93506080880135915080821115611a9b57600080fd5b50611aa888828901611a02565b9150509295509295909350565b60008060408385031215611ac857600080fd5b8235611ad381611739565b91506020830135611ae381611739565b809150509250929050565b60008351611b0081846020880161176b565b6241c55b60e71b9083019081528351611b2081600484016020880161176b565b01600401949350505050565b600181811c90821680611b4057607f821691505b602082108103611b6057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b600060208284031215611bc557600080fd5b815161078281611739565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090611ce59083018461178f565b9695505050505050565b600060208284031215611d0157600080fd5b815161078281611706565b601f82111561063d57600081815260208120601f850160051c81016020861015611d335750805b601f850160051c820191505b81811015610b4e57828155600101611d3f565b815167ffffffffffffffff811115611d6c57611d6c6118f6565b611d8081611d7a8454611b2c565b84611d0c565b602080601f831160018114611db55760008415611d9d5750858301515b600019600386901b1c1916600185901b178555610b4e565b600085815260208120601f198616915b82811015611de457888601518255948401946001909101908401611dc5565b5085821015611e025787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220982ed42a531dac25c2cd2d24df34757ecf10be7c97db68448affe62cbba75e9764736f6c63430008140033a2646970667358221220fee14084f7c8b84170ddb74bcefdd41ccd4dfdb6fcb6f2b4715d9e5da996604564736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000008": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000008" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000009": { + "storage": {}, + "code": "0x6080604052600436106200012b5760003560e01c80636c6563f611620000ad578063a86f9d9e116200006c578063a86f9d9e146200035c578063bc197c811462000381578063c287e57814620003b4578063f23a6e6114620003e8578063f2fde38b146200041957600080fd5b80636c6563f614620002b1578063715018a614620002d65780637333964314620002ee5780638da5cb5b14620003055780639aa8605c146200032557600080fd5b80632ca069a511620000fa5780632ca069a514620001cd57806332a642ca14620002045780633ab76e9f146200021b57806359f4a907146200024f57806367090ccf146200026c57600080fd5b806301ffc9a714620001305780630652b57a146200016a57806319ab453c146200019157806320b8155914620001b6575b600080fd5b3480156200013d57600080fd5b50620001556200014f36600462001fcf565b6200043e565b60405190151581526020015b60405180910390f35b3480156200017757600080fd5b506200018f620001893660046200201e565b62000488565b005b3480156200019e57600080fd5b506200018f620001b03660046200201e565b62000504565b6200018f620001c73660046200213b565b62000624565b348015620001da57600080fd5b50620001ea636cdb3d1360e11b81565b6040516001600160e01b0319909116815260200162000161565b6200018f6200021536600462002201565b62000953565b3480156200022857600080fd5b506097546001600160a01b03165b6040516001600160a01b03909116815260200162000161565b3480156200025c57600080fd5b50620001ea6380ac58cd60e01b81565b3480156200027957600080fd5b50620002366200028b3660046200223f565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b348015620002be57600080fd5b5062000236620002d036600462002281565b62000cfb565b348015620002e357600080fd5b506200018f62000d14565b6200018f620002ff36600462002343565b62000d2c565b3480156200031257600080fd5b506065546001600160a01b031662000236565b3480156200033257600080fd5b506200034a620003443660046200201e565b620010a7565b604051620001619493929190620024b5565b3480156200036957600080fd5b50620002366200037b366004620024f5565b620011fa565b3480156200038e57600080fd5b50620001ea620003a0366004620025af565b63bc197c8160e01b98975050505050505050565b348015620003c157600080fd5b5062000155620003d33660046200201e565b60c96020526000908152604090205460ff1681565b348015620003f557600080fd5b50620001ea620004073660046200267b565b63f23a6e6160e01b9695505050505050565b3480156200042657600080fd5b506200018f620004383660046200201e565b62001209565b60006001600160e01b031982166301ffc9a760e01b14806200047057506001600160e01b03198216631953216560e11b145b80620004825750620004828262001285565b92915050565b62000492620012bc565b6001600160a01b038116620004ba57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff1615808015620005255750600054600160ff909116105b80620005415750303b15801562000541575060005460ff166001145b620005aa5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620005ce576000805461ff0019166101001790555b620005d98262001318565b801562000620576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6200062e62001337565b6562726964676560d01b62000645816001620011fa565b6001600160a01b0316336001600160a01b0316146200067757604051630d85cccf60e11b815260040160405180910390fd5b60405163881107d960e01b81526c195c98cc4c4d4d57dd985d5b1d609a1b600482015230602482015260009073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d9063881107d990604401606060405180830381865af4158015620006e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007069190620026fe565b9050600046883503620007e757620007256040890160208a016200201e565b905060005b8551811015620007e057816001600160a01b031663f242432a30898985815181106200075a576200075a62002765565b602002602001015189868151811062000777576200077762002765565b60200260200101516040518563ffffffff1660e01b8152600401620007a094939291906200277b565b600060405180830381600087803b158015620007bb57600080fd5b505af1158015620007d0573d6000803e3d6000fd5b505050508060010190506200072a565b50620008ce565b620007fc620007f68962002868565b62001392565b905060005b8551811015620008cc57816001600160a01b031663156e29f68888848151811062000830576200083062002765565b60200260200101518885815181106200084d576200084d62002765565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b158015620008a757600080fd5b505af1158015620008bc573d6000803e3d6000fd5b5050505080600101905062000801565b505b620008e36001600160a01b03871634620013d3565b856001600160a01b0316876001600160a01b031683600001517f0f60c37489e435ed8490c30b01c1fa57e62510e88b351b75796ad3d95babe6b18560400151858a8a604051620009379493929190620028b3565b60405180910390a45050506200094c60018055565b5050505050565b6200095d62001337565b6562726964676560d01b62000974816001620011fa565b6001600160a01b0316336001600160a01b031614620009a657604051630d85cccf60e11b815260040160405180910390fd5b60008080620009ba610140860186620028f3565b620009ca9160049082906200293c565b810190620009d9919062002968565b9450945050509250600073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d632c6a56af8762000a146562726964676560d01b6000620011fa565b87602001516040518463ffffffff1660e01b815260040162000a399392919062002a2c565b602060405180830381865af415801562000a57573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a7d919062002b86565b6020808601516001600160a01b0316600090815260c9909152604090205490915060ff161562000b915760005b835181101562000b8a5760208501516001600160a01b031663156e29f662000ad960a08a0160808b016200201e565b86848151811062000aee5762000aee62002765565b602002602001015186858151811062000b0b5762000b0b62002765565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b15801562000b6557600080fd5b505af115801562000b7a573d6000803e3d6000fd5b5050505080600101905062000aaa565b5062000c61565b60005b835181101562000c5f5760208501516001600160a01b031663f242432a3062000bc460a08b0160808c016200201e565b87858151811062000bd95762000bd962002765565b602002602001015187868151811062000bf65762000bf662002765565b60200260200101516040518563ffffffff1660e01b815260040162000c1f94939291906200277b565b600060405180830381600087803b15801562000c3a57600080fd5b505af115801562000c4f573d6000803e3d6000fd5b5050505080600101905062000b94565b505b62000c8c60e087013562000c7c60a0890160808a016200201e565b6001600160a01b031690620013d3565b62000c9e60a08701608088016200201e565b6001600160a01b0316817fe8449897bd3c926a272780c39ba13e77bf7a2c823479a75bfbc13ef631183dfd8660200151868660405162000ce19392919062002ba0565b60405180910390a3505050505062000cf860018055565b50565b600062000d0a8484846200149a565b90505b9392505050565b62000d1e620012bc565b62000d2a600062001554565b565b62000d3662001337565b60808101516060820151604051636030ce6160e11b815273b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d9263c0619cc29262000d7a9260009060040162002be4565b60006040518083038186803b15801562000d9357600080fd5b505af415801562000da8573d6000803e3d6000fd5b5050505073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d6393522e3e62000de883600001516c195c98cc4c4d4d57dd985d5b1d609a1b600062000cfb565b602084015160408086015190516001600160e01b031960e086901b1681526001600160a01b039384166004820152918316602483015291909116604482015260640160006040518083038186803b15801562000e4357600080fd5b505af415801562000e58573d6000803e3d6000fd5b505050604082015162000e7d91506001600160a01b0316636cdb3d1360e11b620015a6565b62000e9b57604051633ee915f560e11b815260040160405180910390fd5b60808082015160408084015160608086015183516101808101855260008082526020820181905294810185905280830185905295860184905260a0860184905260c0860184905260e086018490526101008601849052610120860193909352610140850181905261016085015291928451606082015262000f1d338662001623565b610140820152336080820152606081015162000f4c906c195c98cc4c4d4d57dd985d5b1d609a1b600062000cfb565b6001600160a01b031660a08083019190915285015161012082015260c085015162000f78903462002c20565b60e08083019190915260c08087015161010080850191909152918701516001600160a01b031690830152850151610160820152600062000fc26562726964676560d01b82620011fa565b6001600160a01b0316634c1888bc34846040518363ffffffff1660e01b815260040162000ff0919062002c42565b60206040518083038185885af11580156200100f573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019062001036919062002b86565b905085602001516001600160a01b031682608001516001600160a01b0316827f5e54276405062454e6226625b28a6fea0a838d6b054e38955667234afb3345a3856060015188888b604051620010909493929190620028b3565b60405180910390a4505050505062000cf860018055565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b0390921692620010db9062002d2b565b80601f0160208091040260200160405190810160405280929190818152602001828054620011099062002d2b565b80156200115a5780601f106200112e576101008083540402835291602001916200115a565b820191906000526020600020905b8154815290600101906020018083116200113c57829003601f168201915b505050505090806003018054620011719062002d2b565b80601f01602080910402602001604051908101604052809291908181526020018280546200119f9062002d2b565b8015620011f05780601f10620011c457610100808354040283529160200191620011f0565b820191906000526020600020905b815481529060010190602001808311620011d257829003601f168201915b5050505050905084565b600062000d0d4684846200149a565b62001213620012bc565b6001600160a01b0381166200127a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620005a1565b62000cf88162001554565b60006001600160e01b03198216630271189760e51b14806200048257506301ffc9a760e01b6001600160e01b031983161462000482565b6065546001600160a01b0316331462000d2a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620005a1565b6200132262001b2d565b6200132c62001b61565b62000cf88162001b95565b6002600154036200138b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401620005a1565b6002600155565b8051600090815260cb60209081526040808320828501516001600160a01b0390811685529252909120541680620013ce57620004828262001bdf565b919050565b801580620013e857506001600160a01b038216155b15620013f2575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811462001441576040519150601f19603f3d011682016040523d82523d6000602084013e62001446565b606091505b50509050806200148f5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606401620005a1565b505050565b60018055565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015620014ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001512919062002d67565b9050811580156200152a57506001600160a01b038116155b1562000d0d57604051631467050360e21b81526004810185905260248101849052604401620005a1565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516301ffc9a760e01b81526001600160e01b0319821660048201526000906001600160a01b038416906301ffc9a790602401602060405180830381865afa92505050801562001616575060408051601f3d908101601f19168201909252620016139181019062002d87565b60015b1562000482579392505050565b604080516080810182526000808252602082015260609181018290528082018290526040808401516001600160a01b0316600090815260c9602052205460ff1615620018c7576040808401516001600160a01b03908116600090815260ca6020908152908390208351608081018552815481526001820154909316918301919091526002810180549293919291840191620016be9062002d2b565b80601f0160208091040260200160405190810160405280929190818152602001828054620016ec9062002d2b565b80156200173d5780601f1062001711576101008083540402835291602001916200173d565b820191906000526020600020905b8154815290600101906020018083116200171f57829003601f168201915b50505050508152602001600382018054620017589062002d2b565b80601f0160208091040260200160405190810160405280929190818152602001828054620017869062002d2b565b8015620017d75780601f10620017ab57610100808354040283529160200191620017d7565b820191906000526020600020905b815481529060010190602001808311620017b957829003601f168201915b505050505081525050905060005b836060015151811015620018c05783604001516001600160a01b031663f5298aca868660600151848151811062001820576200182062002765565b60200260200101518760800151858151811062001841576200184162002765565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b1580156200189b57600080fd5b505af1158015620018b0573d6000803e3d6000fd5b50505050806001019050620017e5565b5062001ac6565b604051806080016040528046815260200184604001516001600160a01b03168152602001604051806020016040528060008152508152602001604051806020016040528060008152508152509050600083604001519050806001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa9250505080156200198057506040513d6000823e601f3d908101601f191682016040526200197d919081019062002da7565b60015b156200198c5760608301525b806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa925050508015620019ee57506040513d6000823e601f3d908101601f19168201604052620019eb919081019062002da7565b60015b15620019fa5760408301525b60005b84606001515181101562001ac35784604001516001600160a01b031663f242432a33308860600151858151811062001a395762001a3962002765565b60200260200101518960800151868151811062001a5a5762001a5a62002765565b60200260200101516040518563ffffffff1660e01b815260040162001a8394939291906200277b565b600060405180830381600087803b15801562001a9e57600080fd5b505af115801562001ab3573d6000803e3d6000fd5b50505050806001019050620019fd565b50505b6020830151606084015160808501516040516320b8155960e01b9362001af39386938a9360240162002e74565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152949350505050565b600054610100900460ff1662001b575760405162461bcd60e51b8152600401620005a19062002ed6565b62000d2a62001e58565b600054610100900460ff1662001b8b5760405162461bcd60e51b8152600401620005a19062002ed6565b62000d2a62001e82565b6001600160a01b03811662001bbd57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60008062001c3c60008460405160200162001bfb919062002f21565b604051602081830303815290604052805190602001206040518060200162001c239062001fc1565b601f1982820381018352601f9091011660405262001eb7565b905073b2Bcd028F53637a4FC4E06C52d247F38f44cBe4d6378adc0d68262001c6c6065546001600160a01b031690565b60975460208089015189516040808c015160608d0151915163689ccd8d60e11b9662001ca8966001600160a01b03909116959493910162002f36565b60408051601f198184030181529082905262001cc8929160200162002f7f565b6040516020818303038152906040526040518463ffffffff1660e01b815260040162001cf79392919062002fb2565b602060405180830381865af415801562001d15573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001d3b919062002d67565b6001600160a01b03818116600090815260c9602090815260408083208054600160ff19909116811790915560ca835292819020885181559188015192820180546001600160a01b03191693909416929092179092558501519193508491600282019062001da9908262003032565b506060820151600382019062001dc0908262003032565b50508351600090815260cb6020908152604080832082880180516001600160a01b039081168652919093529281902080546001600160a01b031916878516908117909155915187518289015160608a015193519496509190941693927f2da3c4d305298f6df3653c23d98b4c055f72f7e6f981b2c477ccbec92b1ee5799262001e4a9291620030fe565b60405180910390a450919050565b600054610100900460ff16620014945760405162461bcd60e51b8152600401620005a19062002ed6565b600054610100900460ff1662001eac5760405162461bcd60e51b8152600401620005a19062002ed6565b62000d2a3362001554565b60008347101562001f0b5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e63650000006044820152606401620005a1565b815160000362001f5e5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152606401620005a1565b8282516020840186f590506001600160a01b03811662000d0d5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152606401620005a1565b612546806200312883390190565b60006020828403121562001fe257600080fd5b81356001600160e01b03198116811462000d0d57600080fd5b6001600160a01b038116811462000cf857600080fd5b8035620013ce8162001ffb565b6000602082840312156200203157600080fd5b813562000d0d8162001ffb565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b03811182821017156200207a576200207a6200203e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620020ab57620020ab6200203e565b604052919050565b600082601f830112620020c557600080fd5b813560206001600160401b03821115620020e357620020e36200203e565b8160051b620020f482820162002080565b92835284810182019282810190878511156200210f57600080fd5b83870192505b84831015620021305782358252918301919083019062002115565b979650505050505050565b600080600080600060a086880312156200215457600080fd5b85356001600160401b03808211156200216c57600080fd5b908701906080828a0312156200218157600080fd5b909550602087013590620021958262001ffb565b909450604087013590620021a98262001ffb565b90935060608701359080821115620021c057600080fd5b620021ce89838a01620020b3565b93506080880135915080821115620021e557600080fd5b50620021f488828901620020b3565b9150509295509295909350565b6000602082840312156200221457600080fd5b81356001600160401b038111156200222b57600080fd5b8201610180818503121562000d0d57600080fd5b600080604083850312156200225357600080fd5b823591506020830135620022678162001ffb565b809150509250929050565b801515811462000cf857600080fd5b6000806000606084860312156200229757600080fd5b83359250602084013591506040840135620022b28162002272565b809150509250925092565b60006001600160401b03821115620022d957620022d96200203e565b50601f01601f191660200190565b600082601f830112620022f957600080fd5b8135620023106200230a82620022bd565b62002080565b8181528460208386010111156200232657600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156200235657600080fd5b81356001600160401b03808211156200236e57600080fd5b9083019061012082860312156200238457600080fd5b6200238e62002054565b82358152620023a06020840162002011565b6020820152620023b36040840162002011565b6040820152606083013582811115620023cb57600080fd5b620023d987828601620020b3565b606083015250608083013582811115620023f257600080fd5b6200240087828601620020b3565b60808301525060a083013560a082015260c083013560c08201526200242860e0840162002011565b60e082015261010080840135838111156200244257600080fd5b6200245088828701620022e7565b918301919091525095945050505050565b60005b838110156200247e57818101518382015260200162002464565b50506000910152565b60008151808452620024a181602086016020860162002461565b601f01601f19169290920160200192915050565b8481526001600160a01b0384166020820152608060408201819052600090620024e19083018562002487565b828103606084015262002130818562002487565b600080604083850312156200250957600080fd5b823591506020830135620022678162002272565b60008083601f8401126200253057600080fd5b5081356001600160401b038111156200254857600080fd5b6020830191508360208260051b85010111156200256457600080fd5b9250929050565b60008083601f8401126200257e57600080fd5b5081356001600160401b038111156200259657600080fd5b6020830191508360208285010111156200256457600080fd5b60008060008060008060008060a0898b031215620025cc57600080fd5b8835620025d98162001ffb565b97506020890135620025eb8162001ffb565b965060408901356001600160401b03808211156200260857600080fd5b620026168c838d016200251d565b909850965060608b01359150808211156200263057600080fd5b6200263e8c838d016200251d565b909650945060808b01359150808211156200265857600080fd5b50620026678b828c016200256b565b999c989b5096995094979396929594505050565b60008060008060008060a087890312156200269557600080fd5b8635620026a28162001ffb565b95506020870135620026b48162001ffb565b9450604087013593506060870135925060808701356001600160401b03811115620026de57600080fd5b620026ec89828a016200256b565b979a9699509497509295939492505050565b6000606082840312156200271157600080fd5b604051606081018181106001600160401b03821117156200273657620027366200203e565b6040528251815260208301516200274d8162001ffb565b60208201526040928301519281019290925250919050565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b600060808284031215620027c657600080fd5b604051608081016001600160401b038282108183111715620027ec57620027ec6200203e565b816040528293508435835260208501359150620028098262001ffb565b81602084015260408501359150808211156200282457600080fd5b6200283286838701620022e7565b604084015260608501359150808211156200284c57600080fd5b506200285b85828601620022e7565b6060830152505092915050565b6000620004823683620027b3565b600081518084526020808501945080840160005b83811015620028a8578151875295820195908201906001016200288a565b509495945050505050565b8481526001600160a01b0384166020820152608060408201819052600090620028df9083018562002876565b828103606084015262002130818562002876565b6000808335601e198436030181126200290b57600080fd5b8301803591506001600160401b038211156200292657600080fd5b6020019150368190038213156200256457600080fd5b600080858511156200294d57600080fd5b838611156200295b57600080fd5b5050820193919092039150565b600080600080600060a086880312156200298157600080fd5b85356001600160401b03808211156200299957600080fd5b620029a789838a01620027b3565b965060208801359150620021958262001ffb565b6000808335601e19843603018112620029d357600080fd5b83016020810192503590506001600160401b03811115620029f357600080fd5b8036038213156200256457600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6060815283356060820152600062002a476020860162002011565b6001600160a01b038116608084015250604085013560a0830152606085013560c083015262002a796080860162002011565b6001600160a01b031660e083015262002a9560a0860162002011565b61010062002aad818501836001600160a01b03169052565b62002abb60c0880162002011565b915061012062002ad5818601846001600160a01b03169052565b610140925060e08801358386015261016082890135818701526101809250818901358387015262002b09848a018a620029bb565b94509150826101a087015262002b256101e08701858462002a03565b935062002b35818a018a620029bb565b9350915050605f19858403016101c086015262002b5483838362002a03565b935050505062002b6f60208301856001600160a01b03169052565b6001600160a01b0383166040830152949350505050565b60006020828403121562002b9957600080fd5b5051919050565b6001600160a01b038416815260606020820181905260009062002bc69083018562002876565b828103604084015262002bda818562002876565b9695505050505050565b60608152600062002bf9606083018662002876565b828103602084015262002c0d818662002876565b9150508215156040830152949350505050565b818103818111156200048257634e487b7160e01b600052601160045260246000fd5b60208152815160208201526000602083015162002c6a60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015162002c9a60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e083015161010083810191909152830151610120808401919091528301516101408084019190915283015161018061016080850182905262002d0d6101a086018462002487565b90860151858203601f19018387015290925062002bda838262002487565b600181811c9082168062002d4057607f821691505b60208210810362002d6157634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121562002d7a57600080fd5b815162000d0d8162001ffb565b60006020828403121562002d9a57600080fd5b815162000d0d8162002272565b60006020828403121562002dba57600080fd5b81516001600160401b0381111562002dd157600080fd5b8201601f8101841362002de357600080fd5b805162002df46200230a82620022bd565b81815285602083850101111562002e0a57600080fd5b62002e1d82602083016020860162002461565b95945050505050565b8051825260018060a01b036020820151166020830152600060408201516080604085015262002e59608085018262002487565b90506060830151848203606086015262002e1d828262002487565b60a08152600062002e8960a083018862002e26565b6001600160a01b03878116602085015286166040840152828103606084015262002eb4818662002876565b9050828103608084015262002eca818562002876565b98975050505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60208152600062000d0d602083018462002e26565b6001600160a01b038681168252851660208201526040810184905260a06060820181905260009062002f6b9083018562002487565b828103608084015262002eca818562002487565b6001600160e01b031983168152815160009062002fa481600485016020870162002461565b919091016004019392505050565b6001600160a01b0384811682528316602082015260606040820181905260009062002e1d9083018462002487565b601f8211156200148f57600081815260208120601f850160051c81016020861015620030095750805b601f850160051c820191505b818110156200302a5782815560010162003015565b505050505050565b81516001600160401b038111156200304e576200304e6200203e565b62003066816200305f845462002d2b565b8462002fe0565b602080601f8311600181146200309e5760008415620030855750858301515b600019600386901b1c1916600185901b1785556200302a565b600085815260208120601f198616915b82811015620030cf57888601518255948401946001909101908401620030ae565b5085821015620030ee5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600062003113604083018562002487565b828103602084015262002e1d81856200248756fe608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61245880620000ee6000396000f3fe608060405234801561001057600080fd5b50600436106101415760003560e01c8063715018a6116100b8578063a86f9d9e1161007c578063a86f9d9e1461029c578063d1399b1a146102af578063e985e9c5146102c2578063f242432a146102fe578063f2fde38b14610311578063f5298aca1461032457600080fd5b8063715018a6146102545780637cf8ed0d1461025c5780638da5cb5b1461027057806395d89b4114610281578063a22cb4651461028957600080fd5b8063156e29f61161010a578063156e29f6146101cc5780632eb2c2d6146101df5780633ab76e9f146101f257806349d12605146102175780634e1273f4146102215780636c6563f61461024157600080fd5b8062fdd58e1461014657806301ffc9a71461016c5780630652b57a1461018f57806306fdde03146101a45780630e89341c146101b9575b600080fd5b6101596101543660046118e5565b610337565b6040519081526020015b60405180910390f35b61017f61017a366004611927565b6103d2565b6040519015158152602001610163565b6101a261019d366004611944565b610422565b005b6101ac61049b565b60405161016391906119b1565b6101ac6101c73660046119c4565b6104d1565b6101a26101da3660046119dd565b610565565b6101a26101ed366004611b5e565b61061b565b6097546001600160a01b03165b6040516001600160a01b039091168152602001610163565b61015961012e5481565b61023461022f366004611c0c565b610667565b6040516101639190611d14565b6101ff61024f366004611d3c565b610791565b6101a26107a8565b61012d546101ff906001600160a01b031681565b6065546001600160a01b03166101ff565b6101ac6107bc565b6101a2610297366004611d71565b61084b565b6101ff6102aa366004611da6565b61085a565b6101a26102bd366004611dc9565b610867565b61017f6102d0366004611e2c565b6001600160a01b03918216600090815260fc6020908152604080832093909416825291909152205460ff1690565b6101a261030c366004611e65565b610a10565b6101a261031f366004611944565b610a46565b6101a26103323660046119dd565b610abf565b60006001600160a01b0383166103a75760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b50600081815260fb602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b148061040357506001600160e01b031982166303a24d0760e21b145b806103cc57506301ffc9a760e01b6001600160e01b03198316146103cc565b61042a610b5b565b6001600160a01b03811661045157604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b60606101306104ac61012e54610bb5565b6040516020016104bd929190611f08565b604051602081830303815290604052905090565b606060fd80546104e090611ece565b80601f016020809104026020016040519081016040528092919081815260200182805461050c90611ece565b80156105595780601f1061052e57610100808354040283529160200191610559565b820191906000526020600020905b81548152906001019060200180831161053c57829003601f168201915b50505050509050919050565b6c195c98cc4c4d4d57dd985d5b1d609a1b61058181600161085a565b6001600160a01b0316336001600160a01b0316146105b257604051630d85cccf60e11b815260040160405180910390fd5b6105cd84848460405180602001604052806000815250610c48565b60408051848152602081018490526001600160a01b038616916000917f9ed053bb818ff08b8353cd46f78db1f0799f31c9e4458fdb425c10eccd2efc4491015b60405180910390a350505050565b6001600160a01b038516331480610637575061063785336102d0565b6106535760405162461bcd60e51b815260040161039e90611f9e565b6106608585858585610d5e565b5050505050565b606081518351146106cc5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b606482015260840161039e565b6000835167ffffffffffffffff8111156106e8576106e8611a12565b604051908082528060200260200182016040528015610711578160200160208202803683370190505b50905060005b84518110156107895761075c85828151811061073557610735611fec565b602002602001015185838151811061074f5761074f611fec565b6020026020010151610337565b82828151811061076e5761076e611fec565b602090810291909101015261078281612018565b9050610717565b509392505050565b600061079e848484610f36565b90505b9392505050565b6107b0610b5b565b6107ba6000610fea565b565b61012f80546107ca90611ece565b80601f01602080910402602001604051908101604052809291908181526020018280546107f690611ece565b80156108435780601f1061081857610100808354040283529160200191610843565b820191906000526020600020905b81548152906001019060200180831161082657829003601f168201915b505050505081565b61085633838361103c565b5050565b60006107a1468484610f36565b600054610100900460ff16158080156108875750600054600160ff909116105b806108a15750303b1580156108a1575060005460ff166001145b6109045760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161039e565b6000805460ff191660011790558015610927576000805461ff0019166101001790555b6001600160a01b038516158061093b575083155b8061094557504684145b1561096357604051635d061ab760e11b815260040160405180910390fd5b61096c8661111c565b61098460405180602001604052806000815250611135565b61012d80546001600160a01b0319166001600160a01b03871617905561012e84905561012f6109b3848261207c565b506101306109c1838261207c565b508015610a08576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b306001600160a01b03851603610a3957604051636cfe544760e01b815260040160405180910390fd5b6106608585858585611165565b610a4e610b5b565b6001600160a01b038116610ab35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161039e565b610abc81610fea565b50565b6c195c98cc4c4d4d57dd985d5b1d609a1b610adb81600161085a565b6001600160a01b0316336001600160a01b031614610b0c57604051630d85cccf60e11b815260040160405180910390fd5b610b178484846111aa565b60408051848152602081018490526000916001600160a01b038716917f9ed053bb818ff08b8353cd46f78db1f0799f31c9e4458fdb425c10eccd2efc44910161060d565b6065546001600160a01b031633146107ba5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161039e565b60606000610bc283611329565b600101905060008167ffffffffffffffff811115610be257610be2611a12565b6040519080825280601f01601f191660200182016040528015610c0c576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610c1657509392505050565b6001600160a01b038416610ca85760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b606482015260840161039e565b336000610cb485611401565b90506000610cc185611401565b9050600086815260fb602090815260408083206001600160a01b038b16845290915281208054879290610cf590849061213c565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4610d558360008989898961144c565b50505050505050565b8151835114610dc05760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b606482015260840161039e565b6001600160a01b038416610de65760405162461bcd60e51b815260040161039e9061214f565b3360005b8451811015610ed0576000858281518110610e0757610e07611fec565b602002602001015190506000858381518110610e2557610e25611fec565b602090810291909101810151600084815260fb835260408082206001600160a01b038e168352909352919091205490915081811015610e765760405162461bcd60e51b815260040161039e90612194565b600083815260fb602090815260408083206001600160a01b038e8116855292528083208585039055908b16825281208054849290610eb590849061213c565b9250508190555050505080610ec990612018565b9050610dea565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051610f209291906121de565b60405180910390a4610a088187878787876115a7565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fab919061220c565b905081158015610fc257506001600160a01b038116155b156107a157604051631467050360e21b8152600481018590526024810184905260440161039e565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b0316036110af5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b606482015260840161039e565b6001600160a01b03838116600081815260fc6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611124611662565b61112c611691565b610abc816116c0565b600054610100900460ff1661115c5760405162461bcd60e51b815260040161039e90612229565b610abc81611709565b6001600160a01b038516331480611181575061118185336102d0565b61119d5760405162461bcd60e51b815260040161039e90611f9e565b6106608585858585611739565b6001600160a01b03831661120c5760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b606482015260840161039e565b33600061121884611401565b9050600061122584611401565b604080516020808201835260009182905288825260fb81528282206001600160a01b038b16835290522054909150848110156112af5760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b606482015260840161039e565b600086815260fb602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4604080516020810190915260009052610d55565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106113685772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611394576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106113b257662386f26fc10000830492506010015b6305f5e10083106113ca576305f5e100830492506008015b61271083106113de57612710830492506004015b606483106113f0576064830492506002015b600a83106103cc5760010192915050565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061143b5761143b611fec565b602090810291909101015292915050565b6001600160a01b0384163b15610a085760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906114909089908990889088908890600401612274565b6020604051808303816000875af19250505080156114cb575060408051601f3d908101601f191682019092526114c8918101906122b9565b60015b611577576114d76122d6565b806308c379a00361151057506114eb6122f2565b806114f65750611512565b8060405162461bcd60e51b815260040161039e91906119b1565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b606482015260840161039e565b6001600160e01b0319811663f23a6e6160e01b14610d555760405162461bcd60e51b815260040161039e9061237c565b6001600160a01b0384163b15610a085760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906115eb90899089908890889088906004016123c4565b6020604051808303816000875af1925050508015611626575060408051601f3d908101601f19168201909252611623918101906122b9565b60015b611632576114d76122d6565b6001600160e01b0319811663bc197c8160e01b14610d555760405162461bcd60e51b815260040161039e9061237c565b600054610100900460ff166116895760405162461bcd60e51b815260040161039e90612229565b6107ba611867565b600054610100900460ff166116b85760405162461bcd60e51b815260040161039e90612229565b6107ba611894565b6001600160a01b0381166116e757604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166117305760405162461bcd60e51b815260040161039e90612229565b610abc816118c4565b6001600160a01b03841661175f5760405162461bcd60e51b815260040161039e9061214f565b33600061176b85611401565b9050600061177885611401565b9050600086815260fb602090815260408083206001600160a01b038c168452909152902054858110156117bd5760405162461bcd60e51b815260040161039e90612194565b600087815260fb602090815260408083206001600160a01b038d8116855292528083208985039055908a168252812080548892906117fc90849061213c565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a461185c848a8a8a8a8a61144c565b505050505050505050565b600054610100900460ff1661188e5760405162461bcd60e51b815260040161039e90612229565b60018055565b600054610100900460ff166118bb5760405162461bcd60e51b815260040161039e90612229565b6107ba33610fea565b60fd610856828261207c565b6001600160a01b0381168114610abc57600080fd5b600080604083850312156118f857600080fd5b8235611903816118d0565b946020939093013593505050565b6001600160e01b031981168114610abc57600080fd5b60006020828403121561193957600080fd5b81356107a181611911565b60006020828403121561195657600080fd5b81356107a1816118d0565b60005b8381101561197c578181015183820152602001611964565b50506000910152565b6000815180845261199d816020860160208601611961565b601f01601f19169290920160200192915050565b6020815260006107a16020830184611985565b6000602082840312156119d657600080fd5b5035919050565b6000806000606084860312156119f257600080fd5b83356119fd816118d0565b95602085013595506040909401359392505050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715611a4e57611a4e611a12565b6040525050565b600067ffffffffffffffff821115611a6f57611a6f611a12565b5060051b60200190565b600082601f830112611a8a57600080fd5b81356020611a9782611a55565b604051611aa48282611a28565b83815260059390931b8501820192828101915086841115611ac457600080fd5b8286015b84811015611adf5780358352918301918301611ac8565b509695505050505050565b600082601f830112611afb57600080fd5b813567ffffffffffffffff811115611b1557611b15611a12565b604051611b2c601f8301601f191660200182611a28565b818152846020838601011115611b4157600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215611b7657600080fd5b8535611b81816118d0565b94506020860135611b91816118d0565b9350604086013567ffffffffffffffff80821115611bae57600080fd5b611bba89838a01611a79565b94506060880135915080821115611bd057600080fd5b611bdc89838a01611a79565b93506080880135915080821115611bf257600080fd5b50611bff88828901611aea565b9150509295509295909350565b60008060408385031215611c1f57600080fd5b823567ffffffffffffffff80821115611c3757600080fd5b818501915085601f830112611c4b57600080fd5b81356020611c5882611a55565b604051611c658282611a28565b83815260059390931b8501820192828101915089841115611c8557600080fd5b948201945b83861015611cac578535611c9d816118d0565b82529482019490820190611c8a565b96505086013592505080821115611cc257600080fd5b50611ccf85828601611a79565b9150509250929050565b600081518084526020808501945080840160005b83811015611d0957815187529582019590820190600101611ced565b509495945050505050565b6020815260006107a16020830184611cd9565b80358015158114611d3757600080fd5b919050565b600080600060608486031215611d5157600080fd5b8335925060208401359150611d6860408501611d27565b90509250925092565b60008060408385031215611d8457600080fd5b8235611d8f816118d0565b9150611d9d60208401611d27565b90509250929050565b60008060408385031215611db957600080fd5b82359150611d9d60208401611d27565b600080600080600060a08688031215611de157600080fd5b8535611dec816118d0565b94506020860135611dfc816118d0565b935060408601359250606086013567ffffffffffffffff80821115611e2057600080fd5b611bdc89838a01611aea565b60008060408385031215611e3f57600080fd5b8235611e4a816118d0565b91506020830135611e5a816118d0565b809150509250929050565b600080600080600060a08688031215611e7d57600080fd5b8535611e88816118d0565b94506020860135611e98816118d0565b93506040860135925060608601359150608086013567ffffffffffffffff811115611ec257600080fd5b611bff88828901611aea565b600181811c90821680611ee257607f821691505b602082108103611f0257634e487b7160e01b600052602260045260246000fd5b50919050565b6000808454611f1681611ece565b60018281168015611f2e5760018114611f4357611f72565b60ff1984168752821515830287019450611f72565b8860005260208060002060005b85811015611f695781548a820152908401908201611f50565b50505082870194505b50506241c55b60e71b835250508351611f92816004840160208801611961565b01600401949350505050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161202a5761202a612002565b5060010190565b601f82111561207757600081815260208120601f850160051c810160208610156120585750805b601f850160051c820191505b81811015610a0857828155600101612064565b505050565b815167ffffffffffffffff81111561209657612096611a12565b6120aa816120a48454611ece565b84612031565b602080601f8311600181146120df57600084156120c75750858301515b600019600386901b1c1916600185901b178555610a08565b600085815260208120601f198616915b8281101561210e578886015182559484019460019091019084016120ef565b508582101561212c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156103cc576103cc612002565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b6040815260006121f16040830185611cd9565b82810360208401526122038185611cd9565b95945050505050565b60006020828403121561221e57600080fd5b81516107a1816118d0565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906122ae90830184611985565b979650505050505050565b6000602082840312156122cb57600080fd5b81516107a181611911565b600060033d11156122ef5760046000803e5060005160e01c5b90565b600060443d10156123005790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561233057505050505090565b82850191508151818111156123485750505050505090565b843d87010160208285010111156123625750505050505090565b61237160208286010187611a28565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a0604082018190526000906123f090830186611cd9565b82810360608401526124028186611cd9565b905082810360808401526124168185611985565b9897505050505050505056fea2646970667358221220ee7f810feef1b382c8ef11eb3d6f0b845bda726deaea1e489e353f59025211be64736f6c63430008140033a2646970667358221220ea3ce65f4b921acac47f314a689a5ec16ba6d76cce7b6d58b3b98a450302fd6b64736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000009": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000009" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000003": { + "storage": {}, + "code": "0x6080604052600436106100ab5760003560e01c80638da5cb5b116100645780638da5cb5b146101c0578063a86f9d9e146101de578063ba0bbd95146101fe578063d73bb3d01461021e578063f2fde38b1461023e578063fe9fbb801461025e57600080fd5b80630652b57a146100f457806319ab453c146101145780632d1fb389146101345780633ab76e9f146101545780636c6563f61461018b578063715018a6146101ab57600080fd5b366100ef5747158015906100cf575033600090815260c9602052604090205460ff16155b156100ed57604051634fa3f24560e01b815260040160405180910390fd5b005b600080fd5b34801561010057600080fd5b506100ed61010f366004610a8d565b6102a7565b34801561012057600080fd5b506100ed61012f366004610a8d565b610320565b34801561014057600080fd5b506100ed61014f366004610abf565b610438565b34801561016057600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019757600080fd5b5061016e6101a6366004610af4565b6104f1565b3480156101b757600080fd5b506100ed610508565b3480156101cc57600080fd5b506065546001600160a01b031661016e565b3480156101ea57600080fd5b5061016e6101f9366004610b29565b61051c565b34801561020a57600080fd5b506100ed610219366004610b4c565b610529565b34801561022a57600080fd5b506100ed610239366004610b78565b6105ee565b34801561024a57600080fd5b506100ed610259366004610a8d565b610671565b34801561026a57600080fd5b50610297610279366004610a8d565b6001600160a01b0316600090815260c9602052604090205460ff1690565b6040519015158152602001610182565b6102af6106e7565b6001600160a01b0381166102d657604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff16158080156103405750600054600160ff909116105b8061035a5750303b15801561035a575060005460ff166001145b6103c25760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156103e5576000805461ff0019166101001790555b6103ee82610741565b8015610434576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6104406106e7565b6001600160a01b038216158061047457506001600160a01b038216600090815260c9602052604090205460ff161515811515145b1561049257604051631bebdfa760e21b815260040160405180910390fd5b6001600160a01b038216600081815260c96020908152604091829020805460ff191685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b60006104fe84848461075a565b90505b9392505050565b6105106106e7565b61051a600061080e565b565b600061050146848461075a565b33600090815260c9602052604090205460ff1661055957604051634fa3f24560e01b815260040160405180910390fd5b610561610860565b80156105e5576001600160a01b03821661058e5760405163687563df60e01b815260040160405180910390fd5b6105a16001600160a01b038316826108b9565b816001600160a01b03167f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e826040516105dc91815260200190565b60405180910390a25b61043460018055565b33600090815260c9602052604090205460ff1661061e57604051634fa3f24560e01b815260040160405180910390fd5b610626610860565b61063033826108b9565b60405181815233907f7b9f77d35803cd201eac9c4ed739bc1fcd3f1be6ab8877d925d1e55517b6fd6e9060200160405180910390a261066e60018055565b50565b6106796106e7565b6001600160a01b0381166106de5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016103b9565b61066e8161080e565b6065546001600160a01b0316331461051a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103b9565b61074961097a565b6107516109a9565b61066e816109d8565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa1580156107ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107cf9190610b91565b9050811580156107e657506001600160a01b038116155b1561050157604051631467050360e21b815260048101859052602481018490526044016103b9565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6002600154036108b25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103b9565b6002600155565b8015806108cd57506001600160a01b038216155b156108d6575050565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610923576040519150601f19603f3d011682016040523d82523d6000602084013e610928565b606091505b505090508061096f5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016103b9565b505050565b60018055565b600054610100900460ff166109a15760405162461bcd60e51b81526004016103b990610bae565b61051a610a21565b600054610100900460ff166109d05760405162461bcd60e51b81526004016103b990610bae565b61051a610a48565b6001600160a01b0381166109ff57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166109745760405162461bcd60e51b81526004016103b990610bae565b600054610100900460ff16610a6f5760405162461bcd60e51b81526004016103b990610bae565b61051a3361080e565b6001600160a01b038116811461066e57600080fd5b600060208284031215610a9f57600080fd5b813561050181610a78565b80358015158114610aba57600080fd5b919050565b60008060408385031215610ad257600080fd5b8235610add81610a78565b9150610aeb60208401610aaa565b90509250929050565b600080600060608486031215610b0957600080fd5b8335925060208401359150610b2060408501610aaa565b90509250925092565b60008060408385031215610b3c57600080fd5b82359150610aeb60208401610aaa565b60008060408385031215610b5f57600080fd5b8235610b6a81610a78565b946020939093013593505050565b600060208284031215610b8a57600080fd5b5035919050565b600060208284031215610ba357600080fd5b815161050181610a78565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea26469706673582212204c31d592cfc1ec7ee55355c17834d2e62089d97edf1b79bd01f89108c83709d164736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xa738d3397c1eb96f671d7e4bd29cabbfa1a9c9ebc0db4142aee17809c43ab720": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000003" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0xffffffffffffff21f494c589bfffffff" + }, + "0x0000777700000000000000000000000000000007": { + "storage": {}, + "code": "0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80636c6563f6116100715780636c6563f614610162578063715018a6146101755780638da5cb5b1461017d578063a86f9d9e1461018e578063f2fde38b146101a1578063f8f3f844146101b457600080fd5b80630652b57a146100b957806319ab453c146100ce57806332676bc6146100e15780633ab76e9f146101095780635221f6131461012e57806366ca2bc014610141575b600080fd5b6100cc6100c7366004611a23565b6101e0565b005b6100cc6100dc366004611a23565b610259565b6100f46100ef366004611a40565b610371565b60405190151581526020015b60405180910390f35b6097546001600160a01b03165b6040516001600160a01b039091168152602001610100565b6100f461013c366004611a6c565b6103e3565b61015461014f366004611b02565b61055d565b604051908152602001610100565b610116610170366004611b30565b6105a4565b6100cc6105bb565b6065546001600160a01b0316610116565b61011661019c366004611b65565b6105cf565b6100cc6101af366004611a23565b6105e5565b6101546101c2366004611a40565b6040805192835260208301919091526034600c830120918101905290565b6101e861065e565b6001600160a01b03811661020f57604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0383169081179091556040517f399ded90cb5ed8d89ef7e76ff4af65c373f06d3bf5d7eef55f4228e7b702a18b90600090a250565b600054610100900460ff16158080156102795750600054600160ff909116105b806102935750303b158015610293575060005460ff166001145b6102fb5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801561031e576000805461ff0019166101001790555b610327826106b8565b801561036d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6000826001600160a01b03811661039b576040516354cdfc8d60e11b815260040160405180910390fd5b8260008190036103be5760405163014f1da760e21b815260040160405180910390fd5b5050604080519384526020840192909252506034600c83012091810190525460011490565b6000854681036104065760405163e822b48d60e01b815260040160405180910390fd5b856001600160a01b03811661042e576040516354cdfc8d60e11b815260040160405180910390fd5b8560008190036104515760405163014f1da760e21b815260040160405180910390fd5b600061045f86880188611c01565b90506000610476647461696b6f60d81b60006105cf565b825160405163016674a560e21b815267ffffffffffffffff90911660048201526001600160a01b039190911690630599d29490602401602060405180830381865afa1580156104c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ed9190611cd6565b604080518c8152602081018c90526034600c820120818301909252606081019190915290915061054e90608001604051602081830303815290604052604051806040016040528060018152602001600160f81b8152508460200151846106d1565b9b9a5050505050505050505050565b6000818082036105805760405163014f1da760e21b815260040160405180910390fd5b50506040805133815260208101929092526034600c83012091810190526001815590565b60006105b18484846106f5565b90505b9392505050565b6105c361065e565b6105cd60006107a9565b565b60006105dc4684846106f5565b90505b92915050565b6105ed61065e565b6001600160a01b0381166106525760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016102f2565b61065b816107a9565b50565b6065546001600160a01b031633146105cd5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102f2565b6106c06107fb565b6106c861082a565b61065b81610859565b6000806106dd866108a2565b90506106eb818686866108d4565b9695505050505050565b60975460405163195ac1a960e21b815260048101859052602481018490526000916001600160a01b03169063656b06a490604401602060405180830381865afa158015610746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076a9190611cef565b90508115801561078157506001600160a01b038116155b156105b457604051631467050360e21b815260048101859052602481018490526044016102f2565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166108225760405162461bcd60e51b81526004016102f290611d0c565b6105cd610911565b600054610100900460ff166108515760405162461bcd60e51b81526004016102f290611d0c565b6105cd61093e565b6001600160a01b03811661088057604051634d084d8560e11b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b606081805190602001206040516020016108be91815260200190565b6040516020818303038152906040529050919050565b60008060006108e487868661096e565b9150915081801561090657508051602080830191909120875191880191909120145b979650505050505050565b600054610100900460ff166109385760405162461bcd60e51b81526004016102f290611d0c565b60018055565b600054610100900460ff166109655760405162461bcd60e51b81526004016102f290611d0c565b6105cd336107a9565b60006060600061097d85610a49565b9050600080600061098f848a89610b42565b815192955090935091501580806109a35750815b6109ef5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e00000000000060448201526064016102f2565b600081610a0b5760405180602001604052806000815250610a37565b610a3786610a1a600188611d6d565b81518110610a2a57610a2a611d80565b6020026020010151610f62565b919b919a509098505050505050505050565b60606000610a5683610f89565b90506000815167ffffffffffffffff811115610a7457610a74611b91565b604051908082528060200260200182016040528015610ab957816020015b6040805180820190915260608082526020820152815260200190600190039081610a925790505b50905060005b8251811015610b3a576000610aec848381518110610adf57610adf611d80565b6020026020010151610fbc565b90506040518060400160405280610b0283610f89565b815260200182815250838381518110610b1d57610b1d611d80565b60200260200101819052505080610b3390611d96565b9050610abf565b509392505050565b600060606000806000610b548761104c565b90506000869050600080610b7b604051806040016040528060608152602001606081525090565b60005b8c51811015610f3a578c8181518110610b9957610b99611d80565b602002602001015191508284610baf9190611daf565b9350610bbc600188611daf565b965083600003610c19578482602001518051906020012014610c145760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b60448201526064016102f2565b610cdb565b602082602001515110610c80578482602001518051906020012014610c145760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c2068617368000000000060448201526064016102f2565b84610c8e8360200151611185565b14610cdb5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f6465206861736800000000000060448201526064016102f2565b610ce760106001611dc2565b60ff1682600001515103610d555785518414610f3a576000868581518110610d1157610d11611d80565b01602001518351805160f89290921c925060009183908110610d3557610d35611d80565b60200260200101519050610d48816111ad565b9650600194505050610f2a565b81515160011901610ee2576000610d6b836111e3565b9050600081600081518110610d8257610d82611d80565b016020015160f81c90506000610d99600283611ddb565b610da4906002611e0b565b90506000610db5848360ff16611207565b90506000610dc38b8a611207565b90506000610dd1838361123d565b905060ff851660021480610de8575060ff85166003145b15610e2257808351148015610dfd5750808251145b15610e0f57610e0c818b611daf565b99505b50600160ff1b9950610f3a945050505050565b60ff85161580610e35575060ff85166001145b15610e8b5782518114610e555750600160ff1b9950610f3a945050505050565b610e7c8860000151600181518110610e6f57610e6f611d80565b60200260200101516111ad565b9a509750610f2a945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b60648201526084016102f2565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e00000060448201526064016102f2565b610f3381611d96565b9050610b7e565b50600160ff1b841486610f4d8786611207565b909e909d50909b509950505050505050505050565b805180516060916105df91610f7990600190611d6d565b81518110610adf57610adf611d80565b6040805180820182526000808252602091820152815180830190925282518252808301908201526060906105df906112b7565b60606000806000610fcc856114a3565b919450925090506000816001811115610fe757610fe7611e24565b146110345760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e000000000000000060448201526064016102f2565b611043856020015184846117ed565b95945050505050565b606060008251600261105e9190611e3a565b67ffffffffffffffff81111561107657611076611b91565b6040519080825280601f01601f1916602001820160405280156110a0576020820181803683370190505b50905060005b835181101561117e5760048482815181106110c3576110c3611d80565b01602001516001600160f81b031916901c826110e0836002611e3a565b815181106110f0576110f0611d80565b60200101906001600160f81b031916908160001a905350601084828151811061111b5761111b611d80565b016020015161112d919060f81c611ddb565b60f81b8261113c836002611e3a565b611147906001611daf565b8151811061115757611157611d80565b60200101906001600160f81b031916908160001a90535061117781611d96565b90506110a6565b5092915050565b600060208251101561119957506020015190565b818060200190518101906105df9190611cd6565b600060606020836000015110156111ce576111c783611896565b90506111da565b6111d783610fbc565b90505b6105b481611185565b60606105df6112028360000151600081518110610adf57610adf611d80565b61104c565b60608251821061122657506040805160208101909152600081526105df565b6105dc83838486516112389190611d6d565b6118a1565b6000805b8084511180156112515750808351115b80156112a2575082818151811061126a5761126a611d80565b602001015160f81c60f81b6001600160f81b03191684828151811061129157611291611d80565b01602001516001600160f81b031916145b156105dc576112b081611d96565b9050611241565b60606000806112c5846114a3565b919350909150600190508160018111156112e1576112e1611e24565b1461132e5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e00000000000000000060448201526064016102f2565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816113475790505090506000835b865181101561149857602082106113e05760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b60648201526084016102f2565b60008061141d6040518060400160405280858c600001516114019190611d6d565b8152602001858c602001516114169190611daf565b90526114a3565b5091509150604051806040016040528083836114399190611daf565b8152602001848b6020015161144e9190611daf565b81525085858151811061146357611463611d80565b6020908102919091010152611479600185611daf565b93506114858183611daf565b61148f9084611daf565b92505050611374565b508152949350505050565b6000806000808460000151116114fb5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e000000000000000060448201526064016102f2565b6020840151805160001a607f81116115205760006001600094509450945050506117e6565b60b7811161159c576000611535608083611d6d565b90508087600001511161158a5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e0000000000000060448201526064016102f2565b600195509350600092506117e6915050565b60bf811161168b5760006115b160b783611d6d565b9050808760000151116116065760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e0060448201526064016102f2565b600183015160208290036101000a90046116208183611daf565b88511161166f5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e000000000000000060448201526064016102f2565b61167a826001611daf565b96509450600093506117e692505050565b60f781116117065760006116a060c083611d6d565b9050808760000151116116f55760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e00000000000000000060448201526064016102f2565b6001955093508492506117e6915050565b600061171360f783611d6d565b9050808760000151116117685760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e00000060448201526064016102f2565b600183015160208290036101000a90046117828183611daf565b8851116117ca5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b60448201526064016102f2565b6117d5826001611daf565b96509450600193506117e692505050565b9193909250565b606060008267ffffffffffffffff81111561180a5761180a611b91565b6040519080825280601f01601f191660200182016040528015611834576020820181803683370190505b50905080516000036118475790506105b4565b8484016020820160005b85811015611869578281015182820152602001611851565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60606105df826119f8565b6060816118af81601f611daf565b10156118ee5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102f2565b826118f98382611daf565b10156119385760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016102f2565b6119428284611daf565b845110156119865760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016102f2565b6060821580156119a557604051915060008252602082016040526119ef565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156119de5780518352602092830192016119c6565b5050858452601f01601f1916604052505b50949350505050565b60606105df8260200151600084600001516117ed565b6001600160a01b038116811461065b57600080fd5b600060208284031215611a3557600080fd5b81356105dc81611a0e565b60008060408385031215611a5357600080fd5b8235611a5e81611a0e565b946020939093013593505050565b600080600080600060808688031215611a8457600080fd5b853594506020860135611a9681611a0e565b935060408601359250606086013567ffffffffffffffff80821115611aba57600080fd5b818801915088601f830112611ace57600080fd5b813581811115611add57600080fd5b896020828501011115611aef57600080fd5b9699959850939650602001949392505050565b600060208284031215611b1457600080fd5b5035919050565b80358015158114611b2b57600080fd5b919050565b600080600060608486031215611b4557600080fd5b8335925060208401359150611b5c60408501611b1b565b90509250925092565b60008060408385031215611b7857600080fd5b82359150611b8860208401611b1b565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611bca57611bca611b91565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611bf957611bf9611b91565b604052919050565b60006020808385031215611c1457600080fd5b823567ffffffffffffffff80821115611c2c57600080fd5b9084019060408287031215611c4057600080fd5b611c48611ba7565b82358281168114611c5857600080fd5b81528284013582811115611c6b57600080fd5b80840193505086601f840112611c8057600080fd5b823582811115611c9257611c92611b91565b611ca4601f8201601f19168601611bd0565b92508083528785828601011115611cba57600080fd5b8085850186850137600090830185015292830152509392505050565b600060208284031215611ce857600080fd5b5051919050565b600060208284031215611d0157600080fd5b81516105dc81611a0e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b818103818111156105df576105df611d57565b634e487b7160e01b600052603260045260246000fd5b600060018201611da857611da8611d57565b5060010190565b808201808211156105df576105df611d57565b60ff81811683821601908111156105df576105df611d57565b600060ff831680611dfc57634e487b7160e01b600052601260045260246000fd5b8060ff84160691505092915050565b60ff82811682821603908111156105df576105df611d57565b634e487b7160e01b600052602160045260246000fd5b80820281158282048414176105df576105df611d5756fea2646970667358221220c8e5d2f03cdfd05271211f91051ea017cc78712d374c157f61c7f6293b421c5864736f6c63430008140033", + "balance": "0x0" + }, + "0x1000777700000000000000000000000000000007": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000019b4f9c381c7927fe33d853e48b560141a380c44", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001000777700000000000000000000000000000006", + "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x113cE23c9e0cc50F4D41d7cE6DA02dCAFf8BFF85", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0000777700000000000000000000000000000007" + }, + "code": "0x60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106b3565b610118565b61005b6100933660046106ce565b610155565b3480156100a457600080fd5b506100ad6101bc565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106b3565b6101ed565b3480156100f557600080fd5b506100ad61020d565b61010661022e565b6101166101116102c3565b6102cd565b565b6101206102f1565b6001600160a01b0316330361014d5761014a81604051806020016040528060008152506000610324565b50565b61014a6100fe565b61015d6102f1565b6001600160a01b031633036101b4576101af8383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525060019250610324915050565b505050565b6101af6100fe565b60006101c66102f1565b6001600160a01b031633036101e2576101dd6102c3565b905090565b6101ea6100fe565b90565b6101f56102f1565b6001600160a01b0316330361014d5761014a8161034f565b60006102176102f1565b6001600160a01b031633036101e2576101dd6102f1565b6102366102f1565b6001600160a01b031633036101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101dd6103a3565b3660008037600080366000845af43d6000803e8080156102ec573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b61032d836103cb565b60008251118061033a5750805b156101af57610349838361040b565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103786102f1565b604080516001600160a01b03928316815291841660208301520160405180910390a161014a81610437565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610315565b6103d4816104e0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606061043083836040518060600160405280602781526020016107c560279139610574565b9392505050565b6001600160a01b03811661049c5760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084016102ba565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b6001600160a01b0381163b61054d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016102ba565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6104bf565b6060600080856001600160a01b0316856040516105919190610775565b600060405180830381855af49150503d80600081146105cc576040519150601f19603f3d011682016040523d82523d6000602084013e6105d1565b606091505b50915091506105e2868383876105ec565b9695505050505050565b6060831561065b578251600003610654576001600160a01b0385163b6106545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102ba565b5081610665565b610665838361066d565b949350505050565b81511561067d5781518083602001fd5b8060405162461bcd60e51b81526004016102ba9190610791565b80356001600160a01b03811681146106ae57600080fd5b919050565b6000602082840312156106c557600080fd5b61043082610697565b6000806000604084860312156106e357600080fd5b6106ec84610697565b9250602084013567ffffffffffffffff8082111561070957600080fd5b818601915086601f83011261071d57600080fd5b81358181111561072c57600080fd5b87602082850101111561073e57600080fd5b6020830194508093505050509250925092565b60005b8381101561076c578181015183820152602001610754565b50506000910152565b60008251610787818460208701610751565b9190910192915050565b60208152600082518060208401526107b0816040850160208701610751565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122013e4be7fbb9448379ca283101ef1037ca99a17f6ad00269fe32f79bcefab6e1864736f6c63430008140033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000003e8000", + "0xc4fd933fc30203af5f8bd19ad30e064c96642a369b9fc4288ea95569541f4034": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x967c153683def525608ec6efe0cac3319a9c97a6d4164fb43765c79311abffdc": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x4b9b777e5e3847acfd8740f275a6896b3f3a10ae36191d153fdb5ef40d61b6c1": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x9e7a5276a30d934c5fffd9ef18e4dcae10597352188cecf658522b6bf4d924d3": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069c565b60405180910390f35b6100df6100da366004610706565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610730565b61024c565b604051601281526020016100c3565b6100df610131366004610706565b610270565b6100f361014436600461076c565b6001600160a01b031660009081526020819052604090205490565b6100b6610292565b6100df610175366004610706565b6102a1565b6100df610188366004610706565b610321565b6100f361019b36600461078e565b61032f565b6060600380546101af906107c1565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c1565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b60003361024081858561035a565b60019150505b92915050565b60003361025a85828561047e565b6102658585856104f8565b506001949350505050565b600033610240818585610283838361032f565b61028d91906107fb565b61035a565b6060600480546101af906107c1565b600033816102af828661032f565b9050838110156103145760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b610265828686840361035a565b6000336102408185856104f8565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103bc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161030b565b6001600160a01b03821661041d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161030b565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061048a848461032f565b905060001981146104f257818110156104e55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161030b565b6104f2848484840361035a565b50505050565b6001600160a01b03831661055c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161030b565b6001600160a01b0382166105be5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161030b565b6001600160a01b038316600090815260208190526040902054818110156106365760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161030b565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f2565b600060208083528351808285015260005b818110156106c9578581018301518582016040015282016106ad565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461070157600080fd5b919050565b6000806040838503121561071957600080fd5b610722836106ea565b946020939093013593505050565b60008060006060848603121561074557600080fd5b61074e846106ea565b925061075c602085016106ea565b9150604084013590509250925092565b60006020828403121561077e57600080fd5b610787826106ea565b9392505050565b600080604083850312156107a157600080fd5b6107aa836106ea565b91506107b8602084016106ea565b90509250929050565b600181811c908216806107d557607f821691505b6020821081036107f557634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561024657634e487b7160e01b600052601160045260246000fdfea26469706673582212200c6a590d0220261e9ad2a153910ca40f21f69a425e5af92fee3a769ffc07753764736f6c63430008140033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/katla.json b/crates/primitives/res/genesis/taiko/katla.json new file mode 100644 index 000000000000..52d72f3718b3 --- /dev/null +++ b/crates/primitives/res/genesis/taiko/katla.json @@ -0,0 +1,186 @@ +{ + "0x1D2D1bb9D180541E88a6a682aCf3f61c1605B190": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x39aF15916b41548f04D731079F283135B276652F": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x0167008000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x6080604052600436106100a75760003560e01c8063715018a611610064578063715018a6146101b45780638456cb59146101c95780638da5cb5b146101de578063d8f4648f146101fc578063e1c7392a1461021c578063f2fde38b1461023157600080fd5b806328f713cc146100ac5780633659cfe6146101165780633f4ba83a146101385780634f1ef2861461014d57806352d1902d146101605780635c975abb14610183575b600080fd5b3480156100b857600080fd5b506100f96100c7366004610ce9565b67ffffffffffffffff91909116600090815260976020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012257600080fd5b50610136610131366004610d2a565b610251565b005b34801561014457600080fd5b50610136610339565b61013661015b366004610d5b565b6103b7565b34801561016c57600080fd5b50610175610487565b60405190815260200161010d565b34801561018f57600080fd5b506101a4606554610100900460ff1660021490565b604051901515815260200161010d565b3480156101c057600080fd5b5061013661053a565b3480156101d557600080fd5b5061013661054e565b3480156101ea57600080fd5b506033546001600160a01b03166100f9565b34801561020857600080fd5b50610136610217366004610e1d565b6105c7565b34801561022857600080fd5b50610136610654565b34801561023d57600080fd5b5061013661024c366004610d2a565b610764565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000000061630036102a25760405162461bcd60e51b815260040161029990610e59565b60405180910390fd5b7f00000000000000000000000001670080000000000000000000000000000000066001600160a01b03166102eb600080516020610fc9833981519152546001600160a01b031690565b6001600160a01b0316146103115760405162461bcd60e51b815260040161029990610ea5565b61031a816107da565b60408051600080825260208201909252610336918391906107e2565b50565b61034d606554610100900460ff1660021490565b61036a5760405163bae6e2a960e01b815260040160405180910390fd5b610372610952565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000000061630036103ff5760405162461bcd60e51b815260040161029990610e59565b7f00000000000000000000000001670080000000000000000000000000000000066001600160a01b0316610448600080516020610fc9833981519152546001600160a01b031690565b6001600160a01b03161461046e5760405162461bcd60e51b815260040161029990610ea5565b610477826107da565b610483828260016107e2565b5050565b6000306001600160a01b037f000000000000000000000000016700800000000000000000000000000000000616146105275760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610299565b50600080516020610fc983398151915290565b610542610952565b61054c60006109ac565b565b610562606554610100900460ff1660021490565b156105805760405163bae6e2a960e01b815260040160405180910390fd5b610588610952565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016103ad565b6105cf610952565b67ffffffffffffffff8316600081815260976020908152604080832086845282529182902080546001600160a01b038681166001600160a01b0319831681179093558451928352169181018290529092859290917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b600054610100900460ff16158080156106745750600054600160ff909116105b8061068e5750303b15801561068e575060005460ff166001145b6106f15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610299565b6000805460ff191660011790558015610714576000805461ff0019166101001790555b61071c6109fe565b8015610336576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b61076c610952565b6001600160a01b0381166107d15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610299565b610336816109ac565b610336610952565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561081a5761081583610a17565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610874575060408051601f3d908101601f1916820190925261087191810190610ef1565b60015b6108d75760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610299565b600080516020610fc983398151915281146109465760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610299565b50610815838383610ab3565b6033546001600160a01b0316331461054c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610299565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610a06610ade565b6065805461ffff1916610101179055565b6001600160a01b0381163b610a845760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610299565b600080516020610fc983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610abc83610b0d565b600082511180610ac95750805b1561081557610ad88383610b4d565b50505050565b600054610100900460ff16610b055760405162461bcd60e51b815260040161029990610f0a565b61054c610b79565b610b1681610a17565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060610b728383604051806060016040528060278152602001610fe960279139610ba9565b9392505050565b600054610100900460ff16610ba05760405162461bcd60e51b815260040161029990610f0a565b61054c336109ac565b6060600080856001600160a01b031685604051610bc69190610f79565b600060405180830381855af49150503d8060008114610c01576040519150601f19603f3d011682016040523d82523d6000602084013e610c06565b606091505b5091509150610c1786838387610c21565b9695505050505050565b60608315610c90578251600003610c89576001600160a01b0385163b610c895760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610299565b5081610c9a565b610c9a8383610ca2565b949350505050565b815115610cb25781518083602001fd5b8060405162461bcd60e51b81526004016102999190610f95565b803567ffffffffffffffff81168114610ce457600080fd5b919050565b60008060408385031215610cfc57600080fd5b610d0583610ccc565b946020939093013593505050565b80356001600160a01b0381168114610ce457600080fd5b600060208284031215610d3c57600080fd5b610b7282610d13565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610d6e57600080fd5b610d7783610d13565b9150602083013567ffffffffffffffff80821115610d9457600080fd5b818501915085601f830112610da857600080fd5b813581811115610dba57610dba610d45565b604051601f8201601f19908116603f01168101908382118183101715610de257610de2610d45565b81604052828152886020848701011115610dfb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600060608486031215610e3257600080fd5b610e3b84610ccc565b925060208401359150610e5060408501610d13565b90509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600060208284031215610f0357600080fd5b5051919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b83811015610f70578181015183820152602001610f58565b50506000910152565b60008251610f8b818460208701610f55565b9190910192915050565b6020815260008251806020840152610fb4816040850160208701610f55565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204e2030d9883d08dca7ecdc1d78b36ee54b3130abcb1c45646b02f76d950ff54a64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0xcffa903d987c324286ac7635484e4c4cfab2b3bddddb45773db47593d56d5616": "0x0000000000000000000000001670080000000000000000000000000000000001", + "0x69945f7fb90fd606de42db577551f6eb68877935d99314a2706f3cbe614d714d": "0x0000000000000000000000001670080000000000000000000000000000000002", + "0x0e20b25daa3a523d27c8749dd04006a44414b4569e0b5639cc8bc2cbc8d143ec": "0x0000000000000000000000001670080000000000000000000000000000000003", + "0xc8e904a2a894d2e5590835bec6cb78755de7e546a44a4bede5bccee5641e227e": "0x0000000000000000000000001670080000000000000000000000000000000004", + "0x72cf3566ee7eea8d37039862c9f5956b8622ca74729c83890cfd90fc8645bdcc": "0x0000000000000000000000001670080000000000000000000000000000000005", + "0xdcd7088979e9e1e0b5e55f2c5e67cc79f77b5ff5fc73719c45425ee4ef73911c": "0x0000000000000000000000000167008000000000000000000000000000010096", + "0xd8a967abc0370c9bc69725e8b0433ed844d6abb7e639863dbfb50f4eb3b0a7a6": "0x0000000000000000000000000167008000000000000000000000000000010097", + "0x4ebdc5a0aa6a37034598482e87dac4dbac06e9e750c7c9b4b0606b27f5196be3": "0x0000000000000000000000000167008000000000000000000000000000010098", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000006" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x6080604052600436106101855760003560e01c80635c975abb116100d15780638da5cb5b1161008a578063a86f9d9e11610064578063a86f9d9e146104a5578063d0496d6a146104c5578063eefbf17e1461050e578063f2fde38b1461054657600080fd5b80638da5cb5b146104285780638e3881a914610446578063a24f721b1461048557600080fd5b80635c975abb1461037d57806360ecbdfd1461039e578063625e5b7f146103be578063715018a6146103de578063783f8c93146103f35780638456cb591461041357600080fd5b80633c6cf4731161013e57806348c095391161011857806348c09539146102e75780634f1ef286146103155780634f5f97721461032857806352d1902d1461036857600080fd5b80633c6cf473146102755780633eb6b8cf146102b25780633f4ba83a146102d257600080fd5b8063013824081461019157806319ab453c146101b35780631a92e520146101d357806333bcd0cc146101f35780633659cfe61461021d5780633ab76e9f1461023d57600080fd5b3661018c57005b600080fd5b34801561019d57600080fd5b506101b16101ac3660046124f4565b610566565b005b3480156101bf57600080fd5b506101b16101ce3660046125af565b61089e565b3480156101df57600080fd5b506101b16101ee3660046124f4565b6109b6565b6102066102013660046125cc565b610d7a565b60405161021492919061275a565b60405180910390f35b34801561022957600080fd5b506101b16102383660046125af565b611062565b34801561024957600080fd5b5060975461025d906001600160a01b031681565b6040516001600160a01b039091168152602001610214565b34801561028157600080fd5b506102a5610290366004612773565b60fd6020526000908152604090205460ff1681565b60405161021491906127a2565b3480156102be57600080fd5b5061025d6102cd3660046127ef565b611141565b3480156102de57600080fd5b506101b1611158565b3480156102f357600080fd5b50610307610302366004612a1c565b6111d6565b604051908152602001610214565b6101b1610323366004612a50565b611206565b34801561033457600080fd5b50610358610343366004612773565b60fc6020526000908152604090205460ff1681565b6040519015158152602001610214565b34801561037457600080fd5b506103076112d2565b34801561038957600080fd5b50610358606554610100900460ff1660021490565b3480156103aa57600080fd5b506103586103b93660046125cc565b611385565b3480156103ca57600080fd5b506103586103d93660046124f4565b611458565b3480156103ea57600080fd5b506101b16114cc565b3480156103ff57600080fd5b5061035861040e3660046124f4565b6114e0565b34801561041f57600080fd5b506101b1611544565b34801561043457600080fd5b506033546001600160a01b031661025d565b34801561045257600080fd5b50610466610461366004612a9f565b6115bd565b6040805192151583526001600160a01b03909116602083015201610214565b34801561049157600080fd5b506101b16104a0366004612aba565b6115ea565b3480156104b157600080fd5b5061025d6104c0366004612b0b565b6117ad565b3480156104d157600080fd5b506104da6117ba565b60408051825181526020808401516001600160a01b031690820152918101516001600160401b031690820152606001610214565b34801561051a57600080fd5b5060fb5461052e906001600160801b031681565b6040516001600160801b039091168152602001610214565b34801561055257600080fd5b506101b16105613660046125af565b611843565b60655460ff166001190161058d5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff191660021790556105ae606554610100900460ff1660021490565b156105cc5760405163bae6e2a960e01b815260040160405180910390fd5b6105dc6080840160608501612a9f565b46816001600160401b03161461060557604051631c6c777560e31b815260040160405180910390fd5b610120840135158015610639575061062360a08501608086016125af565b6001600160a01b0316336001600160a01b031614155b15610657576040516372b6e1c360e11b815260040160405180910390fd5b600061066561030286612b30565b905060008082815260fd602052604090205460ff16600381111561068b5761068b61278c565b146106a957604051630cfafbf960e01b815260040160405180910390fd5b60006106c76d7369676e616c5f7365727669636560901b60006117ad565b90506106e581836106de60608a0160408b01612a9f565b88886118b9565b61070257604051635ea5ecc760e01b815260040160405180910390fd5b6000808061071660c08a0160a08b016125af565b6001600160a01b0316148061074257503061073760c08a0160a08b016125af565b6001600160a01b0316145b8061076d57506001600160a01b03831661076260c08a0160a08b016125af565b6001600160a01b0316145b1561078157506002905060e08701356107da565b600061079360a08a0160808b016125af565b6001600160a01b0316336001600160a01b0316146107b6578861012001356107b8565b5a5b90506107c589868361194e565b156107d357600292506107d8565b600192505b505b6107e5838584611af1565b6000806107f860e08b0160c08c016125af565b6001600160a01b03161461081b5761081660e08a0160c08b016125af565b61082b565b61082b60a08a0160808b016125af565b90506001600160a01b03811633036108645761085f61084f836101008c0135612b52565b6001600160a01b03831690611c25565b610886565b610873336101008b0135611c25565b6108866001600160a01b03821683611c25565b50506065805460ff1916600117905550505050505050565b600054610100900460ff16158080156108be5750600054600160ff909116105b806108d85750303b1580156108d8575060005460ff166001145b6109405760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015610963576000805461ff0019166101001790555b61096c82611c30565b80156109b2576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60655460ff16600119016109dd5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff191660021790556109fe606554610100900460ff1660021490565b15610a1c5760405163bae6e2a960e01b815260040160405180910390fd5b610a2c6060840160408501612a9f565b46816001600160401b031614610a5557604051631c6c777560e31b815260040160405180910390fd5b6000610a6361030286612b30565b600081815260fc602052604090205490915060ff1615610a9657604051638759835d60e01b815260040160405180910390fd5b6000610ab46d7369676e616c5f7365727669636560901b60006117ad565b604051631933b5e360e11b8152306004820152602481018490529091506001600160a01b038216906332676bc690604401602060405180830381865afa158015610b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b269190612b65565b610b435760405163ab035ad560e01b815260040160405180910390fd5b6000610b648260038518610b5d60808b0160608c01612a9f565b89896118b9565b905080610b845760405163f149234f60e01b815260040160405180910390fd5b600083815260fc60209081526040808320805460ff19166001179055610bcb91630187134360e71b91610bbc91908c01908c016125af565b6001600160a01b031690611c41565b90508015610d11576040518060600160405280858152602001306001600160a01b03168152602001896040016020810190610c069190612a9f565b6001600160401b03908116909152815160fe5560208083015160ff8054604095860151909416600160a01b026001600160e01b03199094166001600160a01b039092169190911792909217909155610c62918a01908a016125af565b6001600160a01b031663c389a1808960e001358a876040518463ffffffff1660e01b8152600401610c94929190612bf7565b6000604051808303818588803b158015610cad57600080fd5b505af1158015610cc1573d6000803e3d6000fd5b5050604080516060810182526000198082526001600160a01b0360208301526001600160401b03919092015260fe55505060ff80546001600160e01b0319166001600160e01b0317905550610d38565b610d3860e0890135610d2960a08b0160808c016125af565b6001600160a01b031690611c25565b60405184907fc6fbc1fa0145a394c9c414b2ae7bd634eb50dd888938bcd75692ae427b680fa290600090a250506065805460ff19166001179055505050505050565b604080516101808101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820181905261016082015260655460ff1660011901610e005760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055610e21606554610100900460ff1660021490565b15610e3f5760405163bae6e2a960e01b815260040160405180910390fd5b6000610e5160a08501608086016125af565b6001600160a01b031603610e7857604051633c4f94dd60e11b815260040160405180910390fd5b6000610e8d6104616080860160608701612a9f565b50905080610eae57604051631c6c777560e31b815260040160405180910390fd5b46610ebf6080860160608701612a9f565b6001600160401b031603610ee657604051631c6c777560e31b815260040160405180910390fd5b6000610efb61010086013560e0870135612b52565b9050348114610f1d57604051634ac2abdf60e11b815260040160405180910390fd5b610f2685612b30565b60fb80549194506001600160801b03909116906000610f4483612d46565b82546101009290920a6001600160801b03818102199093169183160217909155168352336020840152466001600160401b03166040840152610f85836111d6565b9350610fa36d7369676e616c5f7365727669636560901b60006117ad565b6001600160a01b03166366ca2bc0856040518263ffffffff1660e01b8152600401610fd091815260200190565b6020604051808303816000875af1158015610fef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110139190612d6c565b50837f3406baf0dfd13f7f0ce1d077c461a35b763927e1438d49749442de2eb42148ba846040516110449190612d85565b60405180910390a250506065805460ff191660011790559092909150565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000000011630036110aa5760405162461bcd60e51b815260040161093790612d98565b7f00000000000000000000000001670080000000000000000000000000000000016001600160a01b03166110f3600080516020612fcf833981519152546001600160a01b031690565b6001600160a01b0316146111195760405162461bcd60e51b815260040161093790612de4565b61112281611cd0565b6040805160008082526020820190925261113e91839190611cd8565b50565b600061114e848484611e43565b90505b9392505050565b61116c606554610100900460ff1660021490565b6111895760405163bae6e2a960e01b815260040160405180910390fd5b611191611f2c565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6000816040516020016111e99190612e30565b604051602081830303815290604052805190602001209050919050565b6001600160a01b037f000000000000000000000000016700800000000000000000000000000000000116300361124e5760405162461bcd60e51b815260040161093790612d98565b7f00000000000000000000000001670080000000000000000000000000000000016001600160a01b0316611297600080516020612fcf833981519152546001600160a01b031690565b6001600160a01b0316146112bd5760405162461bcd60e51b815260040161093790612de4565b6112c682611cd0565b6109b282826001611cd8565b6000306001600160a01b037f000000000000000000000000016700800000000000000000000000000000000116146113725760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610937565b50600080516020612fcf83398151915290565b6000466113986060840160408501612a9f565b6001600160401b0316146113ae57506000919050565b6113ca6d7369676e616c5f7365727669636560901b60006117ad565b6001600160a01b03166332676bc6306113e561030286612b30565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa15801561142e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114529190612b65565b92915050565b60004661146b6060860160408701612a9f565b6001600160401b03161461148157506000611151565b61114e6114a06d7369676e616c5f7365727669636560901b60006117ad565b6114b56114af61030288612b30565b60031890565b6114c56080880160608901612a9f565b86866118b9565b6114d4611f2c565b6114de6000611f86565b565b6000466114f36080860160608701612a9f565b6001600160401b03161461150957506000611151565b61114e6115286d7369676e616c5f7365727669636560901b60006117ad565b61153461030287612b30565b6114c56060880160408901612a9f565b611558606554610100900460ff1660021490565b156115765760405163bae6e2a960e01b815260040160405180910390fd5b61157e611f2c565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016111cc565b6000806115d5836562726964676560d01b6001611141565b6001600160a01b038116151594909350915050565b60655460ff16600119016116115760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055611632606554610100900460ff1660021490565b156116505760405163bae6e2a960e01b815260040160405180910390fd5b6116606080830160608401612a9f565b46816001600160401b03161461168957604051631c6c777560e31b815260040160405180910390fd5b61012083013515806116985750815b156116de576116ad60a08401608085016125af565b6001600160a01b0316336001600160a01b0316146116de576040516372b6e1c360e11b815260040160405180910390fd5b60006116ec61030285612b30565b90506001600082815260fd602052604090205460ff1660038111156117135761171361278c565b1461173157604051636e10a9f360e01b815260040160405180910390fd5b61173c84825a61194e565b1561176d576117686117606d7369676e616c5f7365727669636560901b60006117ad565b826002611af1565b61179a565b821561179a5761179a6117926d7369676e616c5f7365727669636560901b60006117ad565b826003611af1565b50506065805460ff191660011790555050565b6000611151468484611e43565b604080516060810182526000808252602082018190529181019190915260fe5460001914806117e9575060fe54155b1561180757604051635ceed17360e01b815260040160405180910390fd5b506040805160608101825260fe54815260ff546001600160a01b0381166020830152600160a01b90046001600160401b03169181019190915290565b61184b611f2c565b6001600160a01b0381166118b05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610937565b61113e81611f86565b6000856001600160a01b031663910af6ed856118e0876562726964676560d01b6000611141565b8887876040518663ffffffff1660e01b8152600401611903959493929190612e67565b602060405180830381865afa158015611920573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119449190612b65565b9695505050505050565b600081600003611971576040516308c2ad5360e01b815260040160405180910390fd5b3061198260408601602087016125af565b6001600160a01b03160361199857611998612ea9565b60405180606001604052808481526020018560200160208101906119bc91906125af565b6001600160a01b031681526020016119da6060870160408801612a9f565b6001600160401b03908116909152815160fe55602082015160ff8054604090940151909216600160a01b026001600160e01b03199093166001600160a01b0390911617919091179055611a3360c0850160a086016125af565b6001600160a01b03168260e0860135611a50610140880188612ebf565b604051611a5e929190612f05565b600060405180830381858888f193505050503d8060008114611a9c576040519150601f19603f3d011682016040523d82523d6000602084013e611aa1565b606091505b5050604080516060810182526000198082526001600160a01b0360208301526001600160401b03919092015260fe5560ff80546001600160e01b0319166001600160e01b03179055949350505050565b806003811115611b0357611b0361278c565b600083815260fd602052604090205460ff166003811115611b2657611b2661278c565b03611b3057505050565b600082815260fd60205260409020805482919060ff19166001836003811115611b5b57611b5b61278c565b0217905550817f6c51882bc2ed67617f77a1e9b9a25d2caad8448647ecb093b357a603b257563482604051611b9091906127a2565b60405180910390a26003816003811115611bac57611bac61278c565b03611c205760405163019b28af60e61b81526003831860048201526001600160a01b038416906366ca2bc0906024016020604051808303816000875af1158015611bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c1e9190612d6c565b505b505050565b6109b282825a611fd8565b611c38612076565b61113e8161208f565b60006001600160a01b0383163b611c5a57506000611452565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa925050508015611cc4575060408051601f3d908101601f19168201909252611cc191810190612b65565b60015b15611452579392505050565b61113e611f2c565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611d0b57611c20836120d8565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d65575060408051601f3d908101601f19168201909252611d6291810190612d6c565b60015b611dc85760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610937565b600080516020612fcf8339815191528114611e375760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610937565b50611c20838383612174565b6097546000906001600160a01b0316611e6f57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611ec7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eeb9190612f15565b905081158015611f0257506001600160a01b038116155b156111515783611f1184612199565b604051630d69e23960e41b8152600401610937929190612f32565b6033546001600160a01b031633146114de5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610937565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038316611fff57604051634c67134d60e11b815260040160405180910390fd5b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d806000811461204f576040519150601f19603f3d011682016040523d82523d6000602084013e612054565b606091505b5050905080611c1e57604051634c67134d60e11b815260040160405180910390fd5b61207e61222b565b6065805461ffff1916610101179055565b6001600160401b0346106120b65760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381163b6121455760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610937565b600080516020612fcf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61217d8361225a565b60008251118061218a5750805b15611c2057611c1e838361229a565b606060006121a6836122bf565b60010190506000816001600160401b038111156121c5576121c561282f565b6040519080825280601f01601f1916602001820160405280156121ef576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846121f957509392505050565b600054610100900460ff166122525760405162461bcd60e51b815260040161093790612f54565b6114de612397565b612263816120d8565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606111518383604051806060016040528060278152602001612fef602791396123c7565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106122fe5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061232a576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061234857662386f26fc10000830492506010015b6305f5e1008310612360576305f5e100830492506008015b612710831061237457612710830492506004015b60648310612386576064830492506002015b600a83106114525760010192915050565b600054610100900460ff166123be5760405162461bcd60e51b815260040161093790612f54565b6114de33611f86565b6060600080856001600160a01b0316856040516123e49190612f9f565b600060405180830381855af49150503d806000811461241f576040519150601f19603f3d011682016040523d82523d6000602084013e612424565b606091505b5091509150611944868383876060831561249f578251600003612498576001600160a01b0385163b6124985760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610937565b50816124a9565b6124a983836124b1565b949350505050565b8151156124c15781518083602001fd5b8060405162461bcd60e51b81526004016109379190612fbb565b600061018082840312156124ee57600080fd5b50919050565b60008060006040848603121561250957600080fd5b83356001600160401b038082111561252057600080fd5b61252c878388016124db565b9450602086013591508082111561254257600080fd5b818601915086601f83011261255657600080fd5b81358181111561256557600080fd5b87602082850101111561257757600080fd5b6020830194508093505050509250925092565b6001600160a01b038116811461113e57600080fd5b80356125aa8161258a565b919050565b6000602082840312156125c157600080fd5b81356111518161258a565b6000602082840312156125de57600080fd5b81356001600160401b038111156125f457600080fd5b6124a9848285016124db565b60005b8381101561261b578181015183820152602001612603565b50506000910152565b6000815180845261263c816020860160208601612600565b601f01601f19169290920160200192915050565b80516001600160801b031682526000610180602083015161267c60208601826001600160a01b03169052565b50604083015161269760408601826001600160401b03169052565b5060608301516126b260608601826001600160401b03169052565b5060808301516126cd60808601826001600160a01b03169052565b5060a08301516126e860a08601826001600160a01b03169052565b5060c083015161270360c08601826001600160a01b03169052565b5060e083015160e085015261010080840151818601525061012080840151818601525061014080840151828287015261273e83870182612624565b9250505061016080840151858303828701526119448382612624565b82815260406020820152600061114e6040830184612650565b60006020828403121561278557600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600483106127c457634e487b7160e01b600052602160045260246000fd5b91905290565b80356001600160401b03811681146125aa57600080fd5b801515811461113e57600080fd5b60008060006060848603121561280457600080fd5b61280d846127ca565b9250602084013591506040840135612824816127e1565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b03811182821017156128685761286861282f565b60405290565b80356001600160801b03811681146125aa57600080fd5b600082601f83011261289657600080fd5b81356001600160401b03808211156128b0576128b061282f565b604051601f8301601f19908116603f011681019082821181831017156128d8576128d861282f565b816040528381528660208588010111156128f157600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610180828403121561292457600080fd5b61292c612845565b90506129378261286e565b81526129456020830161259f565b6020820152612956604083016127ca565b6040820152612967606083016127ca565b60608201526129786080830161259f565b608082015261298960a0830161259f565b60a082015261299a60c0830161259f565b60c082015260e0828101359082015261010080830135908201526101208083013590820152610140808301356001600160401b03808211156129db57600080fd5b6129e786838701612885565b83850152610160925082850135915080821115612a0357600080fd5b50612a1085828601612885565b82840152505092915050565b600060208284031215612a2e57600080fd5b81356001600160401b03811115612a4457600080fd5b6124a984828501612911565b60008060408385031215612a6357600080fd5b8235612a6e8161258a565b915060208301356001600160401b03811115612a8957600080fd5b612a9585828601612885565b9150509250929050565b600060208284031215612ab157600080fd5b611151826127ca565b60008060408385031215612acd57600080fd5b82356001600160401b03811115612ae357600080fd5b612aef858286016124db565b9250506020830135612b00816127e1565b809150509250929050565b60008060408385031215612b1e57600080fd5b823591506020830135612b00816127e1565b60006114523683612911565b634e487b7160e01b600052601160045260246000fd5b8082018082111561145257611452612b3c565b600060208284031215612b7757600080fd5b8151611151816127e1565b6000808335601e19843603018112612b9957600080fd5b83016020810192503590506001600160401b03811115612bb857600080fd5b803603821315612bc757600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60408152612c1860408201612c0b8561286e565b6001600160801b03169052565b6000612c266020850161259f565b6001600160a01b03166060830152612c40604085016127ca565b6001600160401b03166080830152612c5a606085016127ca565b6001600160401b031660a0830152612c746080850161259f565b6001600160a01b031660c0830152612c8e60a0850161259f565b6001600160a01b031660e0830152612ca860c0850161259f565b610100612cbf818501836001600160a01b03169052565b610120915060e086013582850152610140818701358186015261016091508287013582860152612cf181880188612b82565b6101808781015293509050612d0b6101c086018483612bce565b925050612d1a81870187612b82565b858403603f19016101a08701529150612d34838383612bce565b93505050508260208301529392505050565b60006001600160801b03808316818103612d6257612d62612b3c565b6001019392505050565b600060208284031215612d7e57600080fd5b5051919050565b6020815260006111516020830184612650565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60408152600d60408201526c5441494b4f5f4d45535341474560981b60608201526080602082015260006111516080830184612650565b6001600160401b038616815260018060a01b0385166020820152836040820152608060608201526000612e9e608083018486612bce565b979650505050505050565b634e487b7160e01b600052600160045260246000fd5b6000808335601e19843603018112612ed657600080fd5b8301803591506001600160401b03821115612ef057600080fd5b602001915036819003821315612bc757600080fd5b8183823760009101908152919050565b600060208284031215612f2757600080fd5b81516111518161258a565b6001600160401b038316815260406020820152600061114e6040830184612624565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008251612fb1818460208701612600565b9190910192915050565b602081526000611151602083018461262456fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220e892cdceae8d4b60780b9127de196345c4092abe37dfdd4712cf041b1bee238f64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670080000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x033b2dcd9a1ae301c8000000" + }, + "0x0167008000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x6080604052600436106200014f5760003560e01c80635c975abb11620000b95780638da5cb5b11620000785780638da5cb5b14620003b85780639aa8605c14620003d8578063a86f9d9e1462000410578063c389a1801462000435578063caec3e4e146200044c578063f2fde38b146200048057600080fd5b80635c975abb14620002fa57806367090ccf146200031d578063715018a61462000362578063755fc20c146200037a5780638456cb5914620003a057600080fd5b80633659cfe611620001125780633659cfe614620002475780633ab76e9f146200026c5780633eb6b8cf146200028e5780633f4ba83a14620002b35780634f1ef28614620002cb57806352d1902d14620002e257600080fd5b806301ffc9a7146200015457806306fdde03146200019e5780630ecd8be914620001cb57806319ab453c1462000209578063240f6a5f1462000230575b600080fd5b3480156200016157600080fd5b506200018962000173366004620031e0565b6001600160e01b031916630187134360e71b1490565b60405190151581526020015b60405180910390f35b348015620001ab57600080fd5b506a195c98cc8c17dd985d5b1d60aa1b5b60405190815260200162000195565b348015620001d857600080fd5b50620001f0620001ea3660046200323b565b620004a5565b6040516001600160a01b03909116815260200162000195565b3480156200021657600080fd5b506200022e6200022836600462003292565b62000b92565b005b6200022e62000241366004620032b2565b62000cb2565b3480156200025457600080fd5b506200022e6200026636600462003292565b62000ead565b3480156200027957600080fd5b50609754620001f0906001600160a01b031681565b3480156200029b57600080fd5b50620001f0620002ad36600462003348565b62000f98565b348015620002c057600080fd5b506200022e62000fb1565b6200022e620002dc36600462003496565b62001033565b348015620002ef57600080fd5b50620001bc6200110b565b3480156200030757600080fd5b5062000189606554610100900460ff1660021490565b3480156200032a57600080fd5b50620001f06200033c36600462003500565b60fc6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200036f57600080fd5b506200022e620011c2565b620003916200038b36600462003528565b620011da565b604051620001959190620035ba565b348015620003ad57600080fd5b506200022e62001584565b348015620003c557600080fd5b506033546001600160a01b0316620001f0565b348015620003e557600080fd5b50620003fd620003f736600462003292565b62001602565b60405162000195959493929190620036c2565b3480156200041d57600080fd5b50620001f06200042f36600462003720565b6200176b565b6200022e6200044636600462003748565b62001783565b3480156200045957600080fd5b50620001896200046b36600462003292565b60fd6020526000908152604090205460ff1681565b3480156200048d57600080fd5b506200022e6200049f36600462003292565b620019e2565b60655460009060ff1660011901620004d05760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055620004f2606554610100900460ff1660021490565b15620005115760405163bae6e2a960e01b815260040160405180910390fd5b6200051b62001a5e565b6001600160a01b03821615806200055257506001600160a01b03828116600090815260fb6020526040902054600160401b90041615155b15620005715760405163dc63f98760e01b815260040160405180910390fd5b6001600160a01b038216600090815260fd602052604090205460ff1615620005ac576040516375c42fc160e01b815260040160405180910390fd5b6033546001600160a01b03166001600160a01b0316826001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000600573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006269190620037a2565b6001600160a01b0316146200064e5760405163c0507c1760e01b815260040160405180910390fd5b60fc6000620006616020860186620037c2565b6001600160401b0316815260200190815260200160002060008460200160208101906200068f919062003292565b6001600160a01b039081168252602082019290925260400160002054169050801562000a2a576001600160a01b03818116600090815260fb60209081526040808320815160a08101835281546001600160401b0381168252600160401b810490961693810193909352600160e01b90940460ff1690820152600183018054929391926060840191906200072290620037e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200075090620037e2565b8015620007a15780601f106200077557610100808354040283529160200191620007a1565b820191906000526020600020905b8154815290600101906020018083116200078357829003601f168201915b50505050508152602001600282018054620007bc90620037e2565b80601f0160208091040260200160405190810160405280929190818152602001828054620007ea90620037e2565b80156200083b5780601f106200080f576101008083540402835291602001916200083b565b820191906000526020600020905b8154815290600101906020018083116200081d57829003601f168201915b50505050508152505090508360400160208101906200085b919062003835565b60ff16816040015160ff16141580620008a557506200087e606085018562003855565b6040516200088e929190620038a5565b604051809103902081606001518051906020012014155b80620008e25750620008bb608085018562003855565b604051620008cb929190620038a5565b604051809103902081608001518051906020012014155b156200090157604051632f9d1d7b60e11b815260040160405180910390fd5b6001600160a01b038216600090815260fb6020526040812080546001600160e81b031916815590620009376001830182620030dc565b62000947600283016000620030dc565b50506001600160a01b03828116600081815260fd6020526040808220805460ff191660011790555163b8f2e0c560e01b8152928616600484015260248301529063b8f2e0c590604401600060405180830381600087803b158015620009ab57600080fd5b505af1158015620009c0573d6000803e3d6000fd5b505060405163b8f2e0c560e01b81526001600160a01b038581166004830152600160248301528616925063b8f2e0c59150604401600060405180830381600087803b15801562000a0f57600080fd5b505af115801562000a24573d6000803e3d6000fd5b50505050505b6001600160a01b038216600090815260fb60205260409020839062000a508282620039d4565b5082905060fc600062000a676020870187620037c2565b6001600160401b03168152602001908152602001600020600085602001602081019062000a95919062003292565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555082602001602081019062000aee919062003292565b6001600160a01b031662000b066020850185620037c2565b6001600160401b03167f031d68e1805917560c34a5f55a7dd91bef98f911190ed02cdbb53caedae6c39d838562000b41606089018962003855565b62000b5060808b018b62003855565b62000b6260608d0160408e0162003835565b60405162000b77979695949392919062003ad0565b60405180910390a36065805460ff1916600117905592915050565b600054610100900460ff161580801562000bb35750600054600160ff909116105b8062000bcf5750303b15801562000bcf575060005460ff166001145b62000c385760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff19166001179055801562000c5c576000805461ff0019166101001790555b62000c678262001aba565b801562000cae576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60655460ff166001190162000cda5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905562000cfc606554610100900460ff1660021490565b1562000d1b5760405163bae6e2a960e01b815260040160405180910390fd5b600062000d2762001acf565b905060006001600160a01b038416158062000d4a57506001600160a01b03841630145b62000d56578362000d58565b845b905060004662000d6c6020890189620037c2565b6001600160401b03160362000dab5762000d8d604088016020890162003292565b905062000da56001600160a01b038216838662001bf9565b62000e1f565b62000db68762001c63565b6040516340c10f1960e01b81526001600160a01b03848116600483015260248201879052919250908216906340c10f1990604401600060405180830381600087803b15801562000e0557600080fd5b505af115801562000e1a573d6000803e3d6000fd5b505050505b62000e346001600160a01b0383163462001cdd565b825160408085015181516001600160401b0390911681526001600160a01b0384811660208301529181018790528188169291891691907fc8d296a7a3ffa2fb1e316d8c6cbaf5f7ea5e12f11abd76e61f47d2dfa12bb4679060600160405180910390a450506065805460ff191660011790555050505050565b6001600160a01b037f000000000000000000000000016700800000000000000000000000000000000216300362000ef85760405162461bcd60e51b815260040162000c2f9062003b2c565b7f00000000000000000000000001670080000000000000000000000000000000026001600160a01b031662000f436000805160206200472b833981519152546001600160a01b031690565b6001600160a01b03161462000f6c5760405162461bcd60e51b815260040162000c2f9062003b78565b62000f778162001cea565b6040805160008082526020820190925262000f959183919062001cf4565b50565b600062000fa784848462001e6c565b90505b9392505050565b62000fc6606554610100900460ff1660021490565b62000fe45760405163bae6e2a960e01b815260040160405180910390fd5b62000fee62001a5e565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000000021630036200107e5760405162461bcd60e51b815260040162000c2f9062003b2c565b7f00000000000000000000000001670080000000000000000000000000000000026001600160a01b0316620010c96000805160206200472b833981519152546001600160a01b031690565b6001600160a01b031614620010f25760405162461bcd60e51b815260040162000c2f9062003b78565b620010fd8262001cea565b62000cae8282600162001cf4565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000000021614620011ad5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000c2f565b506000805160206200472b8339815191525b90565b620011cc62001a5e565b620011d8600062001f5f565b565b620011e46200311b565b60655460ff16600119016200120c5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff191660021790556200122e606554610100900460ff1660021490565b156200124d5760405163bae6e2a960e01b815260040160405180910390fd5b81606001356000036200127357604051634299323b60e11b815260040160405180910390fd5b600062001287606084016040850162003292565b6001600160a01b031603620012af576040516303f8a7d360e01b815260040160405180910390fd5b60fd6000620012c5606085016040860162003292565b6001600160a01b0316815260208101919091526040016000205460ff161562001301576040516375c42fc160e01b815260040160405180910390fd5b60006200130d6200311b565b620013413362001324606087016040880162003292565b62001336604088016020890162003292565b876060013562001fb1565b61014083019190915291506200135b6020850185620037c2565b6001600160401b031660608201523360808201526200139a620013826020860186620037c2565b6a195c98cc8c17dd985d5b1d60aa1b5b600062000f98565b6001600160a01b031660a0808301919091526080850135610120830152620013c6908501353462003bc4565b60e08083019190915260a0850135610100830152620013eb90850160c0860162003292565b6001600160a01b031660c08201526200140860e085018562003855565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250610160860194909452506200145b91506562726964676560d01b9050826200176b565b6001600160a01b03166333bcd0cc34846040518363ffffffff1660e01b8152600401620014899190620035ba565b60006040518083038185885af1158015620014a8573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052620014d3919081019062003c57565b94509050620014e9604086016020870162003292565b60808501516001600160a01b039182169116827fd2934b7e737b6465ee52ffdc702435c483343c4354cafc7f296e05e890358e486200152c60208a018a620037c2565b6200153e60608b0160408c0162003292565b604080516001600160401b0390931683526001600160a01b039091166020830152810188905260600160405180910390a450506065805460ff1916600117905550919050565b62001599606554610100900460ff1660021490565b15620015b85760405163bae6e2a960e01b815260040160405180910390fd5b620015c262001a5e565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162001029565b60fb60205260009081526040902080546001820180546001600160401b03831693600160401b84046001600160a01b031693600160e01b900460ff169290916200164c90620037e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200167a90620037e2565b8015620016cb5780601f106200169f57610100808354040283529160200191620016cb565b820191906000526020600020905b815481529060010190602001808311620016ad57829003601f168201915b505050505090806002018054620016e290620037e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200171090620037e2565b8015620017615780601f10620017355761010080835404028352916020019162001761565b820191906000526020600020905b8154815290600101906020018083116200174357829003601f168201915b5050505050905085565b60006200177a46848462001e6c565b90505b92915050565b60655460ff1660011901620017ab5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055620017cd606554610100900460ff1660021490565b15620017ec5760405163bae6e2a960e01b815260040160405180910390fd5b620017f6620024e4565b506000806200180a61014085018562003855565b6200181a91600490829062003da8565b81019062001829919062003e04565b919450909250506001600160a01b03831690506200185a576040516303f8a7d360e01b815260040160405180910390fd5b80156200193a576001600160a01b03828116600090815260fb6020526040902054600160401b9004161562001912576001600160a01b0382166340c10f19620018aa60a087016080880162003292565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101849052604401600060405180830381600087803b158015620018f357600080fd5b505af115801562001908573d6000803e3d6000fd5b505050506200193a565b6200193a6200192860a086016080870162003292565b6001600160a01b038416908362001bf9565b6200196560e08501356200195560a087016080880162003292565b6001600160a01b03169062001cdd565b6200197760a085016080860162003292565b6001600160a01b0316837f75c5fedbd5fff6123ad9b70827e9742ea1eee996583d6e14249f1429fc4fd9938484604051620019c79291906001600160a01b03929092168252602082015260400190565b60405180910390a350506065805460ff191660011790555050565b620019ec62001a5e565b6001600160a01b03811662001a535760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000c2f565b62000f958162001f5f565b6033546001600160a01b03163314620011d85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000c2f565b62001ac4620025df565b62000f9581620025fa565b604080516060810182526000808252602082018190529181019190915262001b026562726964676560d01b60006200176b565b6001600160a01b0316336001600160a01b03161462001b3457604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562001b73573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b99919062003efa565b9050600062001bbc8260400151620013926a195c98cc8c17dd985d5b1d60aa1b90565b9050806001600160a01b031682602001516001600160a01b03161462001bf557604051632583296b60e01b815260040160405180910390fd5b5090565b6040516001600160a01b03831660248201526044810182905262001c5e90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915262002644565b505050565b600060fc8162001c776020850185620037c2565b6001600160401b03168152602001908152602001600020600083602001602081019062001ca5919062003292565b6001600160a01b0390811682526020820192909252604001600020541690508062001cd85762001cd5826200271d565b90505b919050565b62000cae82825a6200296a565b62000f9562001a5e565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001d2a5762001c5e8362002a12565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001d87575060408051601f3d908101601f1916820190925262001d849181019062003f6a565b60015b62001dec5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000c2f565b6000805160206200472b833981519152811462001e5e5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000c2f565b5062001c5e83838362002ab1565b6097546000906001600160a01b031662001e9957604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001ef2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f189190620037a2565b90508115801562001f3057506001600160a01b038116155b1562000faa578362001f428462002adc565b604051630d69e23960e41b815260040162000c2f92919062003f84565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040805160a08101825260008082526020820181905291810182905260608181018190526080820181905291906001600160a01b03868116600090815260fb6020526040902054600160401b9004161562002207576001600160a01b03868116600090815260fb6020908152604091829020825160a08101845281546001600160401b0381168252600160401b810490951692810192909252600160e01b90930460ff16918101919091526001820180549192916060840191906200207690620037e2565b80601f0160208091040260200160405190810160405280929190818152602001828054620020a490620037e2565b8015620020f55780601f10620020c957610100808354040283529160200191620020f5565b820191906000526020600020905b815481529060010190602001808311620020d757829003601f168201915b505050505081526020016002820180546200211090620037e2565b80601f01602080910402602001604051908101604052809291908181526020018280546200213e90620037e2565b80156200218f5780601f1062002163576101008083540402835291602001916200218f565b820191906000526020600020905b8154815290600101906020018083116200217157829003601f168201915b505050919092525050604051632770a7eb60e21b815233600482015260248101879052919250506001600160a01b03871690639dc29fac90604401600060405180830381600087803b158015620021e557600080fd5b505af1158015620021fa573d6000803e3d6000fd5b5050505083915062002483565b60008690506040518060a00160405280466001600160401b03168152602001886001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002274573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200229a919062003fa8565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620022e1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200230b919081019062003fc8565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156200234f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262002379919081019062003fc8565b90526040516370a0823160e01b81523060048201529092506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015620023c6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023ec919062003f6a565b9050620024056001600160a01b03831633308962002b75565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa1580156200244c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002472919062003f6a565b6200247e919062003bc4565b935050505b306001600160a01b031663240f6a5f82898886604051602401620024ab949392919062004000565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505092505094509492505050565b6040805160608101825260008082526020820181905291810191909152620025176562726964676560d01b60006200176b565b6001600160a01b0316336001600160a01b0316146200254957604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562002588573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025ae919062003efa565b60208101519091506001600160a01b03163314620011bf57604051632583296b60e01b815260040160405180910390fd5b620025e962002baf565b6065805461ffff1916610101179055565b6001600160401b034610620026225760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b60006200269b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662002be39092919063ffffffff16565b80519091501562001c5e5780806020019051810190620026bc9190620040a6565b62001c5e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000c2f565b6097546000908190636c0db62b60e01b906001600160a01b031662002749604086016020870162003292565b620027586020870187620037c2565b6200276a606088016040890162003835565b62002779606089018962003855565b6200278860808b018b62003855565b604051602001620027a1989796959493929190620040c6565b60408051601f1981840301815290829052620027c1929160200162004131565b604051602081830303815290604052905062002806620027f36c0627269646765645f657263323609c1b60006200176b565b6033546001600160a01b03168362002bf4565b6001600160a01b038116600090815260fb6020526040902090925083906200282f8282620039d4565b5082905060fc6000620028466020870187620037c2565b6001600160401b03168152602001908152602001600020600085602001602081019062002874919062003292565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316836020016020810190620028d7919062003292565b6001600160a01b0316620028ef6020860186620037c2565b6001600160401b03167fb6b427556e8cb0ebf9175da4bc48c64c4f56e44cfaf8c3ab5ebf8e2ea130907962002928606088018862003855565b6200293760808a018a62003855565b6200294960608c0160408d0162003835565b6040516200295c95949392919062004164565b60405180910390a450919050565b6001600160a01b0383166200299257604051634c67134d60e11b815260040160405180910390fd5b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d8060008114620029e4576040519150601f19603f3d011682016040523d82523d6000602084013e620029e9565b606091505b505090508062002a0c57604051634c67134d60e11b815260040160405180910390fd5b50505050565b6001600160a01b0381163b62002a815760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000c2f565b6000805160206200472b83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b62002abc8362002d54565b60008251118062002aca5750805b1562001c5e5762002a0c838362002d96565b6060600062002aeb8362002dbe565b60010190506000816001600160401b0381111562002b0d5762002b0d6200338f565b6040519080825280601f01601f19166020018201604052801562002b38576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508462002b4257509392505050565b6040516001600160a01b038085166024830152831660448201526064810182905262002a0c9085906323b872dd60e01b9060840162001c26565b600054610100900460ff1662002bd95760405162461bcd60e51b815260040162000c2f90620041a5565b620011d862002e9d565b606062000fa7848460008562002ed2565b60006001600160a01b03841662002c1e576040516305d1c47b60e41b815260040160405180910390fd5b838260405162002c2e90620031bb565b62002c3b929190620041f0565b604051809103906000f08015801562002c58573d6000803e3d6000fd5b5090506001600160a01b0383161580159062002cea5750806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002cae573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002cd49190620037a2565b6001600160a01b0316836001600160a01b031614155b1562000faa5760405163f2fde38b60e01b81526001600160a01b03848116600483015282169063f2fde38b90602401600060405180830381600087803b15801562002d3457600080fd5b505af115801562002d49573d6000803e3d6000fd5b505050509392505050565b62002d5f8162002a12565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606200177a83836040518060600160405280602781526020016200474b6027913962002fb7565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831062002dfe5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831062002e2b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831062002e4a57662386f26fc10000830492506010015b6305f5e100831062002e63576305f5e100830492506008015b612710831062002e7857612710830492506004015b6064831062002e8b576064830492506002015b600a83106200177d5760010192915050565b600054610100900460ff1662002ec75760405162461bcd60e51b815260040162000c2f90620041a5565b620011d83362001f5f565b60608247101562002f355760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000c2f565b600080866001600160a01b0316858760405162002f53919062004216565b60006040518083038185875af1925050503d806000811462002f92576040519150601f19603f3d011682016040523d82523d6000602084013e62002f97565b606091505b509150915062002faa8783838762003035565b925050505b949350505050565b6060600080856001600160a01b03168560405162002fd6919062004216565b600060405180830381855af49150503d806000811462003013576040519150601f19603f3d011682016040523d82523d6000602084013e62003018565b606091505b50915091506200302b8683838762003035565b9695505050505050565b60608315620030a9578251600003620030a1576001600160a01b0385163b620030a15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000c2f565b508162002faf565b62002faf8383815115620030c05781518083602001fd5b8060405162461bcd60e51b815260040162000c2f919062004234565b508054620030ea90620037e2565b6000825580601f10620030fb575050565b601f01602090049060005260206000209081019062000f959190620031c9565b60405180610180016040528060006001600160801b0316815260200160006001600160a01b0316815260200160006001600160401b0316815260200160006001600160401b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160608152602001606081525090565b6104e1806200424a83390190565b5b8082111562001bf55760008155600101620031ca565b600060208284031215620031f357600080fd5b81356001600160e01b03198116811462000faa57600080fd5b600060a082840312156200321f57600080fd5b50919050565b6001600160a01b038116811462000f9557600080fd5b600080604083850312156200324f57600080fd5b82356001600160401b038111156200326657600080fd5b62003274858286016200320c565b9250506020830135620032878162003225565b809150509250929050565b600060208284031215620032a557600080fd5b813562000faa8162003225565b60008060008060808587031215620032c957600080fd5b84356001600160401b03811115620032e057600080fd5b620032ee878288016200320c565b9450506020850135620033018162003225565b92506040850135620033138162003225565b9396929550929360600135925050565b6001600160401b038116811462000f9557600080fd5b801515811462000f9557600080fd5b6000806000606084860312156200335e57600080fd5b83356200336b8162003323565b9250602084013591506040840135620033848162003339565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b0381118282101715620033cb57620033cb6200338f565b60405290565b60405160a081016001600160401b0381118282101715620033cb57620033cb6200338f565b604051601f8201601f191681016001600160401b03811182821017156200342157620034216200338f565b604052919050565b60006001600160401b038211156200344557620034456200338f565b50601f01601f191660200190565b60006200346a620034648462003429565b620033f6565b90508281528383830111156200347f57600080fd5b828260208301376000602084830101529392505050565b60008060408385031215620034aa57600080fd5b8235620034b78162003225565b915060208301356001600160401b03811115620034d357600080fd5b8301601f81018513620034e557600080fd5b620034f68582356020840162003453565b9150509250929050565b600080604083850312156200351457600080fd5b823591506020830135620032878162003225565b6000602082840312156200353b57600080fd5b81356001600160401b038111156200355257600080fd5b8201610100818503121562000faa57600080fd5b60005b838110156200358357818101518382015260200162003569565b50506000910152565b60008151808452620035a681602086016020860162003566565b601f01601f19169290920160200192915050565b60208152620035d56020820183516001600160801b03169052565b60006020830151620035f260408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610180610160808501829052620036a46101a08601846200358c565b90860151858203601f1901838701529092506200302b83826200358c565b6001600160401b03861681526001600160a01b038516602082015260ff8416604082015260a06060820181905260009062003700908301856200358c565b82810360808401526200371481856200358c565b98975050505050505050565b600080604083850312156200373457600080fd5b823591506020830135620032878162003339565b600080604083850312156200375c57600080fd5b82356001600160401b038111156200377357600080fd5b830161018081860312156200378757600080fd5b946020939093013593505050565b805162001cd88162003225565b600060208284031215620037b557600080fd5b815162000faa8162003225565b600060208284031215620037d557600080fd5b813562000faa8162003323565b600181811c90821680620037f757607f821691505b6020821081036200321f57634e487b7160e01b600052602260045260246000fd5b60ff8116811462000f9557600080fd5b803562001cd88162003818565b6000602082840312156200384857600080fd5b813562000faa8162003818565b6000808335601e198436030181126200386d57600080fd5b8301803591506001600160401b038211156200388857600080fd5b6020019150368190038213156200389e57600080fd5b9250929050565b8183823760009101908152919050565b601f82111562001c5e57600081815260208120601f850160051c81016020861015620038de5750805b601f850160051c820191505b81811015620038ff57828155600101620038ea565b505050505050565b6001600160401b038311156200392157620039216200338f565b6200393983620039328354620037e2565b83620038b5565b6000601f841160018114620039705760008515620039575750838201355b600019600387901b1c1916600186901b178355620039cd565b600083815260209020601f19861690835b82811015620039a3578685013582556020948501946001909201910162003981565b5086821015620039c15760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8135620039e18162003323565b6001600160401b03811690508154816001600160401b03198216178355602084013562003a0e8162003225565b68010000000000000000600160e01b03604091821b166001600160e01b031983168417811785559085013562003a448162003818565b6001600160e81b0319929092169092179190911760e09190911b60ff60e01b1617815562003a76606083018362003855565b62003a8681836001860162003907565b505062003a97608083018362003855565b62002a0c81836002860162003907565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0388811682528716602082015260a06040820181905260009062003aff908301878962003aa7565b828103606084015262003b1481868862003aa7565b91505060ff8316608083015298975050505050505050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b818103818111156200177d57634e487b7160e01b600052601160045260246000fd5b80516001600160801b038116811462001cd857600080fd5b805162001cd88162003323565b600082601f83011262003c1d57600080fd5b815162003c2e620034648262003429565b81815284602083860101111562003c4457600080fd5b62002faf82602083016020870162003566565b6000806040838503121562003c6b57600080fd5b8251915060208301516001600160401b038082111562003c8a57600080fd5b90840190610180828703121562003ca057600080fd5b62003caa620033a5565b62003cb58362003be6565b815262003cc56020840162003795565b602082015262003cd86040840162003bfe565b604082015262003ceb6060840162003bfe565b606082015262003cfe6080840162003795565b608082015262003d1160a0840162003795565b60a082015262003d2460c0840162003795565b60c082015260e0838101519082015261010080840151908201526101208084015190820152610140808401518381111562003d5e57600080fd5b62003d6c8982870162003c0b565b828401525050610160808401518381111562003d8757600080fd5b62003d958982870162003c0b565b8284015250508093505050509250929050565b6000808585111562003db957600080fd5b8386111562003dc757600080fd5b5050820193919092039150565b600082601f83011262003de657600080fd5b6200177a8383356020850162003453565b803562001cd88162003225565b6000806000806080858703121562003e1b57600080fd5b84356001600160401b038082111562003e3357600080fd5b9086019060a0828903121562003e4857600080fd5b62003e52620033d1565b823562003e5f8162003323565b8152602083013562003e718162003225565b602082015262003e846040840162003828565b604082015260608301358281111562003e9c57600080fd5b62003eaa8a82860162003dd4565b60608301525060808301358281111562003ec357600080fd5b62003ed18a82860162003dd4565b608083015250955062003eea9150506020860162003df7565b9250620033136040860162003df7565b60006060828403121562003f0d57600080fd5b604051606081018181106001600160401b038211171562003f325762003f326200338f565b60405282518152602083015162003f498162003225565b6020820152604083015162003f5e8162003323565b60408201529392505050565b60006020828403121562003f7d57600080fd5b5051919050565b6001600160401b038316815260406020820152600062000fa760408301846200358c565b60006020828403121562003fbb57600080fd5b815162000faa8162003818565b60006020828403121562003fdb57600080fd5b81516001600160401b0381111562003ff257600080fd5b62002faf8482850162003c0b565b608081526001600160401b03855116608082015260018060a01b0360208601511660a082015260ff60408601511660c08201526000606086015160a060e0840152620040516101208401826200358c565b90506080870151607f19848303016101008501526200407182826200358c565b925050506200408b60208301866001600160a01b03169052565b6001600160a01b039390931660408201526060015292915050565b600060208284031215620040b957600080fd5b815162000faa8162003339565b6001600160a01b038981168252881660208201526001600160401b038716604082015260ff8616606082015260c0608082018190526000906200410d908301868862003aa7565b82810360a08401526200412281858762003aa7565b9b9a5050505050505050505050565b6001600160e01b03198316815281516000906200415681600485016020870162003566565b919091016004019392505050565b6060815260006200417a60608301878962003aa7565b82810360208401526200418f81868862003aa7565b91505060ff831660408301529695505050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b038316815260406020820181905260009062000fa7908301846200358c565b600082516200422a81846020870162003566565b9190910192915050565b6020815260006200177a60208301846200358c56fe60806040526040516104e13803806104e1833981016040819052610022916102de565b61002e82826000610035565b50506103fb565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ba60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019d91906103ac565b600060405180830381855af49150503d80600081146101d8576040519150601f19603f3d011682016040523d82523d6000602084013e6101dd565b606091505b5090925090506101ef868383876101f9565b9695505050505050565b60608315610268578251600003610261576001600160a01b0385163b6102615760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610136565b5081610272565b610272838361027a565b949350505050565b81511561028a5781518083602001fd5b8060405162461bcd60e51b815260040161013691906103c8565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102d55781810151838201526020016102bd565b50506000910152565b600080604083850312156102f157600080fd5b82516001600160a01b038116811461030857600080fd5b60208401519092506001600160401b038082111561032557600080fd5b818501915085601f83011261033957600080fd5b81518181111561034b5761034b6102a4565b604051601f8201601f19908116603f01168101908382118183101715610373576103736102a4565b8160405282815288602084870101111561038c57600080fd5b61039d8360208301602088016102ba565b80955050505050509250929050565b600082516103be8184602087016102ba565b9190910192915050565b60208152600082518060208401526103e78160408501602087016102ba565b601f01601f19169190910160400192915050565b60b1806104096000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122047c4452ec207e12ab2ede7e4584377b6d10b42be2bc68e538c3afb63891c0e1d64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670080000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x608060405260043610620001675760003560e01c806352d1902d11620000c55780638456cb5911620000785780638456cb59146200042f5780638da5cb5b14620004475780639aa8605c1462000467578063a86f9d9e146200049e578063c389a18014620004c3578063f2fde38b14620004da57600080fd5b806352d1902d146200036357806359f4a907146200037b5780635c975abb1462000398578063634da63a14620003bb57806367090ccf14620003d2578063715018a6146200041757600080fd5b80633659cfe6116200011e5780633659cfe614620002895780633ab76e9f14620002ae5780633eb6b8cf14620002e95780633f4ba83a146200030e57806348b2772e14620003265780634f1ef286146200034c57600080fd5b806301ffc9a7146200016c57806306fdde0314620001b6578063150b7a0214620001e457806319ab453c146200022e5780632ca069a51462000255578063300536b51462000272575b600080fd5b3480156200017957600080fd5b50620001a16200018b36600462002c5f565b6001600160e01b031916630187134360e71b1490565b60405190151581526020015b60405180910390f35b348015620001c357600080fd5b506b195c98cdcc8c57dd985d5b1d60a21b5b604051908152602001620001ad565b348015620001f157600080fd5b50620002146200020336600462002ca1565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001620001ad565b3480156200023b57600080fd5b50620002536200024d36600462002d48565b620004ff565b005b3480156200026257600080fd5b5062000214636cdb3d1360e11b81565b620002536200028336600462002e65565b6200061f565b3480156200029657600080fd5b5062000253620002a836600462002d48565b6200091e565b348015620002bb57600080fd5b50609754620002d0906001600160a01b031681565b6040516001600160a01b039091168152602001620001ad565b348015620002f657600080fd5b50620002d06200030836600462002f28565b62000a09565b3480156200031b57600080fd5b506200025362000a22565b6200033d6200033736600462002f6f565b62000aa4565b604051620001ad919062003001565b620002536200035d36600462003176565b62000f57565b3480156200037057600080fd5b50620001d56200102f565b3480156200038857600080fd5b50620002146380ac58cd60e01b81565b348015620003a557600080fd5b50620001a1606554610100900460ff1660021490565b348015620003c857600080fd5b50620001d5600a81565b348015620003df57600080fd5b50620002d0620003f1366004620031e0565b60fc6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200042457600080fd5b5062000253620010e6565b3480156200043c57600080fd5b5062000253620010fe565b3480156200045457600080fd5b506033546001600160a01b0316620002d0565b3480156200047457600080fd5b506200048c6200048636600462002d48565b6200117c565b604051620001ad949392919062003213565b348015620004ab57600080fd5b50620002d0620004bd3660046200325c565b620012db565b62000253620004d436600462003284565b620012f3565b348015620004e757600080fd5b5062000253620004f936600462002d48565b620016e5565b600054610100900460ff1615808015620005205750600054600160ff909116105b806200053c5750303b1580156200053c575060005460ff166001145b620005a55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620005c9576000805461ff0019166101001790555b620005d48262001761565b80156200061b576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60655460ff1660011901620006475760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905562000669606554610100900460ff1660021490565b15620006885760405163bae6e2a960e01b815260040160405180910390fd5b60006200069462001776565b905060006001600160a01b0384161580620006b757506001600160a01b03841630145b620006c35783620006c5565b845b9050600046620006d96020890189620032d1565b6001600160401b031603620007b657620006fa604088016020890162002d48565b905060005b8451811015620007af57816001600160a01b03166342842e0e30858885815181106200072f576200072f620032f1565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b1580156200078a57600080fd5b505af11580156200079f573d6000803e3d6000fd5b50505050806001019050620006ff565b5062000871565b620007c187620018a1565b905060005b84518110156200086f57816001600160a01b03166340c10f1984878481518110620007f557620007f5620032f1565b60200260200101516040518363ffffffff1660e01b81526004016200082f9291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b1580156200084a57600080fd5b505af11580156200085f573d6000803e3d6000fd5b50505050806001019050620007c6565b505b620008866001600160a01b0383163462001925565b825160408401516001600160a01b0380881692908916917f8a4d138c7a19e12f6cdedfca02085820b0b1f5a9655c7a8b784f1d534347f2479085896000604051908082528060200260200182016040528015620008ed578160200160208202803683370190505b5060405162000900949392919062003344565b60405180910390a450506065805460ff191660011790555050505050565b6001600160a01b037f0000000000000000000000000167008000000000000000000000000000000003163003620009695760405162461bcd60e51b81526004016200059c906200338d565b7f00000000000000000000000001670080000000000000000000000000000000036001600160a01b0316620009b460008051602062004200833981519152546001600160a01b031690565b6001600160a01b031614620009dd5760405162461bcd60e51b81526004016200059c90620033d9565b620009e88162001932565b6040805160008082526020820190925262000a06918391906200193c565b50565b600062000a1884848462001ab9565b90505b9392505050565b62000a37606554610100900460ff1660021490565b62000a555760405163bae6e2a960e01b815260040160405180910390fd5b62000a5f62001bac565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b62000aae62002bb1565b60655460ff166001190162000ad65760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905562000af8606554610100900460ff1660021490565b1562000b175760405163bae6e2a960e01b815260040160405180910390fd5b8162000b27608082018262003425565b905062000b38606083018362003425565b90501462000b595760405163196e8a4160e31b815260040160405180910390fd5b600a62000b6a606083018362003425565b9050111562000b8c5760405163e4a4c1c760e01b815260040160405180910390fd5b600062000ba0606083016040840162002d48565b6001600160a01b03160362000bc8576040516303f8a7d360e01b815260040160405180910390fd5b60005b62000bda606085018562003425565b905081101562000c415762000bf3608085018562003425565b8281811062000c065762000c06620032f1565b9050602002013560001462000c2e57604051634299323b60e11b815260040160405180910390fd5b62000c39816200348e565b905062000bcb565b5062000c706380ac58cd60e01b62000c60606086016040870162002d48565b6001600160a01b03169062001c08565b62000c8e57604051633ee915f560e11b815260040160405180910390fd5b600062000c9f608085018562003425565b80806020026020016040519081016040528093929190818152602001838360200280828437600092018290525093945062000ce592505050606086016040870162002d48565b9050600062000cf8606087018762003425565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092935062000d38925062002bb1915050565b62000d476020880188620032d1565b6001600160401b0316606082015262000d61338862001c9d565b610140820152336080820152606081015162000d90906b195c98cdcc8c57dd985d5b1d60a21b5b600062000a09565b6001600160a01b031660a08083019190915287013561012082015262000dbb60c088013534620034aa565b60e08083019190915260c08801356101008084019190915262000de49190890190890162002d48565b6001600160a01b031660c082015262000e02610100880188620034c0565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101608601949094525062000e5591506562726964676560d01b905082620012db565b6001600160a01b03166333bcd0cc34846040518363ffffffff1660e01b815260040162000e83919062003001565b60006040518083038185885af115801562000ea2573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405262000ecd919081019062003587565b9750905062000ee36040890160208a0162002d48565b6001600160a01b031687608001516001600160a01b0316827f329b657c35d4e2dfede6ef5132869accb1f8542912a40f9a854b4a917ffae2e98a6060015188888b60405162000f36949392919062003344565b60405180910390a450506065805460ff191660011790555092949350505050565b6001600160a01b037f000000000000000000000000016700800000000000000000000000000000000316300362000fa25760405162461bcd60e51b81526004016200059c906200338d565b7f00000000000000000000000001670080000000000000000000000000000000036001600160a01b031662000fed60008051602062004200833981519152546001600160a01b031690565b6001600160a01b031614620010165760405162461bcd60e51b81526004016200059c90620033d9565b620010218262001932565b6200061b828260016200193c565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000000031614620010d15760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016200059c565b50600080516020620042008339815191525b90565b620010f062001bac565b620010fc6000620021e2565b565b62001113606554610100900460ff1660021490565b15620011325760405163bae6e2a960e01b815260040160405180910390fd5b6200113c62001bac565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000a9a565b60fb60205260009081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b0316929190620011bc90620036d8565b80601f0160208091040260200160405190810160405280929190818152602001828054620011ea90620036d8565b80156200123b5780601f106200120f576101008083540402835291602001916200123b565b820191906000526020600020905b8154815290600101906020018083116200121d57829003601f168201915b5050505050908060020180546200125290620036d8565b80601f01602080910402602001604051908101604052809291908181526020018280546200128090620036d8565b8015620012d15780601f10620012a557610100808354040283529160200191620012d1565b820191906000526020600020905b815481529060010190602001808311620012b357829003601f168201915b5050505050905084565b6000620012ea46848462001ab9565b90505b92915050565b60655460ff16600119016200131b5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff191660021790556200133d606554610100900460ff1660021490565b156200135c5760405163bae6e2a960e01b815260040160405180910390fd5b6200136662002234565b5060006200137b60a084016080850162002d48565b6001600160a01b031603620013a35760405163016a294f60e41b815260040160405180910390fd5b46620013b66060840160408501620032d1565b6001600160401b031614620013de57604051630a15fbb960e01b815260040160405180910390fd5b600080620013f1610140850185620034c0565b6200140191600490829062003714565b81019062001410919062003825565b6020840151939550935050506001600160a01b031662001443576040516303f8a7d360e01b815260040160405180910390fd5b6020808301516001600160a01b03908116600090815260fb909252604090912054600160401b900416156200153a5760005b8151811015620015335760208301516001600160a01b03166340c10f19620014a460a088016080890162002d48565b848481518110620014b957620014b9620032f1565b60200260200101516040518363ffffffff1660e01b8152600401620014f39291906001600160a01b03929092168252602082015260400190565b600060405180830381600087803b1580156200150e57600080fd5b505af115801562001523573d6000803e3d6000fd5b5050505080600101905062001475565b5062001604565b60005b8151811015620016025760208301516001600160a01b03166342842e0e306200156d60a0890160808a0162002d48565b858581518110620015825762001582620032f1565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b158015620015dd57600080fd5b505af1158015620015f2573d6000803e3d6000fd5b505050508060010190506200153d565b505b6200162f60e08501356200161f60a087016080880162002d48565b6001600160a01b03169062001925565b6200164160a085016080860162002d48565b6001600160a01b0316837fe8449897bd3c926a272780c39ba13e77bf7a2c823479a75bfbc13ef631183dfd84602001518460006001600160401b038111156200168e576200168e62002d68565b604051908082528060200260200182016040528015620016b8578160200160208202803683370190505b50604051620016ca9392919062003876565b60405180910390a350506065805460ff191660011790555050565b620016ef62001bac565b6001600160a01b038116620017565760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200059c565b62000a0681620021e2565b6200176b6200232f565b62000a06816200234a565b6040805160608101825260008082526020820181905291810191909152620017a96562726964676560d01b6000620012db565b6001600160a01b0316336001600160a01b031614620017db57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156200181a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018409190620038b0565b9050600062001864826040015162000d886b195c98cdcc8c57dd985d5b1d60a21b90565b9050806001600160a01b031682602001516001600160a01b0316146200189d57604051632583296b60e01b815260040160405180910390fd5b5090565b600060fc81620018b56020850185620032d1565b6001600160401b031681526020019081526020016000206000836020016020810190620018e3919062002d48565b6001600160a01b0390811682526020820192909252604001600020541690508062001920576200191d620019178362003920565b62002394565b90505b919050565b6200061b82825a62002561565b62000a0662001bac565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156200197757620019728362002609565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015620019d4575060408051601f3d908101601f19168201909252620019d1918101906200392e565b60015b62001a395760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016200059c565b60008051602062004200833981519152811462001aab5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016200059c565b5062001972838383620026a8565b6097546000906001600160a01b031662001ae657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001b3f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b65919062003948565b90508115801562001b7d57506001600160a01b038116155b1562000a1b578362001b8f84620026d3565b604051630d69e23960e41b81526004016200059c92919062003968565b6033546001600160a01b03163314620010fc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200059c565b60006001600160a01b0383163b62001c2357506000620012ed565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa92505050801562001c90575060408051601f3d908101601f1916820190925262001c8d918101906200398c565b60015b15620012ed579392505050565b60408051608081018252600080825260208201526060918101829052808201829052600060fb8162001cd6606087016040880162002d48565b6001600160a01b039081168252602082019290925260400160002054600160401b9004161462001f715760fb600062001d16606086016040870162002d48565b6001600160a01b0390811682526020808301939093526040918201600020825160808101845281546001600160401b0381168252600160401b90049092169382019390935260018301805491939284019162001d7290620036d8565b80601f016020809104026020016040519081016040528092919081815260200182805462001da090620036d8565b801562001df15780601f1062001dc55761010080835404028352916020019162001df1565b820191906000526020600020905b81548152906001019060200180831162001dd357829003601f168201915b5050505050815260200160028201805462001e0c90620036d8565b80601f016020809104026020016040519081016040528092919081815260200182805462001e3a90620036d8565b801562001e8b5780601f1062001e5f5761010080835404028352916020019162001e8b565b820191906000526020600020905b81548152906001019060200180831162001e6d57829003601f168201915b505050505081525050905060005b62001ea8606085018562003425565b905081101562001f6a5762001ec4606085016040860162002d48565b6001600160a01b0316639dc29fac8662001ee2606088018862003425565b8581811062001ef55762001ef5620032f1565b6040516001600160e01b031960e087901b1681526001600160a01b0390941660048501526020029190910135602483015250604401600060405180830381600087803b15801562001f4557600080fd5b505af115801562001f5a573d6000803e3d6000fd5b5050505080600101905062001e99565b506200216e565b600062001f85606085016040860162002d48565b90506040518060800160405280466001600160401b0316815260200185604001602081019062001fb6919062002d48565b6001600160a01b03168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562002003573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200202d9190810190620039ac565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562002071573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200209b9190810190620039ac565b9052915060005b620020b1606086018662003425565b90508110156200216b576001600160a01b0382166323b872dd8730620020db60608a018a62003425565b86818110620020ee57620020ee620032f1565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b1580156200214657600080fd5b505af11580156200215b573d6000803e3d6000fd5b50505050806001019050620020a2565b50505b3063300536b5828662002188604088016020890162002d48565b62002197606089018962003425565b604051602401620021ad959493929190620039e4565b60408051601f198184030181529190526020810180516001600160e01b031660e09390931b9290921790915295945050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040805160608101825260008082526020820181905291810191909152620022676562726964676560d01b6000620012db565b6001600160a01b0316336001600160a01b0316146200229957604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015620022d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022fe9190620038b0565b60208101519091506001600160a01b03163314620010e357604051632583296b60e01b815260040160405180910390fd5b620023396200276c565b6065805461ffff1916610101179055565b6001600160401b034610620023725760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b609754602080830151835160408086015160608701519151600096879663689ccd8d60e11b96620023d8966001600160a01b03909316959094929390910162003a9a565b60408051601f1981840301815290829052620023f8929160200162003af7565b60405160208183030381529060405290506200243e6200242b6d627269646765645f65726337323160901b6000620012db565b6033546001600160a01b031683620027a0565b6001600160a01b03808216600090815260fb60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620024a3908262003b7c565b5060608201516002820190620024ba908262003b7c565b505083516001600160401b03908116600090815260fc6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b9262002553929062003c48565b60405180910390a450919050565b6001600160a01b0383166200258957604051634c67134d60e11b815260040160405180910390fd5b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d8060008114620025db576040519150601f19603f3d011682016040523d82523d6000602084013e620025e0565b606091505b50509050806200260357604051634c67134d60e11b815260040160405180910390fd5b50505050565b6001600160a01b0381163b620026785760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200059c565b6000805160206200420083398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b620026b38362002900565b600082511180620026c15750805b15620019725762002603838362002942565b60606000620026e2836200296a565b60010190506000816001600160401b0381111562002704576200270462002d68565b6040519080825280601f01601f1916602001820160405280156200272f576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846200273957509392505050565b600054610100900460ff16620027965760405162461bcd60e51b81526004016200059c9062003c7a565b620010fc62002a49565b60006001600160a01b038416620027ca576040516305d1c47b60e41b815260040160405180910390fd5b8382604051620027da9062002c51565b620027e792919062003cc5565b604051809103906000f08015801562002804573d6000803e3d6000fd5b5090506001600160a01b03831615801590620028965750806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200285a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002880919062003948565b6001600160a01b0316836001600160a01b031614155b1562000a1b5760405163f2fde38b60e01b81526001600160a01b03848116600483015282169063f2fde38b90602401600060405180830381600087803b158015620028e057600080fd5b505af1158015620028f5573d6000803e3d6000fd5b505050509392505050565b6200290b8162002609565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620012ea8383604051806060016040528060278152602001620042206027913962002a7e565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310620029aa5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310620029d7576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310620029f657662386f26fc10000830492506010015b6305f5e100831062002a0f576305f5e100830492506008015b612710831062002a2457612710830492506004015b6064831062002a37576064830492506002015b600a8310620012ed5760010192915050565b600054610100900460ff1662002a735760405162461bcd60e51b81526004016200059c9062003c7a565b620010fc33620021e2565b6060600080856001600160a01b03168560405162002a9d919062003ceb565b600060405180830381855af49150503d806000811462002ada576040519150601f19603f3d011682016040523d82523d6000602084013e62002adf565b606091505b509150915062002af28683838762002afc565b9695505050505050565b6060831562002b7057825160000362002b68576001600160a01b0385163b62002b685760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200059c565b508162002b7c565b62002b7c838362002b84565b949350505050565b81511562002b955781518083602001fd5b8060405162461bcd60e51b81526004016200059c919062003d09565b60405180610180016040528060006001600160801b0316815260200160006001600160a01b0316815260200160006001600160401b0316815260200160006001600160401b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160608152602001606081525090565b6104e18062003d1f83390190565b60006020828403121562002c7257600080fd5b81356001600160e01b031981168114620012ea57600080fd5b6001600160a01b038116811462000a0657600080fd5b60008060008060006080868803121562002cba57600080fd5b853562002cc78162002c8b565b9450602086013562002cd98162002c8b565b93506040860135925060608601356001600160401b038082111562002cfd57600080fd5b818801915088601f83011262002d1257600080fd5b81358181111562002d2257600080fd5b89602082850101111562002d3557600080fd5b9699959850939650602001949392505050565b60006020828403121562002d5b57600080fd5b8135620012ea8162002c8b565b634e487b7160e01b600052604160045260246000fd5b60405161018081016001600160401b038111828210171562002da45762002da462002d68565b60405290565b604051601f8201601f191681016001600160401b038111828210171562002dd55762002dd562002d68565b604052919050565b600082601f83011262002def57600080fd5b813560206001600160401b0382111562002e0d5762002e0d62002d68565b8160051b62002e1e82820162002daa565b928352848101820192828101908785111562002e3957600080fd5b83870192505b8483101562002e5a5782358252918301919083019062002e3f565b979650505050505050565b6000806000806080858703121562002e7c57600080fd5b84356001600160401b038082111562002e9457600080fd5b908601906080828903121562002ea957600080fd5b90945060208601359062002ebd8262002c8b565b90935060408601359062002ed18262002c8b565b9092506060860135908082111562002ee857600080fd5b5062002ef78782880162002ddd565b91505092959194509250565b6001600160401b038116811462000a0657600080fd5b801515811462000a0657600080fd5b60008060006060848603121562002f3e57600080fd5b833562002f4b8162002f03565b925060208401359150604084013562002f648162002f19565b809150509250925092565b60006020828403121562002f8257600080fd5b81356001600160401b0381111562002f9957600080fd5b82016101208185031215620012ea57600080fd5b60005b8381101562002fca57818101518382015260200162002fb0565b50506000910152565b6000815180845262002fed81602086016020860162002fad565b601f01601f19169290920160200192915050565b602081526200301c6020820183516001600160801b03169052565b600060208301516200303960408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610180610160808501829052620030eb6101a086018462002fd3565b90860151858203601f19018387015290925062002af2838262002fd3565b60006001600160401b0382111562003125576200312562002d68565b50601f01601f191660200190565b60006200314a620031448462003109565b62002daa565b90508281528383830111156200315f57600080fd5b828260208301376000602084830101529392505050565b600080604083850312156200318a57600080fd5b8235620031978162002c8b565b915060208301356001600160401b03811115620031b357600080fd5b8301601f81018513620031c557600080fd5b620031d68582356020840162003133565b9150509250929050565b60008060408385031215620031f457600080fd5b823591506020830135620032088162002c8b565b809150509250929050565b6001600160401b03851681526001600160a01b0384166020820152608060408201819052600090620032489083018562002fd3565b828103606084015262002e5a818562002fd3565b600080604083850312156200327057600080fd5b823591506020830135620032088162002f19565b600080604083850312156200329857600080fd5b82356001600160401b03811115620032af57600080fd5b83016101808186031215620032c357600080fd5b946020939093013593505050565b600060208284031215620032e457600080fd5b8135620012ea8162002f03565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b8381101562003339578151875295820195908201906001016200331b565b509495945050505050565b6001600160401b03851681526001600160a01b0384166020820152608060408201819052600090620033799083018562003307565b828103606084015262002e5a818562003307565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000808335601e198436030181126200343d57600080fd5b8301803591506001600160401b038211156200345857600080fd5b6020019150600581901b36038213156200347157600080fd5b9250929050565b634e487b7160e01b600052601160045260246000fd5b600060018201620034a357620034a362003478565b5060010190565b81810381811115620012ed57620012ed62003478565b6000808335601e19843603018112620034d857600080fd5b8301803591506001600160401b03821115620034f357600080fd5b6020019150368190038213156200347157600080fd5b80516001600160801b03811681146200192057600080fd5b8051620019208162002c8b565b8051620019208162002f03565b600082601f8301126200354d57600080fd5b81516200355e620031448262003109565b8181528460208386010111156200357457600080fd5b62002b7c82602083016020870162002fad565b600080604083850312156200359b57600080fd5b8251915060208301516001600160401b0380821115620035ba57600080fd5b908401906101808287031215620035d057600080fd5b620035da62002d7e565b620035e58362003509565b8152620035f56020840162003521565b602082015262003608604084016200352e565b60408201526200361b606084016200352e565b60608201526200362e6080840162003521565b60808201526200364160a0840162003521565b60a08201526200365460c0840162003521565b60c082015260e083810151908201526101008084015190820152610120808401519082015261014080840151838111156200368e57600080fd5b6200369c898287016200353b565b8284015250506101608084015183811115620036b757600080fd5b620036c5898287016200353b565b8284015250508093505050509250929050565b600181811c90821680620036ed57607f821691505b6020821081036200370e57634e487b7160e01b600052602260045260246000fd5b50919050565b600080858511156200372557600080fd5b838611156200373357600080fd5b5050820193919092039150565b600082601f8301126200375257600080fd5b620012ea8383356020850162003133565b6000608082840312156200377657600080fd5b604051608081016001600160401b0382821081831117156200379c576200379c62002d68565b8160405282935084359150620037b28262002f03565b908252602084013590620037c68262002c8b565b8160208401526040850135915080821115620037e157600080fd5b620037ef8683870162003740565b604084015260608501359150808211156200380957600080fd5b50620038188582860162003740565b6060830152505092915050565b600080600080608085870312156200383c57600080fd5b84356001600160401b03808211156200385457600080fd5b620038628883890162003763565b95506020870135915062002ebd8262002c8b565b6001600160a01b03841681526060602082018190526000906200389c9083018562003307565b828103604084015262002af2818562003307565b600060608284031215620038c357600080fd5b604051606081018181106001600160401b0382111715620038e857620038e862002d68565b604052825181526020830151620038ff8162002c8b565b60208201526040830151620039148162002f03565b60408201529392505050565b60006200191d368362003763565b6000602082840312156200394157600080fd5b5051919050565b6000602082840312156200395b57600080fd5b8151620012ea8162002c8b565b6001600160401b038316815260406020820152600062000a18604083018462002fd3565b6000602082840312156200399f57600080fd5b8151620012ea8162002f19565b600060208284031215620039bf57600080fd5b81516001600160401b03811115620039d657600080fd5b62002b7c848285016200353b565b608080825286516001600160401b03168282015260208701516001600160a01b0390811660a0840152604088015160c08401929092526000919062003a2e61010085018362002fd3565b91506060890151607f198584030160e086015262003a4d838262002fd3565b8983166020870152918816604086015250838103606085015284815290506001600160fb1b0384111562003a8057600080fd5b8360051b8086602084013701602001979650505050505050565b6001600160a01b038681168252851660208201526001600160401b038416604082015260a06060820181905260009062003ad79083018562002fd3565b828103608084015262003aeb818562002fd3565b98975050505050505050565b6001600160e01b031983168152815160009062003b1c81600485016020870162002fad565b919091016004019392505050565b601f8211156200197257600081815260208120601f850160051c8101602086101562003b535750805b601f850160051c820191505b8181101562003b745782815560010162003b5f565b505050505050565b81516001600160401b0381111562003b985762003b9862002d68565b62003bb08162003ba98454620036d8565b8462003b2a565b602080601f83116001811462003be8576000841562003bcf5750858301515b600019600386901b1c1916600185901b17855562003b74565b600085815260208120601f198616915b8281101562003c195788860151825594840194600190910190840162003bf8565b508582101562003c385787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600062003c5d604083018562002fd3565b828103602084015262003c71818562002fd3565b95945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b038316815260406020820181905260009062000a189083018462002fd3565b6000825162003cff81846020870162002fad565b9190910192915050565b602081526000620012ea602083018462002fd356fe60806040526040516104e13803806104e1833981016040819052610022916102de565b61002e82826000610035565b50506103fb565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ba60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019d91906103ac565b600060405180830381855af49150503d80600081146101d8576040519150601f19603f3d011682016040523d82523d6000602084013e6101dd565b606091505b5090925090506101ef868383876101f9565b9695505050505050565b60608315610268578251600003610261576001600160a01b0385163b6102615760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610136565b5081610272565b610272838361027a565b949350505050565b81511561028a5781518083602001fd5b8060405162461bcd60e51b815260040161013691906103c8565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102d55781810151838201526020016102bd565b50506000910152565b600080604083850312156102f157600080fd5b82516001600160a01b038116811461030857600080fd5b60208401519092506001600160401b038082111561032557600080fd5b818501915085601f83011261033957600080fd5b81518181111561034b5761034b6102a4565b604051601f8201601f19908116603f01168101908382118183101715610373576103736102a4565b8160405282815288602084870101111561038c57600080fd5b61039d8360208301602088016102ba565b80955050505050509250929050565b600082516103be8184602087016102ba565b9190910192915050565b60208152600082518060208401526103e78160408501602087016102ba565b601f01601f19169190910160400192915050565b60b1806104096000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122034f9fc40c762685de47255fa9cd4229571eee4fcb64ab3c7108167a46b3404ef64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670080000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000003" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x608060405260043610620001845760003560e01c806359f4a90711620000e25780638da5cb5b1162000095578063bc197c81116200006c578063bc197c8114620004a1578063c389a18014620004d4578063f23a6e6114620004eb578063f2fde38b146200051c57600080fd5b80638da5cb5b14620004255780639aa8605c1462000445578063a86f9d9e146200047c57600080fd5b806359f4a90714620003595780635c975abb1462000376578063634da63a146200039957806367090ccf14620003b0578063715018a614620003f55780638456cb59146200040d57600080fd5b80633ab76e9f116200013b5780633ab76e9f146200028c5780633eb6b8cf14620002c75780633f4ba83a14620002ec57806348b2772e14620003045780634f1ef286146200032a57806352d1902d146200034157600080fd5b806301ffc9a7146200018957806306fdde0314620001c3578063079312bf14620001f257806319ab453c146200020b5780632ca069a514620002305780633659cfe61462000267575b600080fd5b3480156200019657600080fd5b50620001ae620001a836600462002c08565b62000541565b60405190151581526020015b60405180910390f35b348015620001d057600080fd5b506c195c98cc4c4d4d57dd985d5b1d609a1b5b604051908152602001620001ba565b620002096200020336600462002d7a565b62000579565b005b3480156200021857600080fd5b50620002096200022a36600462002e40565b62000885565b3480156200023d57600080fd5b506200024d636cdb3d1360e11b81565b6040516001600160e01b03199091168152602001620001ba565b3480156200027457600080fd5b50620002096200028636600462002e40565b620009a5565b3480156200029957600080fd5b50609754620002ae906001600160a01b031681565b6040516001600160a01b039091168152602001620001ba565b348015620002d457600080fd5b50620002ae620002e636600462002e92565b62000a90565b348015620002f957600080fd5b506200020962000aa9565b6200031b6200031536600462002ed9565b62000b2b565b604051620001ba919062002f6b565b620002096200033b366004620030e0565b62000fe9565b3480156200034e57600080fd5b50620001e3620010c1565b3480156200036657600080fd5b506200024d6380ac58cd60e01b81565b3480156200038357600080fd5b50620001ae606554610100900460ff1660021490565b348015620003a657600080fd5b50620001e3600a81565b348015620003bd57600080fd5b50620002ae620003cf3660046200314a565b60fc6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156200040257600080fd5b506200020962001178565b3480156200041a57600080fd5b506200020962001190565b3480156200043257600080fd5b506033546001600160a01b0316620002ae565b3480156200045257600080fd5b506200046a6200046436600462002e40565b6200120e565b604051620001ba94939291906200317d565b3480156200048957600080fd5b50620002ae6200049b366004620031c6565b6200136d565b348015620004ae57600080fd5b506200024d620004c036600462003280565b63bc197c8160e01b98975050505050505050565b62000209620004e53660046200334c565b6200137c565b348015620004f857600080fd5b506200024d6200050a36600462003399565b63f23a6e6160e01b9695505050505050565b3480156200052957600080fd5b50620002096200053b36600462002e40565b620016de565b60006001600160e01b031982166301ffc9a760e01b1480620005735750630187134360e71b6001600160e01b03198316145b92915050565b60655460ff1660011901620005a15760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055620005c3606554610100900460ff1660021490565b15620005e25760405163bae6e2a960e01b815260040160405180910390fd5b6000620005ee6200175a565b905060006001600160a01b03851615806200061157506001600160a01b03851630145b6200061d57846200061f565b855b90506000466200063360208a018a6200341c565b6001600160401b0316036200071657620006546040890160208a0162002e40565b905060005b85518110156200070f57816001600160a01b031663f242432a30858985815181106200068957620006896200343c565b6020026020010151898681518110620006a657620006a66200343c565b60200260200101516040518563ffffffff1660e01b8152600401620006cf949392919062003452565b600060405180830381600087803b158015620006ea57600080fd5b505af1158015620006ff573d6000803e3d6000fd5b5050505080600101905062000659565b50620007fd565b6200072b62000725896200356f565b62001886565b905060005b8551811015620007fb57816001600160a01b031663156e29f6848884815181106200075f576200075f6200343c565b60200260200101518885815181106200077c576200077c6200343c565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b158015620007d657600080fd5b505af1158015620007eb573d6000803e3d6000fd5b5050505080600101905062000730565b505b620008126001600160a01b03831634620018d0565b856001600160a01b0316876001600160a01b031684600001517f8a4d138c7a19e12f6cdedfca02085820b0b1f5a9655c7a8b784f1d534347f2478660400151858a8a604051620008669493929190620035ba565b60405180910390a450506065805460ff19166001179055505050505050565b600054610100900460ff1615808015620008a65750600054600160ff909116105b80620008c25750303b158015620008c2575060005460ff166001145b6200092b5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156200094f576000805461ff0019166101001790555b6200095a82620018dd565b8015620009a1576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6001600160a01b037f0000000000000000000000000167008000000000000000000000000000000004163003620009f05760405162461bcd60e51b8152600401620009229062003603565b7f00000000000000000000000001670080000000000000000000000000000000046001600160a01b031662000a3b60008051602062004483833981519152546001600160a01b031690565b6001600160a01b03161462000a645760405162461bcd60e51b815260040162000922906200364f565b62000a6f81620018f2565b6040805160008082526020820190925262000a8d91839190620018fc565b50565b600062000a9f84848462001a79565b90505b9392505050565b62000abe606554610100900460ff1660021490565b62000adc5760405163bae6e2a960e01b815260040160405180910390fd5b62000ae662001b6c565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b62000b3562002b5a565b60655460ff166001190162000b5d5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905562000b7f606554610100900460ff1660021490565b1562000b9e5760405163bae6e2a960e01b815260040160405180910390fd5b8162000bae60808201826200369b565b905062000bbf60608301836200369b565b90501462000be05760405163196e8a4160e31b815260040160405180910390fd5b600a62000bf160608301836200369b565b9050111562000c135760405163e4a4c1c760e01b815260040160405180910390fd5b600062000c27606083016040840162002e40565b6001600160a01b03160362000c4f576040516303f8a7d360e01b815260040160405180910390fd5b60005b62000c6160808501856200369b565b905081101562000cc85762000c7a60808501856200369b565b8281811062000c8d5762000c8d6200343c565b9050602002013560000362000cb557604051634299323b60e11b815260040160405180910390fd5b62000cc081620036fd565b905062000c52565b5062000cf7636cdb3d1360e11b62000ce7606086016040870162002e40565b6001600160a01b03169062001bc8565b62000d1557604051633ee915f560e11b815260040160405180910390fd5b600062000d2660808501856200369b565b80806020026020016040519081016040528093929190818152602001838360200280828437600092018290525093945062000d6c92505050606086016040870162002e40565b9050600062000d7f60608701876200369b565b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092935062000dbf925062002b5a915050565b62000dce60208801886200341c565b6001600160401b0316606082015262000df23362000dec8962003719565b62001c5d565b610140820152336080820152606081015162000e22906c195c98cc4c4d4d57dd985d5b1d609a1b5b600062000a90565b6001600160a01b031660a08083019190915287013561012082015262000e4d60c0880135346200381c565b60e08083019190915260c08801356101008084019190915262000e769190890190890162002e40565b6001600160a01b031660c082015262000e9461010088018862003832565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052506101608601949094525062000ee791506562726964676560d01b9050826200136d565b6001600160a01b03166333bcd0cc34846040518363ffffffff1660e01b815260040162000f15919062002f6b565b60006040518083038185885af115801562000f34573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405262000f5f9190810190620038f9565b9750905062000f756040890160208a0162002e40565b6001600160a01b031687608001516001600160a01b0316827f329b657c35d4e2dfede6ef5132869accb1f8542912a40f9a854b4a917ffae2e98a6060015188888b60405162000fc89493929190620035ba565b60405180910390a450506065805460ff191660011790555092949350505050565b6001600160a01b037f0000000000000000000000000167008000000000000000000000000000000004163003620010345760405162461bcd60e51b8152600401620009229062003603565b7f00000000000000000000000001670080000000000000000000000000000000046001600160a01b03166200107f60008051602062004483833981519152546001600160a01b031690565b6001600160a01b031614620010a85760405162461bcd60e51b815260040162000922906200364f565b620010b382620018f2565b620009a182826001620018fc565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000000041614620011635760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840162000922565b50600080516020620044838339815191525b90565b6200118262001b6c565b6200118e60006200218a565b565b620011a5606554610100900460ff1660021490565b15620011c45760405163bae6e2a960e01b815260040160405180910390fd5b620011ce62001b6c565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200162000b21565b60fb60205260009081526040902080546001820180546001600160401b03831693600160401b9093046001600160a01b03169291906200124e9062003a4a565b80601f01602080910402602001604051908101604052809291908181526020018280546200127c9062003a4a565b8015620012cd5780601f10620012a157610100808354040283529160200191620012cd565b820191906000526020600020905b815481529060010190602001808311620012af57829003601f168201915b505050505090806002018054620012e49062003a4a565b80601f0160208091040260200160405190810160405280929190818152602001828054620013129062003a4a565b8015620013635780601f10620013375761010080835404028352916020019162001363565b820191906000526020600020905b8154815290600101906020018083116200134557829003601f168201915b5050505050905084565b600062000aa246848462001a79565b60655460ff1660011901620013a45760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055620013c6606554610100900460ff1660021490565b15620013e55760405163bae6e2a960e01b815260040160405180910390fd5b620013ef620021dc565b50600080806200140461014086018662003832565b6200141491600490829062003a86565b81019062001423919062003ab2565b6020850151949750909550935050506001600160a01b031662001459576040516303f8a7d360e01b815260040160405180910390fd5b6020808401516001600160a01b03908116600090815260fb909252604090912054600160401b90041615620015725760005b82518110156200156b5760208401516001600160a01b031663156e29f6620014ba60a0890160808a0162002e40565b858481518110620014cf57620014cf6200343c565b6020026020010151858581518110620014ec57620014ec6200343c565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b1580156200154657600080fd5b505af11580156200155b573d6000803e3d6000fd5b505050508060010190506200148b565b5062001642565b60005b8251811015620016405760208401516001600160a01b031663f242432a30620015a560a08a0160808b0162002e40565b868581518110620015ba57620015ba6200343c565b6020026020010151868681518110620015d757620015d76200343c565b60200260200101516040518563ffffffff1660e01b815260040162001600949392919062003452565b600060405180830381600087803b1580156200161b57600080fd5b505af115801562001630573d6000803e3d6000fd5b5050505080600101905062001575565b505b6200166d60e08601356200165d60a088016080890162002e40565b6001600160a01b031690620018d0565b6200167f60a086016080870162002e40565b6001600160a01b0316847fe8449897bd3c926a272780c39ba13e77bf7a2c823479a75bfbc13ef631183dfd85602001518585604051620016c29392919062003b05565b60405180910390a350506065805460ff19166001179055505050565b620016e862001b6c565b6001600160a01b0381166200174f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000922565b62000a8d816200218a565b60408051606081018252600080825260208201819052918101919091526200178d6562726964676560d01b60006200136d565b6001600160a01b0316336001600160a01b031614620017bf57604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa158015620017fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001824919062003b3f565b9050600062001849826040015162000e1a6c195c98cc4c4d4d57dd985d5b1d609a1b90565b9050806001600160a01b031682602001516001600160a01b0316146200188257604051632583296b60e01b815260040160405180910390fd5b5090565b80516001600160401b0316600090815260fc60209081526040808320828501516001600160a01b0390811685529252909120541680620018cb576200057382620022d7565b919050565b620009a182825a620024a5565b620018e76200254d565b62000a8d8162002568565b62000a8d62001b6c565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161562001937576200193283620025b2565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801562001994575060408051601f3d908101601f19168201909252620019919181019062003baf565b60015b620019f95760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840162000922565b60008051602062004483833981519152811462001a6b5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840162000922565b506200193283838362002651565b6097546000906001600160a01b031662001aa657604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa15801562001aff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b25919062003bc9565b90508115801562001b3d57506001600160a01b038116155b1562000aa2578362001b4f846200267c565b604051630d69e23960e41b81526004016200092292919062003be9565b6033546001600160a01b031633146200118e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000922565b60006001600160a01b0383163b62001be35750600062000573565b6040516301ffc9a760e01b81526001600160e01b0319831660048201526001600160a01b038416906301ffc9a790602401602060405180830381865afa92505050801562001c50575060408051601f3d908101601f1916820190925262001c4d9181019062003c0d565b60015b1562000573579392505050565b604080516080810182526000808252602082015260609181018290528082018290526040808401516001600160a01b03908116600090815260fb6020529190912054600160401b9004161562001f17576040808401516001600160a01b03908116600090815260fb602090815290839020835160808101855281546001600160401b0381168252600160401b900490931691830191909152600181018054929391929184019162001d0e9062003a4a565b80601f016020809104026020016040519081016040528092919081815260200182805462001d3c9062003a4a565b801562001d8d5780601f1062001d615761010080835404028352916020019162001d8d565b820191906000526020600020905b81548152906001019060200180831162001d6f57829003601f168201915b5050505050815260200160028201805462001da89062003a4a565b80601f016020809104026020016040519081016040528092919081815260200182805462001dd69062003a4a565b801562001e275780601f1062001dfb5761010080835404028352916020019162001e27565b820191906000526020600020905b81548152906001019060200180831162001e0957829003601f168201915b505050505081525050905060005b83606001515181101562001f105783604001516001600160a01b031663f5298aca868660600151848151811062001e705762001e706200343c565b60200260200101518760800151858151811062001e915762001e916200343c565b60209081029190910101516040516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526044820152606401600060405180830381600087803b15801562001eeb57600080fd5b505af115801562001f00573d6000803e3d6000fd5b5050505080600101905062001e35565b506200211f565b6040518060800160405280466001600160401b0316815260200184604001516001600160a01b03168152602001604051806020016040528060008152508152602001604051806020016040528060008152508152509050600083604001519050806001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa92505050801562001fd957506040513d6000823e601f3d908101601f1916820160405262001fd6919081019062003c2d565b60015b1562001fe55760608301525b806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa9250505080156200204757506040513d6000823e601f3d908101601f1916820160405262002044919081019062003c2d565b60015b15620020535760408301525b60005b8460600151518110156200211c5784604001516001600160a01b031663f242432a3330886060015185815181106200209257620020926200343c565b602002602001015189608001518681518110620020b357620020b36200343c565b60200260200101516040518563ffffffff1660e01b8152600401620020dc949392919062003452565b600060405180830381600087803b158015620020f757600080fd5b505af11580156200210c573d6000803e3d6000fd5b5050505080600101905062002056565b50505b306001600160a01b031663079312bf82868660200151876060015188608001516040516024016200215595949392919062003c65565b60408051601f198184030181529190526020810180516001600160e01b031660e09390931b9290921790915295945050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60408051606081018252600080825260208201819052918101919091526200220f6562726964676560d01b60006200136d565b6001600160a01b0316336001600160a01b0316146200224157604051632583296b60e01b815260040160405180910390fd5b336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562002280573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022a6919062003b3f565b60208101519091506001600160a01b031633146200117557604051632583296b60e01b815260040160405180910390fd5b609754602080830151835160408086015160608701519151600096879663689ccd8d60e11b966200231b966001600160a01b03909316959094929390910162003d29565b60408051601f19818403018152908290526200233b929160200162003d7a565b6040516020818303038152906040529050620023826200236f6e627269646765645f6572633131353560881b60006200136d565b6033546001600160a01b03168362002715565b6001600160a01b03808216600090815260fb60209081526040918290208751815492890151909416600160401b026001600160e01b03199092166001600160401b039094169390931717825585015191935084916001820190620023e7908262003dff565b5060608201516002820190620023fe908262003dff565b505083516001600160401b03908116600090815260fc6020908152604080832082890180516001600160a01b039081168652919093529281902080546001600160a01b03191688851690811790915591518851828a015160608b01519351949750919094169493909316927f44977f2d30fe1e3aee2c1476f2f95aaacaf34e44b9359c403da01fcc93fd751b9262002497929062003ecb565b60405180910390a450919050565b6001600160a01b038316620024cd57604051634c67134d60e11b815260040160405180910390fd5b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d80600081146200251f576040519150601f19603f3d011682016040523d82523d6000602084013e62002524565b606091505b50509050806200254757604051634c67134d60e11b815260040160405180910390fd5b50505050565b6200255762002875565b6065805461ffff1916610101179055565b6001600160401b034610620025905760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381163b620026215760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840162000922565b6000805160206200448383398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6200265c83620028a9565b6000825111806200266a5750805b156200193257620025478383620028eb565b606060006200268b8362002913565b60010190506000816001600160401b03811115620026ad57620026ad62002c57565b6040519080825280601f01601f191660200182016040528015620026d8576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084620026e257509392505050565b60006001600160a01b0384166200273f576040516305d1c47b60e41b815260040160405180910390fd5b83826040516200274f9062002bfa565b6200275c92919062003efd565b604051809103906000f08015801562002779573d6000803e3d6000fd5b5090506001600160a01b038316158015906200280b5750806001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620027cf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620027f5919062003bc9565b6001600160a01b0316836001600160a01b031614155b1562000aa25760405163f2fde38b60e01b81526001600160a01b03848116600483015282169063f2fde38b90602401600060405180830381600087803b1580156200285557600080fd5b505af11580156200286a573d6000803e3d6000fd5b505050509392505050565b600054610100900460ff166200289f5760405162461bcd60e51b8152600401620009229062003f23565b6200118e620029f2565b620028b481620025b2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b606062000aa28383604051806060016040528060278152602001620044a36027913962002a27565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310620029535772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831062002980576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106200299f57662386f26fc10000830492506010015b6305f5e1008310620029b8576305f5e100830492506008015b6127108310620029cd57612710830492506004015b60648310620029e0576064830492506002015b600a8310620005735760010192915050565b600054610100900460ff1662002a1c5760405162461bcd60e51b8152600401620009229062003f23565b6200118e336200218a565b6060600080856001600160a01b03168560405162002a46919062003f6e565b600060405180830381855af49150503d806000811462002a83576040519150601f19603f3d011682016040523d82523d6000602084013e62002a88565b606091505b509150915062002a9b8683838762002aa5565b9695505050505050565b6060831562002b1957825160000362002b11576001600160a01b0385163b62002b115760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000922565b508162002b25565b62002b25838362002b2d565b949350505050565b81511562002b3e5781518083602001fd5b8060405162461bcd60e51b815260040162000922919062003f8c565b60405180610180016040528060006001600160801b0316815260200160006001600160a01b0316815260200160006001600160401b0316815260200160006001600160401b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160608152602001606081525090565b6104e18062003fa283390190565b60006020828403121562002c1b57600080fd5b81356001600160e01b03198116811462000aa257600080fd5b6001600160a01b038116811462000a8d57600080fd5b8035620018cb8162002c34565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b038111828210171562002c935762002c9362002c57565b60405290565b60405161018081016001600160401b038111828210171562002c935762002c9362002c57565b604051601f8201601f191681016001600160401b038111828210171562002cea5762002cea62002c57565b604052919050565b600082601f83011262002d0457600080fd5b813560206001600160401b0382111562002d225762002d2262002c57565b8160051b62002d3382820162002cbf565b928352848101820192828101908785111562002d4e57600080fd5b83870192505b8483101562002d6f5782358252918301919083019062002d54565b979650505050505050565b600080600080600060a0868803121562002d9357600080fd5b85356001600160401b038082111562002dab57600080fd5b908701906080828a03121562002dc057600080fd5b90955060208701359062002dd48262002c34565b90945060408701359062002de88262002c34565b9093506060870135908082111562002dff57600080fd5b62002e0d89838a0162002cf2565b9350608088013591508082111562002e2457600080fd5b5062002e338882890162002cf2565b9150509295509295909350565b60006020828403121562002e5357600080fd5b813562000aa28162002c34565b6001600160401b038116811462000a8d57600080fd5b8035620018cb8162002e60565b801515811462000a8d57600080fd5b60008060006060848603121562002ea857600080fd5b833562002eb58162002e60565b925060208401359150604084013562002ece8162002e83565b809150509250925092565b60006020828403121562002eec57600080fd5b81356001600160401b0381111562002f0357600080fd5b8201610120818503121562000aa257600080fd5b60005b8381101562002f3457818101518382015260200162002f1a565b50506000910152565b6000815180845262002f5781602086016020860162002f17565b601f01601f19169290920160200192915050565b6020815262002f866020820183516001600160801b03169052565b6000602083015162002fa360408401826001600160a01b03169052565b5060408301516001600160401b03811660608401525060608301516001600160401b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610180610160808501829052620030556101a086018462002f3d565b90860151858203601f19018387015290925062002a9b838262002f3d565b60006001600160401b038211156200308f576200308f62002c57565b50601f01601f191660200190565b6000620030b4620030ae8462003073565b62002cbf565b9050828152838383011115620030c957600080fd5b828260208301376000602084830101529392505050565b60008060408385031215620030f457600080fd5b8235620031018162002c34565b915060208301356001600160401b038111156200311d57600080fd5b8301601f810185136200312f57600080fd5b62003140858235602084016200309d565b9150509250929050565b600080604083850312156200315e57600080fd5b823591506020830135620031728162002c34565b809150509250929050565b6001600160401b03851681526001600160a01b0384166020820152608060408201819052600090620031b29083018562002f3d565b828103606084015262002d6f818562002f3d565b60008060408385031215620031da57600080fd5b823591506020830135620031728162002e83565b60008083601f8401126200320157600080fd5b5081356001600160401b038111156200321957600080fd5b6020830191508360208260051b85010111156200323557600080fd5b9250929050565b60008083601f8401126200324f57600080fd5b5081356001600160401b038111156200326757600080fd5b6020830191508360208285010111156200323557600080fd5b60008060008060008060008060a0898b0312156200329d57600080fd5b8835620032aa8162002c34565b97506020890135620032bc8162002c34565b965060408901356001600160401b0380821115620032d957600080fd5b620032e78c838d01620031ee565b909850965060608b01359150808211156200330157600080fd5b6200330f8c838d01620031ee565b909650945060808b01359150808211156200332957600080fd5b50620033388b828c016200323c565b999c989b5096995094979396929594505050565b600080604083850312156200336057600080fd5b82356001600160401b038111156200337757600080fd5b830161018081860312156200338b57600080fd5b946020939093013593505050565b60008060008060008060a08789031215620033b357600080fd5b8635620033c08162002c34565b95506020870135620033d28162002c34565b9450604087013593506060870135925060808701356001600160401b03811115620033fc57600080fd5b6200340a89828a016200323c565b979a9699509497509295939492505050565b6000602082840312156200342f57600080fd5b813562000aa28162002e60565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b600082601f8301126200349c57600080fd5b62000aa2838335602085016200309d565b600060808284031215620034c057600080fd5b604051608081016001600160401b038282108183111715620034e657620034e662002c57565b8160405282935084359150620034fc8262002e60565b908252602084013590620035108262002c34565b81602084015260408501359150808211156200352b57600080fd5b62003539868387016200348a565b604084015260608501359150808211156200355357600080fd5b5062003562858286016200348a565b6060830152505092915050565b6000620005733683620034ad565b600081518084526020808501945080840160005b83811015620035af5781518752958201959082019060010162003591565b509495945050505050565b6001600160401b03851681526001600160a01b0384166020820152608060408201819052600090620035ef908301856200357d565b828103606084015262002d6f81856200357d565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000808335601e19843603018112620036b357600080fd5b8301803591506001600160401b03821115620036ce57600080fd5b6020019150600581901b36038213156200323557600080fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620037125762003712620036e7565b5060010190565b600061012082360312156200372d57600080fd5b6200373762002c6d565b620037428362002e76565b8152620037526020840162002c4a565b6020820152620037656040840162002c4a565b604082015260608301356001600160401b03808211156200378557600080fd5b620037933683870162002cf2565b60608401526080850135915080821115620037ad57600080fd5b620037bb3683870162002cf2565b608084015260a085013560a084015260c085013560c0840152620037e260e0860162002c4a565b60e084015261010091508185013581811115620037fe57600080fd5b6200380c368288016200348a565b8385015250505080915050919050565b81810381811115620005735762000573620036e7565b6000808335601e198436030181126200384a57600080fd5b8301803591506001600160401b038211156200386557600080fd5b6020019150368190038213156200323557600080fd5b80516001600160801b0381168114620018cb57600080fd5b8051620018cb8162002c34565b8051620018cb8162002e60565b600082601f830112620038bf57600080fd5b8151620038d0620030ae8262003073565b818152846020838601011115620038e657600080fd5b62002b2582602083016020870162002f17565b600080604083850312156200390d57600080fd5b8251915060208301516001600160401b03808211156200392c57600080fd5b9084019061018082870312156200394257600080fd5b6200394c62002c99565b62003957836200387b565b8152620039676020840162003893565b60208201526200397a60408401620038a0565b60408201526200398d60608401620038a0565b6060820152620039a06080840162003893565b6080820152620039b360a0840162003893565b60a0820152620039c660c0840162003893565b60c082015260e0838101519082015261010080840151908201526101208084015190820152610140808401518381111562003a0057600080fd5b62003a0e89828701620038ad565b828401525050610160808401518381111562003a2957600080fd5b62003a3789828701620038ad565b8284015250508093505050509250929050565b600181811c9082168062003a5f57607f821691505b60208210810362003a8057634e487b7160e01b600052602260045260246000fd5b50919050565b6000808585111562003a9757600080fd5b8386111562003aa557600080fd5b5050820193919092039150565b600080600080600060a0868803121562003acb57600080fd5b85356001600160401b038082111562003ae357600080fd5b62003af189838a01620034ad565b96506020880135915062002dd48262002c34565b6001600160a01b038416815260606020820181905260009062003b2b908301856200357d565b828103604084015262002a9b81856200357d565b60006060828403121562003b5257600080fd5b604051606081018181106001600160401b038211171562003b775762003b7762002c57565b60405282518152602083015162003b8e8162002c34565b6020820152604083015162003ba38162002e60565b60408201529392505050565b60006020828403121562003bc257600080fd5b5051919050565b60006020828403121562003bdc57600080fd5b815162000aa28162002c34565b6001600160401b038316815260406020820152600062000a9f604083018462002f3d565b60006020828403121562003c2057600080fd5b815162000aa28162002e83565b60006020828403121562003c4057600080fd5b81516001600160401b0381111562003c5757600080fd5b62002b2584828501620038ad565b60a080825286516001600160401b03169082015260208601516001600160a01b031660c08201526040860151608060e083015260009062003cab61012084018262002f3d565b90506060880151609f198483030161010085015262003ccb828262002f3d565b91505062003ce460208401886001600160a01b03169052565b6001600160a01b0386166040840152828103606084015262003d0781866200357d565b9050828103608084015262003d1d81856200357d565b98975050505050505050565b6001600160a01b038681168252851660208201526001600160401b038416604082015260a06060820181905260009062003d669083018562002f3d565b828103608084015262003d1d818562002f3d565b6001600160e01b031983168152815160009062003d9f81600485016020870162002f17565b919091016004019392505050565b601f8211156200193257600081815260208120601f850160051c8101602086101562003dd65750805b601f850160051c820191505b8181101562003df75782815560010162003de2565b505050505050565b81516001600160401b0381111562003e1b5762003e1b62002c57565b62003e338162003e2c845462003a4a565b8462003dad565b602080601f83116001811462003e6b576000841562003e525750858301515b600019600386901b1c1916600185901b17855562003df7565b600085815260208120601f198616915b8281101562003e9c5788860151825594840194600190910190840162003e7b565b508582101562003ebb5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600062003ee0604083018562002f3d565b828103602084015262003ef4818562002f3d565b95945050505050565b6001600160a01b038316815260406020820181905260009062000a9f9083018462002f3d565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000825162003f8281846020870162002f17565b9190910192915050565b60208152600062000aa2602083018462002f3d56fe60806040526040516104e13803806104e1833981016040819052610022916102de565b61002e82826000610035565b50506103fb565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ba60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019d91906103ac565b600060405180830381855af49150503d80600081146101d8576040519150601f19603f3d011682016040523d82523d6000602084013e6101dd565b606091505b5090925090506101ef868383876101f9565b9695505050505050565b60608315610268578251600003610261576001600160a01b0385163b6102615760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610136565b5081610272565b610272838361027a565b949350505050565b81511561028a5781518083602001fd5b8060405162461bcd60e51b815260040161013691906103c8565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102d55781810151838201526020016102bd565b50506000910152565b600080604083850312156102f157600080fd5b82516001600160a01b038116811461030857600080fd5b60208401519092506001600160401b038082111561032557600080fd5b818501915085601f83011261033957600080fd5b81518181111561034b5761034b6102a4565b604051601f8201601f19908116603f01168101908382118183101715610373576103736102a4565b8160405282815288602084870101111561038c57600080fd5b61039d8360208301602088016102ba565b80955050505050509250929050565b600082516103be8184602087016102ba565b9190910192915050565b60208152600082518060208401526103e78160408501602087016102ba565b601f01601f19169190910160400192915050565b60b1806104096000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122020b12ec97a75ea2a99ed24ae0d05211a476f5ca05d2ec3d3dc18afc15c10549564736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670080000000000000000000000000000000006", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000004" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010096": { + "storage": {}, + "code": "0x6080604052600436106101e35760003560e01c80635c975abb1161010257806395d89b4111610095578063a9059cbb11610064578063a9059cbb14610591578063b8f2e0c5146105b1578063dd62ed3e146105d1578063f2fde38b146105f157600080fd5b806395d89b411461051c5780639dc29fac14610531578063a457c2d714610551578063a86f9d9e1461057157600080fd5b80637cf8ed0d116100d15780637cf8ed0d146104b15780637e474634146104d25780638456cb59146104f25780638da5cb5b1461050757600080fd5b80635c975abb146104245780636c0db62b1461044557806370a0823114610465578063715018a61461049c57600080fd5b8063395093511161017a57806340c10f191161014957806340c10f19146103c557806349d12605146103e55780634f1ef286146103fc57806352d1902d1461040f57600080fd5b806339509351146103385780633ab76e9f146103585780633eb6b8cf146103905780633f4ba83a146103b057600080fd5b806323b872dd116101b657806323b872dd1461028457806326afaadd146102a4578063313ce567146102e95780633659cfe61461031657600080fd5b806306fdde03146101e8578063095ea7b3146102135780630ae745481461024357806318160ddd14610264575b600080fd5b3480156101f457600080fd5b506101fd610611565b60405161020a91906120a3565b60405180910390f35b34801561021f57600080fd5b5061023361022e3660046120cb565b61062c565b604051901515815260200161020a565b34801561024f57600080fd5b5060fb5461023390600160a01b900460ff1681565b34801561027057600080fd5b5061012f545b60405190815260200161020a565b34801561029057600080fd5b5061023361029f3660046120f7565b610646565b3480156102b057600080fd5b506102ca61015f54610160546001600160a01b0390911691565b604080516001600160a01b03909316835260208301919091520161020a565b3480156102f557600080fd5b5061015f54600160a01b900460ff1660405160ff909116815260200161020a565b34801561032257600080fd5b50610336610331366004612138565b61066c565b005b34801561034457600080fd5b506102336103533660046120cb565b610754565b34801561036457600080fd5b50609754610378906001600160a01b031681565b6040516001600160a01b03909116815260200161020a565b34801561039c57600080fd5b506103786103ab36600461216a565b610776565b3480156103bc57600080fd5b5061033661078b565b3480156103d157600080fd5b506103366103e03660046120cb565b610809565b3480156103f157600080fd5b506102766101605481565b61033661040a366004612241565b610971565b34801561041b57600080fd5b50610276610a41565b34801561043057600080fd5b50610233606554610100900460ff1660021490565b34801561045157600080fd5b506103366104603660046122c5565b610af4565b34801561047157600080fd5b50610276610480366004612138565b6001600160a01b0316600090815261012d602052604090205490565b3480156104a857600080fd5b50610336610c95565b3480156104bd57600080fd5b5061015f54610378906001600160a01b031681565b3480156104de57600080fd5b5060fb54610378906001600160a01b031681565b3480156104fe57600080fd5b50610336610ca9565b34801561051357600080fd5b50610378610d22565b34801561052857600080fd5b506101fd610d36565b34801561053d57600080fd5b5061033661054c3660046120cb565b610d48565b34801561055d57600080fd5b5061023361056c3660046120cb565b610eda565b34801561057d57600080fd5b5061037861058c36600461236f565b610f60565b34801561059d57600080fd5b506102336105ac3660046120cb565b610f6d565b3480156105bd57600080fd5b506103366105cc36600461239b565b610f7b565b3480156105dd57600080fd5b506102766105ec3660046123c7565b6110d9565b3480156105fd57600080fd5b5061033661060c366004612138565b611105565b606061062761061e61117b565b6101605461120e565b905090565b60003361063a818585611242565b60019150505b92915050565b600033610654858285611367565b61065f8585856113e1565b60019150505b9392505050565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100961630036106bd5760405162461bcd60e51b81526004016106b490612400565b60405180910390fd5b7f00000000000000000000000001670080000000000000000000000000000100966001600160a01b0316610706600080516020612749833981519152546001600160a01b031690565b6001600160a01b03161461072c5760405162461bcd60e51b81526004016106b49061244c565b61073581611599565b60408051600080825260208201909252610751918391906115a1565b50565b60003361063a81858561076783836110d9565b6107719190612498565b611242565b6000610783848484611711565b949350505050565b61079f606554610100900460ff1660021490565b6107bc5760405163bae6e2a960e01b815260040160405180910390fd5b6107c46117fb565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60655460ff16600119016108305760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055610851606554610100900460ff1660021490565b1561086f5760405163bae6e2a960e01b815260040160405180910390fd5b60fb546001600160a01b031615801590610893575060fb54600160a01b900460ff16155b156108b15760405163b19aa30f60e01b815260040160405180910390fd5b60fb546001600160a01b0316330361090c5760fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a3610956565b6109256a195c98cc8c17dd985d5b1d60aa1b6001610f60565b6001600160a01b0316336001600160a01b031614610956576040516361fad54f60e11b815260040160405180910390fd5b610960828261185a565b50506065805460ff19166001179055565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100961630036109b95760405162461bcd60e51b81526004016106b490612400565b7f00000000000000000000000001670080000000000000000000000000000100966001600160a01b0316610a02600080516020612749833981519152546001600160a01b031690565b6001600160a01b031614610a285760405162461bcd60e51b81526004016106b49061244c565b610a3182611599565b610a3d828260016115a1565b5050565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000100961614610ae15760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016106b4565b5060008051602061274983398151915290565b600054610100900460ff1615808015610b145750600054600160ff909116105b80610b2e5750303b158015610b2e575060005460ff166001145b610b915760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016106b4565b6000805460ff191660011790558015610bb4576000805461ff0019166101001790555b6001600160a01b0386161580610bc8575084155b80610bd257504685145b80610bdc57508251155b80610be657508151155b15610c045760405163c118d2f360e01b815260040160405180910390fd5b610c0d87611864565b610c178284611875565b61015f805461016087905560ff8616600160a01b026001600160a81b03199091166001600160a01b038916171790558015610c8c576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610c9d6117fb565b610ca760006118a6565b565b610cbd606554610100900460ff1660021490565b15610cdb5760405163bae6e2a960e01b815260040160405180910390fd5b610ce36117fb565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016107ff565b60006106276033546001600160a01b031690565b6060610627610d436118f8565b611908565b60655460ff1660011901610d6f5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055610d90606554610100900460ff1660021490565b15610dae5760405163bae6e2a960e01b815260040160405180910390fd5b60fb546001600160a01b031615801590610dd2575060fb54600160a01b900460ff16155b15610e865760fb546040518281526001600160a01b038481169216907f638edf84937fb2534b47cac985ea84d6ea4f4076315b56ea1c784d26b87e2bcb9060200160405180910390a360fb546040516340c10f1960e01b81526001600160a01b03848116600483015260248201849052909116906340c10f1990604401600060405180830381600087803b158015610e6957600080fd5b505af1158015610e7d573d6000803e3d6000fd5b50505050610ed0565b610e9f6a195c98cc8c17dd985d5b1d60aa1b6001610f60565b6001600160a01b0316336001600160a01b031614610ed057604051630d85cccf60e11b815260040160405180910390fd5b6109608282611931565b60003381610ee882866110d9565b905083811015610f485760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016106b4565b610f558286868403611242565b506001949350505050565b6000610665468484611711565b60003361063a8185856113e1565b610f8f606554610100900460ff1660021490565b15610fad5760405163bae6e2a960e01b815260040160405180910390fd5b6a195c98cc8c17dd985d5b1d60aa1b610fc4610d22565b6001600160a01b0316336001600160a01b0316141580156110015750610feb816001610f60565b6001600160a01b0316336001600160a01b031614155b1561101f57604051630d85cccf60e11b815260040160405180910390fd5b60fb546001600160a01b03848116911614801561104e575060fb60149054906101000a900460ff161515821515145b1561106c5760405163b253fdfd60e01b815260040160405180910390fd5b60fb80546001600160a01b0385166001600160a81b03199091168117600160a01b851515908102919091179092556040805191825260208201929092527fa6b6f959792843a48d9d03d13595f2de7c86ae0ce12ef0fa759dd911b205e565910160405180910390a1505050565b6001600160a01b03918216600090815261012e6020908152604080832093909416825291909152205490565b61110d6117fb565b6001600160a01b0381166111725760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106b4565b610751816118a6565b6060610130805461118b906124b9565b80601f01602080910402602001604051908101604052809291908181526020018280546111b7906124b9565b80156112045780601f106111d957610100808354040283529160200191611204565b820191906000526020600020905b8154815290600101906020018083116111e757829003601f168201915b5050505050905090565b60608261121a8361193b565b60405160200161122b9291906124f3565b604051602081830303815290604052905092915050565b6001600160a01b0383166112a45760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016106b4565b6001600160a01b0382166113055760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016106b4565b6001600160a01b03838116600081815261012e602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061137384846110d9565b905060001981146113db57818110156113ce5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016106b4565b6113db8484848403611242565b50505050565b6001600160a01b0383166114455760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016106b4565b6001600160a01b0382166114a75760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016106b4565b6114b28383836119ce565b6001600160a01b038316600090815261012d60205260409020548181101561152b5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016106b4565b6001600160a01b03808516600081815261012d602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061158c9086815260200190565b60405180910390a36113db565b6107516117fb565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156115d9576115d483611a29565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611633575060408051601f3d908101601f1916820190925261163091810190612554565b60015b6116965760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016106b4565b60008051602061274983398151915281146117055760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016106b4565b506115d4838383611ac5565b6097546000906001600160a01b031661173d57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611796573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ba919061256d565b9050811580156117d157506001600160a01b038116155b1561066557836117e08461193b565b604051630d69e23960e41b81526004016106b492919061258a565b33611804610d22565b6001600160a01b031614610ca75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106b4565b610a3d8282611aea565b61186c611bb9565b61075181611bd2565b600054610100900460ff1661189c5760405162461bcd60e51b81526004016106b4906125ad565b610a3d8282611c1c565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060610131805461118b906124b9565b60608160405160200161191b91906125f8565b6040516020818303038152906040529050919050565b610a3d8282611c5e565b6060600061194883611da1565b600101905060008167ffffffffffffffff811115611968576119686121b5565b6040519080825280601f01601f191660200182016040528015611992576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461199c57509392505050565b306001600160a01b038316036119f757604051630183150560e21b815260040160405180910390fd5b611a0b606554610100900460ff1660021490565b156115d45760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0381163b611a965760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016106b4565b60008051602061274983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611ace83611e79565b600082511180611adb5750805b156115d4576113db8383611eb9565b6001600160a01b038216611b405760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106b4565b611b4c600083836119ce565b8061012f6000828254611b5f9190612498565b90915550506001600160a01b038216600081815261012d60209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b611bc1611ede565b6065805461ffff1916610101179055565b67ffffffffffffffff4610611bfa5760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16611c435760405162461bcd60e51b81526004016106b4906125ad565b610130611c50838261266c565b506101316115d4828261266c565b6001600160a01b038216611cbe5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016106b4565b611cca826000836119ce565b6001600160a01b038216600090815261012d602052604090205481811015611d3f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016106b4565b6001600160a01b038316600081815261012d60209081526040808320868603905561012f80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611de05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611e0c576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611e2a57662386f26fc10000830492506010015b6305f5e1008310611e42576305f5e100830492506008015b6127108310611e5657612710830492506004015b60648310611e68576064830492506002015b600a83106106405760010192915050565b611e8281611a29565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060610665838360405180606001604052806027815260200161276960279139611f0d565b600054610100900460ff16611f055760405162461bcd60e51b81526004016106b4906125ad565b610ca7611f85565b6060600080856001600160a01b031685604051611f2a919061272c565b600060405180830381855af49150503d8060008114611f65576040519150601f19603f3d011682016040523d82523d6000602084013e611f6a565b606091505b5091509150611f7b86838387611fb5565b9695505050505050565b600054610100900460ff16611fac5760405162461bcd60e51b81526004016106b4906125ad565b610ca7336118a6565b6060831561202457825160000361201d576001600160a01b0385163b61201d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016106b4565b5081610783565b61078383838151156120395781518083602001fd5b8060405162461bcd60e51b81526004016106b491906120a3565b60005b8381101561206e578181015183820152602001612056565b50506000910152565b6000815180845261208f816020860160208601612053565b601f01601f19169290920160200192915050565b6020815260006106656020830184612077565b6001600160a01b038116811461075157600080fd5b600080604083850312156120de57600080fd5b82356120e9816120b6565b946020939093013593505050565b60008060006060848603121561210c57600080fd5b8335612117816120b6565b92506020840135612127816120b6565b929592945050506040919091013590565b60006020828403121561214a57600080fd5b8135610665816120b6565b8035801515811461216557600080fd5b919050565b60008060006060848603121561217f57600080fd5b833567ffffffffffffffff8116811461219757600080fd5b9250602084013591506121ac60408501612155565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156121e6576121e66121b5565b604051601f8501601f19908116603f0116810190828211818310171561220e5761220e6121b5565b8160405280935085815286868601111561222757600080fd5b858560208301376000602087830101525050509392505050565b6000806040838503121561225457600080fd5b823561225f816120b6565b9150602083013567ffffffffffffffff81111561227b57600080fd5b8301601f8101851361228c57600080fd5b61229b858235602084016121cb565b9150509250929050565b600082601f8301126122b657600080fd5b610665838335602085016121cb565b60008060008060008060c087890312156122de57600080fd5b86356122e9816120b6565b955060208701356122f9816120b6565b945060408701359350606087013560ff8116811461231657600080fd5b9250608087013567ffffffffffffffff8082111561233357600080fd5b61233f8a838b016122a5565b935060a089013591508082111561235557600080fd5b5061236289828a016122a5565b9150509295509295509295565b6000806040838503121561238257600080fd5b8235915061239260208401612155565b90509250929050565b600080604083850312156123ae57600080fd5b82356123b9816120b6565b915061239260208401612155565b600080604083850312156123da57600080fd5b82356123e5816120b6565b915060208301356123f5816120b6565b809150509250929050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b8082018082111561064057634e487b7160e01b600052601160045260246000fd5b600181811c908216806124cd57607f821691505b6020821081036124ed57634e487b7160e01b600052602260045260246000fd5b50919050565b670213934b233b2b2160c51b815260008351612516816008850160208801612053565b634051c55b60df1b600891840191820152835161253a81600d840160208801612053565b602960f81b600d9290910191820152600e01949350505050565b60006020828403121561256657600080fd5b5051919050565b60006020828403121561257f57600080fd5b8151610665816120b6565b67ffffffffffffffff831681526040602082015260006107836040830184612077565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000825161260a818460208701612053565b610b9d60f21b920191825250600201919050565b601f8211156115d457600081815260208120601f850160051c810160208610156126455750805b601f850160051c820191505b8181101561266457828155600101612651565b505050505050565b815167ffffffffffffffff811115612686576126866121b5565b61269a8161269484546124b9565b8461261e565b602080601f8311600181146126cf57600084156126b75750858301515b600019600386901b1c1916600185901b178555612664565b600085815260208120601f198616915b828110156126fe578886015182559484019460019091019084016126df565b508582101561271c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000825161273e818460208701612053565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212205bc683190212156508762d7a87d9b18bef7321f0d9ea785d029d1bf1541516fb64736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010097": { + "storage": {}, + "code": "0x6080604052600436106101d85760003560e01c80636352211e116101025780639dc29fac11610095578063c87b56dd11610064578063c87b56dd14610554578063d1399b1a14610582578063e985e9c5146105a2578063f2fde38b146105ec57600080fd5b80639dc29fac146104d4578063a22cb465146104f4578063a86f9d9e14610514578063b88d4fde1461053457600080fd5b80637cf8ed0d116100d15780637cf8ed0d1461046b5780638456cb591461048c5780638da5cb5b146104a157806395d89b41146104bf57600080fd5b80636352211e146103d157806367e828bf146103f157806370a0823114610436578063715018a61461045657600080fd5b80633eb6b8cf1161017a57806349d126051161014957806349d12605146103635780634f1ef2861461038857806352d1902d1461039b5780635c975abb146103b057600080fd5b80633eb6b8cf146102ee5780633f4ba83a1461030e57806340c10f191461032357806342842e0e1461034357600080fd5b8063095ea7b3116101b6578063095ea7b31461026c57806323b872dd1461028e5780633659cfe6146102ae5780633ab76e9f146102ce57600080fd5b806301ffc9a7146101dd57806306fdde0314610212578063081812fc14610234575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004612111565b61060c565b60405190151581526020015b60405180910390f35b34801561021e57600080fd5b5061022761065e565b604051610209919061217e565b34801561024057600080fd5b5061025461024f366004612191565b610679565b6040516001600160a01b039091168152602001610209565b34801561027857600080fd5b5061028c6102873660046121bf565b6106a1565b005b34801561029a57600080fd5b5061028c6102a93660046121eb565b6107bb565b3480156102ba57600080fd5b5061028c6102c936600461222c565b6107ec565b3480156102da57600080fd5b50609754610254906001600160a01b031681565b3480156102fa57600080fd5b5061025461030936600461225e565b6108cb565b34801561031a57600080fd5b5061028c6108e2565b34801561032f57600080fd5b5061028c61033e3660046121bf565b610960565b34801561034f57600080fd5b5061028c61035e3660046121eb565b610a2e565b34801561036f57600080fd5b5061037a6101605481565b604051908152602001610209565b61028c61039636600461234c565b610a49565b3480156103a757600080fd5b5061037a610b19565b3480156103bc57600080fd5b506101fd606554610100900460ff1660021490565b3480156103dd57600080fd5b506102546103ec366004612191565b610bcc565b3480156103fd57600080fd5b5061041761015f54610160546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610209565b34801561044257600080fd5b5061037a61045136600461222c565b610c2d565b34801561046257600080fd5b5061028c610cb4565b34801561047757600080fd5b5061015f54610254906001600160a01b031681565b34801561049857600080fd5b5061028c610cc8565b3480156104ad57600080fd5b506033546001600160a01b0316610254565b3480156104cb57600080fd5b50610227610d41565b3480156104e057600080fd5b5061028c6104ef3660046121bf565b610d53565b34801561050057600080fd5b5061028c61050f36600461239c565b610e48565b34801561052057600080fd5b5061025461052f3660046123d1565b610e53565b34801561054057600080fd5b5061028c61054f3660046123f4565b610e60565b34801561056057600080fd5b5061022761056f366004612191565b5060408051602081019091526000815290565b34801561058e57600080fd5b5061028c61059d366004612460565b610e98565b3480156105ae57600080fd5b506101fd6105bd3660046124f3565b6001600160a01b0391821660009081526101326020908152604080832093909416825291909152205460ff1690565b3480156105f857600080fd5b5061028c61060736600461222c565b61102b565b60006001600160e01b031982166380ac58cd60e01b148061063d57506001600160e01b03198216635b5e139f60e01b145b8061065857506301ffc9a760e01b6001600160e01b03198316145b92915050565b606061067461066b6110a1565b61016054611134565b905090565b600061068482611168565b50600090815261013160205260409020546001600160a01b031690565b60006106ac82610bcc565b9050806001600160a01b0316836001600160a01b03160361071e5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b038216148061073a575061073a81336105bd565b6107ac5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610715565b6107b683836111c8565b505050565b6107c53382611237565b6107e15760405162461bcd60e51b81526004016107159061252c565b6107b68383836112b7565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100971630036108345760405162461bcd60e51b815260040161071590612579565b7f00000000000000000000000001670080000000000000000000000000000100976001600160a01b031661087d600080516020612980833981519152546001600160a01b031690565b6001600160a01b0316146108a35760405162461bcd60e51b8152600401610715906125c5565b6108ac8161142b565b604080516000808252602082019092526108c891839190611433565b50565b60006108d884848461159e565b90505b9392505050565b6108f6606554610100900460ff1660021490565b6109135760405163bae6e2a960e01b815260040160405180910390fd5b61091b611688565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60655460ff16600119016109875760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff191660021790556109a8606554610100900460ff1660021490565b156109c65760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b6109e1816001610e53565b6001600160a01b0316336001600160a01b031614610a1257604051630d85cccf60e11b815260040160405180910390fd5b610a1c83836116e2565b50506065805460ff1916600117905550565b6107b683838360405180602001604052806000815250610e60565b6001600160a01b037f0000000000000000000000000167008000000000000000000000000000010097163003610a915760405162461bcd60e51b815260040161071590612579565b7f00000000000000000000000001670080000000000000000000000000000100976001600160a01b0316610ada600080516020612980833981519152546001600160a01b031690565b6001600160a01b031614610b005760405162461bcd60e51b8152600401610715906125c5565b610b098261142b565b610b1582826001611433565b5050565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000100971614610bb95760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610715565b5060008051602061298083398151915290565b600081815261012f60205260408120546001600160a01b0316806106585760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610715565b60006001600160a01b038216610c975760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610715565b506001600160a01b03166000908152610130602052604090205490565b610cbc611688565b610cc6600061187f565b565b610cdc606554610100900460ff1660021490565b15610cfa5760405163bae6e2a960e01b815260040160405180910390fd5b610d02611688565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610956565b6060610674610d4e6118d1565b6118e1565b60655460ff1660011901610d7a5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055610d9b606554610100900460ff1660021490565b15610db95760405163bae6e2a960e01b815260040160405180910390fd5b6b195c98cdcc8c57dd985d5b1d60a21b610dd4816001610e53565b6001600160a01b0316336001600160a01b031614610e0557604051630d85cccf60e11b815260040160405180910390fd5b826001600160a01b0316610e1883610bcc565b6001600160a01b031614610e3f5760405163358bf3d960e01b815260040160405180910390fd5b610a1c8261190a565b610b153383836119b0565b60006108db46848461159e565b610e6a3383611237565b610e865760405162461bcd60e51b81526004016107159061252c565b610e9284848484611a7f565b50505050565b600054610100900460ff1615808015610eb85750600054600160ff909116105b80610ed25750303b158015610ed2575060005460ff166001145b610f355760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610715565b6000805460ff191660011790558015610f58576000805461ff0019166101001790555b6001600160a01b0385161580610f6c575083155b80610f7657504684145b80610f8057508251155b80610f8a57508151155b15610fa85760405163c118d2f360e01b815260040160405180910390fd5b610fb186611ab2565b610fbb8284611ac3565b61015f80546001600160a01b0319166001600160a01b0387161790556101608490558015611023576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b611033611688565b6001600160a01b0381166110985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610715565b6108c88161187f565b606061012d80546110b190612611565b80601f01602080910402602001604051908101604052809291908181526020018280546110dd90612611565b801561112a5780601f106110ff5761010080835404028352916020019161112a565b820191906000526020600020905b81548152906001019060200180831161110d57829003601f168201915b5050505050905090565b60608261114083611af4565b60405160200161115192919061264b565b604051602081830303815290604052905092915050565b600081815261012f60205260409020546001600160a01b03166108c85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610715565b60008181526101316020526040902080546001600160a01b0319166001600160a01b03841690811790915581906111fe82610bcc565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061124383610bcc565b9050806001600160a01b0316846001600160a01b0316148061128b57506001600160a01b038082166000908152610132602090815260408083209388168352929052205460ff165b806112af5750836001600160a01b03166112a484610679565b6001600160a01b0316145b949350505050565b826001600160a01b03166112ca82610bcc565b6001600160a01b0316146112f05760405162461bcd60e51b8152600401610715906126ac565b6001600160a01b0382166113525760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610715565b61135f8383836001611b87565b826001600160a01b031661137282610bcc565b6001600160a01b0316146113985760405162461bcd60e51b8152600401610715906126ac565b60008181526101316020908152604080832080546001600160a01b03199081169091556001600160a01b03878116808652610130855283862080546000190190559087168086528386208054600101905586865261012f90945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6108c8611688565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611466576107b683611be2565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156114c0575060408051601f3d908101601f191682019092526114bd918101906126f1565b60015b6115235760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610715565b60008051602061298083398151915281146115925760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610715565b506107b6838383611c7e565b6097546000906001600160a01b03166115ca57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b815267ffffffffffffffff86166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611623573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611647919061270a565b90508115801561165e57506001600160a01b038116155b156108db578361166d84611af4565b604051630d69e23960e41b8152600401610715929190612727565b6033546001600160a01b03163314610cc65760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610715565b6001600160a01b0382166117385760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610715565b600081815261012f60205260409020546001600160a01b03161561179e5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610715565b6117ac600083836001611b87565b600081815261012f60205260409020546001600160a01b0316156118125760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610715565b6001600160a01b0382166000818152610130602090815260408083208054600101905584835261012f90915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606061012e80546110b190612611565b6060816040516020016118f4919061274a565b6040516020818303038152906040529050919050565b600061191582610bcc565b9050611925816000846001611b87565b61192e82610bcc565b60008381526101316020908152604080832080546001600160a01b03199081169091556001600160a01b0385168085526101308452828520805460001901905587855261012f909352818420805490911690555192935084927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b816001600160a01b0316836001600160a01b031603611a115760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610715565b6001600160a01b0383811660008181526101326020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611a8a8484846112b7565b611a9684848484611ca3565b610e925760405162461bcd60e51b815260040161071590612770565b611aba611da4565b6108c881611dbd565b600054610100900460ff16611aea5760405162461bcd60e51b8152600401610715906127c2565b610b158282611e07565b60606000611b0183611e49565b600101905060008167ffffffffffffffff811115611b2157611b216122a9565b6040519080825280601f01601f191660200182016040528015611b4b576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611b5557509392505050565b306001600160a01b03841603611bb057604051630183150560e21b815260040160405180910390fd5b611bc4606554610100900460ff1660021490565b15610e925760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0381163b611c4f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610715565b60008051602061298083398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611c8783611f21565b600082511180611c945750805b156107b657610e928383611f61565b60006001600160a01b0384163b15611d9957604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290611ce790339089908890889060040161280d565b6020604051808303816000875af1925050508015611d22575060408051601f3d908101601f19168201909252611d1f91810190612840565b60015b611d7f573d808015611d50576040519150601f19603f3d011682016040523d82523d6000602084013e611d55565b606091505b508051600003611d775760405162461bcd60e51b815260040161071590612770565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506112af565b506001949350505050565b611dac611f86565b6065805461ffff1916610101179055565b67ffffffffffffffff4610611de55760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16611e2e5760405162461bcd60e51b8152600401610715906127c2565b61012d611e3b83826128a3565b5061012e6107b682826128a3565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310611e885772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310611eb4576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310611ed257662386f26fc10000830492506010015b6305f5e1008310611eea576305f5e100830492506008015b6127108310611efe57612710830492506004015b60648310611f10576064830492506002015b600a83106106585760010192915050565b611f2a81611be2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606108db83836040518060600160405280602781526020016129a060279139611fb5565b600054610100900460ff16611fad5760405162461bcd60e51b8152600401610715906127c2565b610cc661202d565b6060600080856001600160a01b031685604051611fd29190612963565b600060405180830381855af49150503d806000811461200d576040519150601f19603f3d011682016040523d82523d6000602084013e612012565b606091505b50915091506120238683838761205d565b9695505050505050565b600054610100900460ff166120545760405162461bcd60e51b8152600401610715906127c2565b610cc63361187f565b606083156120cc5782516000036120c5576001600160a01b0385163b6120c55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610715565b50816112af565b6112af83838151156120e15781518083602001fd5b8060405162461bcd60e51b8152600401610715919061217e565b6001600160e01b0319811681146108c857600080fd5b60006020828403121561212357600080fd5b81356108db816120fb565b60005b83811015612149578181015183820152602001612131565b50506000910152565b6000815180845261216a81602086016020860161212e565b601f01601f19169290920160200192915050565b6020815260006108db6020830184612152565b6000602082840312156121a357600080fd5b5035919050565b6001600160a01b03811681146108c857600080fd5b600080604083850312156121d257600080fd5b82356121dd816121aa565b946020939093013593505050565b60008060006060848603121561220057600080fd5b833561220b816121aa565b9250602084013561221b816121aa565b929592945050506040919091013590565b60006020828403121561223e57600080fd5b81356108db816121aa565b8035801515811461225957600080fd5b919050565b60008060006060848603121561227357600080fd5b833567ffffffffffffffff8116811461228b57600080fd5b9250602084013591506122a060408501612249565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126122d057600080fd5b813567ffffffffffffffff808211156122eb576122eb6122a9565b604051601f8301601f19908116603f01168101908282118183101715612313576123136122a9565b8160405283815286602085880101111561232c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561235f57600080fd5b823561236a816121aa565b9150602083013567ffffffffffffffff81111561238657600080fd5b612392858286016122bf565b9150509250929050565b600080604083850312156123af57600080fd5b82356123ba816121aa565b91506123c860208401612249565b90509250929050565b600080604083850312156123e457600080fd5b823591506123c860208401612249565b6000806000806080858703121561240a57600080fd5b8435612415816121aa565b93506020850135612425816121aa565b925060408501359150606085013567ffffffffffffffff81111561244857600080fd5b612454878288016122bf565b91505092959194509250565b600080600080600060a0868803121561247857600080fd5b8535612483816121aa565b94506020860135612493816121aa565b935060408601359250606086013567ffffffffffffffff808211156124b757600080fd5b6124c389838a016122bf565b935060808801359150808211156124d957600080fd5b506124e6888289016122bf565b9150509295509295909350565b6000806040838503121561250657600080fd5b8235612511816121aa565b91506020830135612521816121aa565b809150509250929050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600181811c9082168061262557607f821691505b60208210810361264557634e487b7160e01b600052602260045260246000fd5b50919050565b670213934b233b2b2160c51b81526000835161266e81600885016020880161212e565b634051c55b60df1b600891840191820152835161269281600d84016020880161212e565b602960f81b600d9290910191820152600e01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60006020828403121561270357600080fd5b5051919050565b60006020828403121561271c57600080fd5b81516108db816121aa565b67ffffffffffffffff831681526040602082015260006108d86040830184612152565b6000825161275c81846020870161212e565b610b9d60f21b920191825250600201919050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061202390830184612152565b60006020828403121561285257600080fd5b81516108db816120fb565b601f8211156107b657600081815260208120601f850160051c810160208610156128845750805b601f850160051c820191505b8181101561102357828155600101612890565b815167ffffffffffffffff8111156128bd576128bd6122a9565b6128d1816128cb8454612611565b8461285d565b602080601f83116001811461290657600084156128ee5750858301515b600019600386901b1c1916600185901b178555611023565b600085815260208120601f198616915b8281101561293557888601518255948401946001909101908401612916565b50858210156129535787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000825161297581846020870161212e565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206a230c0fe38afc09a92c9b089efc0b32440c3a17558afb7d5f4c5525243985cf64736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010098": { + "storage": {}, + "code": "0x60806040526004361061019b5760003560e01c806352d1902d116100ec578063a22cb4651161008a578063e985e9c511610064578063e985e9c51461047f578063f242432a146104c9578063f2fde38b146104e9578063f5298aca1461050957600080fd5b8063a22cb4651461041f578063a86f9d9e1461043f578063d1399b1a1461045f57600080fd5b80637cf8ed0d116100c65780637cf8ed0d146103b65780638456cb59146103d75780638da5cb5b146103ec57806395d89b411461040a57600080fd5b806352d1902d1461036b5780635c975abb14610380578063715018a6146103a157600080fd5b80633659cfe6116101595780633f4ba83a116101335780633f4ba83a146102ff57806349d12605146103145780634e1273f41461032b5780634f1ef2861461035857600080fd5b80633659cfe6146102875780633ab76e9f146102a75780633eb6b8cf146102df57600080fd5b8062fdd58e146101a057806301ffc9a7146101d357806306fdde03146102035780630e89341c14610225578063156e29f6146102455780632eb2c2d614610267575b600080fd5b3480156101ac57600080fd5b506101c06101bb3660046122d0565b610529565b6040519081526020015b60405180910390f35b3480156101df57600080fd5b506101f36101ee366004612312565b6105c5565b60405190151581526020016101ca565b34801561020f57600080fd5b50610218610615565b6040516101ca919061237f565b34801561023157600080fd5b50610218610240366004612392565b6106b4565b34801561025157600080fd5b506102656102603660046123ab565b610749565b005b34801561027357600080fd5b50610265610282366004612529565b61082a565b34801561029357600080fd5b506102656102a23660046125d6565b610876565b3480156102b357600080fd5b506097546102c7906001600160a01b031681565b6040516001600160a01b0390911681526020016101ca565b3480156102eb57600080fd5b506102c76102fa366004612608565b610955565b34801561030b57600080fd5b5061026561096c565b34801561032057600080fd5b506101c06101605481565b34801561033757600080fd5b5061034b610346366004612652565b6109ea565b6040516101ca9190612759565b61026561036636600461276c565b610b13565b34801561037757600080fd5b506101c0610be3565b34801561038c57600080fd5b506101f3606554610100900460ff1660021490565b3480156103ad57600080fd5b50610265610c97565b3480156103c257600080fd5b5061015f546102c7906001600160a01b031681565b3480156103e357600080fd5b50610265610cab565b3480156103f857600080fd5b506033546001600160a01b03166102c7565b34801561041657600080fd5b50610218610d24565b34801561042b57600080fd5b5061026561043a3660046127b1565b610dba565b34801561044b57600080fd5b506102c761045a3660046127e6565b610dc5565b34801561046b57600080fd5b5061026561047a366004612809565b610dd2565b34801561048b57600080fd5b506101f361049a36600461286b565b6001600160a01b03918216600090815261012e6020908152604080832093909416825291909152205460ff1690565b3480156104d557600080fd5b506102656104e43660046128a4565b610f7b565b3480156104f557600080fd5b506102656105043660046125d6565b610fc0565b34801561051557600080fd5b506102656105243660046123ab565b611036565b60006001600160a01b0383166105995760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b50600081815261012d602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b14806105f657506001600160e01b031982166303a24d0760e21b145b806105bf57506301ffc9a760e01b6001600160e01b03198316146105bf565b60606106af61016280546106289061290c565b80601f01602080910402602001604051908101604052809291908181526020018280546106549061290c565b80156106a15780601f10610676576101008083540402835291602001916106a1565b820191906000526020600020905b81548152906001019060200180831161068457829003601f168201915b5050505050610160546110f4565b905090565b606061012f80546106c49061290c565b80601f01602080910402602001604051908101604052809291908181526020018280546106f09061290c565b801561073d5780601f106107125761010080835404028352916020019161073d565b820191906000526020600020905b81548152906001019060200180831161072057829003601f168201915b50505050509050919050565b60655460ff16600119016107705760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055610791606554610100900460ff1660021490565b156107af5760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b6107cb816001610dc5565b6001600160a01b0316336001600160a01b0316146107fc57604051630d85cccf60e11b815260040160405180910390fd5b61081784848460405180602001604052806000815250611128565b50506065805460ff191660011790555050565b6001600160a01b0385163314806108465750610846853361049a565b6108625760405162461bcd60e51b815260040161059090612946565b61086f858585858561124e565b5050505050565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100981630036108be5760405162461bcd60e51b815260040161059090612994565b7f00000000000000000000000001670080000000000000000000000000000100986001600160a01b0316610907600080516020612f39833981519152546001600160a01b031690565b6001600160a01b03161461092d5760405162461bcd60e51b8152600401610590906129e0565b61093681611436565b604080516000808252602082019092526109529183919061143e565b50565b60006109628484846115ae565b90505b9392505050565b610980606554610100900460ff1660021490565b61099d5760405163bae6e2a960e01b815260040160405180910390fd5b6109a5611697565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60608151835114610a4f5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610590565b600083516001600160401b03811115610a6a57610a6a6123e0565b604051908082528060200260200182016040528015610a93578160200160208202803683370190505b50905060005b8451811015610b0b57610ade858281518110610ab757610ab7612a2c565b6020026020010151858381518110610ad157610ad1612a2c565b6020026020010151610529565b828281518110610af057610af0612a2c565b6020908102919091010152610b0481612a58565b9050610a99565b509392505050565b6001600160a01b037f0000000000000000000000000167008000000000000000000000000000010098163003610b5b5760405162461bcd60e51b815260040161059090612994565b7f00000000000000000000000001670080000000000000000000000000000100986001600160a01b0316610ba4600080516020612f39833981519152546001600160a01b031690565b6001600160a01b031614610bca5760405162461bcd60e51b8152600401610590906129e0565b610bd382611436565b610bdf8282600161143e565b5050565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000100981614610c835760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610590565b50600080516020612f398339815191525b90565b610c9f611697565b610ca960006116f1565b565b610cbf606554610100900460ff1660021490565b15610cdd5760405163bae6e2a960e01b815260040160405180910390fd5b610ce5611697565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016109e0565b60606106af6101618054610d379061290c565b80601f0160208091040260200160405190810160405280929190818152602001828054610d639061290c565b8015610db05780601f10610d8557610100808354040283529160200191610db0565b820191906000526020600020905b815481529060010190602001808311610d9357829003601f168201915b5050505050611743565b610bdf33838361176c565b60006109654684846115ae565b600054610100900460ff1615808015610df25750600054600160ff909116105b80610e0c5750303b158015610e0c575060005460ff166001145b610e6f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610590565b6000805460ff191660011790558015610e92576000805461ff0019166101001790555b6001600160a01b0385161580610ea6575083155b80610eb057504684145b15610ece5760405163c118d2f360e01b815260040160405180910390fd5b610ed78661184d565b610eef6040518060200160405280600081525061185e565b61015f80546001600160a01b0319166001600160a01b038716179055610160849055610161610f1e8482612ab7565b50610162610f2c8382612ab7565b508015610f73576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b6001600160a01b038516331480610f975750610f97853361049a565b610fb35760405162461bcd60e51b815260040161059090612946565b61086f858585858561188e565b610fc8611697565b6001600160a01b03811661102d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610590565b610952816116f1565b60655460ff166001190161105d5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905561107e606554610100900460ff1660021490565b1561109c5760405163bae6e2a960e01b815260040160405180910390fd5b6c195c98cc4c4d4d57dd985d5b1d609a1b6110b8816001610dc5565b6001600160a01b0316336001600160a01b0316146110e957604051630d85cccf60e11b815260040160405180910390fd5b6108178484846119cc565b60608261110083611b62565b604051602001611111929190612b76565b604051602081830303815290604052905092915050565b6001600160a01b0384166111885760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610590565b33600061119485611bf4565b905060006111a185611bf4565b90506111b283600089858589611c3f565b600086815261012d602090815260408083206001600160a01b038b168452909152812080548792906111e5908490612bd7565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a461124583600089898989611c9a565b50505050505050565b81518351146112b05760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610590565b6001600160a01b0384166112d65760405162461bcd60e51b815260040161059090612bea565b336112e5818787878787611c3f565b60005b84518110156113d057600085828151811061130557611305612a2c565b60200260200101519050600085838151811061132357611323612a2c565b602090810291909101810151600084815261012d835260408082206001600160a01b038e1683529093529190912054909150818110156113755760405162461bcd60e51b815260040161059090612c2f565b600083815261012d602090815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906113b5908490612bd7565b92505081905550505050806113c990612a58565b90506112e8565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051611420929190612c79565b60405180910390a4610f73818787878787611df5565b610952611697565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156114765761147183611eb0565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156114d0575060408051601f3d908101601f191682019092526114cd91810190612ca7565b60015b6115335760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610590565b600080516020612f3983398151915281146115a25760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610590565b50611471838383611f4c565b6097546000906001600160a01b03166115da57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611632573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116569190612cc0565b90508115801561166d57506001600160a01b038116155b15610965578361167c84611b62565b604051630d69e23960e41b8152600401610590929190612cdd565b6033546001600160a01b03163314610ca95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610590565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060816040516020016117569190612cff565b6040516020818303038152906040529050919050565b816001600160a01b0316836001600160a01b0316036117df5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610590565b6001600160a01b03838116600081815261012e6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b611855611f77565b61095281611f90565b600054610100900460ff166118855760405162461bcd60e51b815260040161059090612d25565b61095281611fd9565b6001600160a01b0384166118b45760405162461bcd60e51b815260040161059090612bea565b3360006118c085611bf4565b905060006118cd85611bf4565b90506118dd838989858589611c3f565b600086815261012d602090815260408083206001600160a01b038c168452909152902054858110156119215760405162461bcd60e51b815260040161059090612c2f565b600087815261012d602090815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290611961908490612bd7565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46119c1848a8a8a8a8a611c9a565b505050505050505050565b6001600160a01b038316611a2e5760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610590565b336000611a3a84611bf4565b90506000611a4784611bf4565b9050611a6783876000858560405180602001604052806000815250611c3f565b600085815261012d602090815260408083206001600160a01b038a16845290915290205484811015611ae75760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610590565b600086815261012d602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4604080516020810190915260009052611245565b60606000611b6f83612009565b60010190506000816001600160401b03811115611b8e57611b8e6123e0565b6040519080825280601f01601f191660200182016040528015611bb8576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611bc257509392505050565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110611c2e57611c2e612a2c565b602090810291909101015292915050565b306001600160a01b03851603611c6857604051630183150560e21b815260040160405180910390fd5b611c7c606554610100900460ff1660021490565b15610f735760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0384163b15610f735760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190611cde9089908990889088908890600401612d70565b6020604051808303816000875af1925050508015611d19575060408051601f3d908101601f19168201909252611d1691810190612db5565b60015b611dc557611d25612dd2565b806308c379a003611d5e5750611d39612ded565b80611d445750611d60565b8060405162461bcd60e51b8152600401610590919061237f565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610590565b6001600160e01b0319811663f23a6e6160e01b146112455760405162461bcd60e51b815260040161059090612e76565b6001600160a01b0384163b15610f735760405163bc197c8160e01b81526001600160a01b0385169063bc197c8190611e399089908990889088908890600401612ebe565b6020604051808303816000875af1925050508015611e74575060408051601f3d908101601f19168201909252611e7191810190612db5565b60015b611e8057611d25612dd2565b6001600160e01b0319811663bc197c8160e01b146112455760405162461bcd60e51b815260040161059090612e76565b6001600160a01b0381163b611f1d5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610590565b600080516020612f3983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611f55836120e1565b600082511180611f625750805b1561147157611f718383612121565b50505050565b611f7f612146565b6065805461ffff1916610101179055565b6001600160401b034610611fb75760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff166120005760405162461bcd60e51b815260040161059090612d25565b61095281612175565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106120485772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612074576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061209257662386f26fc10000830492506010015b6305f5e10083106120aa576305f5e100830492506008015b61271083106120be57612710830492506004015b606483106120d0576064830492506002015b600a83106105bf5760010192915050565b6120ea81611eb0565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606109658383604051806060016040528060278152602001612f5960279139612182565b600054610100900460ff1661216d5760405162461bcd60e51b815260040161059090612d25565b610ca96121fa565b61012f610bdf8282612ab7565b6060600080856001600160a01b03168560405161219f9190612f1c565b600060405180830381855af49150503d80600081146121da576040519150601f19603f3d011682016040523d82523d6000602084013e6121df565b606091505b50915091506121f08683838761222a565b9695505050505050565b600054610100900460ff166122215760405162461bcd60e51b815260040161059090612d25565b610ca9336116f1565b60608315612299578251600003612292576001600160a01b0385163b6122925760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610590565b50816122a3565b6122a383836122ab565b949350505050565b815115611d445781518083602001fd5b6001600160a01b038116811461095257600080fd5b600080604083850312156122e357600080fd5b82356122ee816122bb565b946020939093013593505050565b6001600160e01b03198116811461095257600080fd5b60006020828403121561232457600080fd5b8135610965816122fc565b60005b8381101561234a578181015183820152602001612332565b50506000910152565b6000815180845261236b81602086016020860161232f565b601f01601f19169290920160200192915050565b6020815260006109656020830184612353565b6000602082840312156123a457600080fd5b5035919050565b6000806000606084860312156123c057600080fd5b83356123cb816122bb565b95602085013595506040909401359392505050565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b038111828210171561241b5761241b6123e0565b6040525050565b60006001600160401b0382111561243b5761243b6123e0565b5060051b60200190565b600082601f83011261245657600080fd5b8135602061246382612422565b60405161247082826123f6565b83815260059390931b850182019282810191508684111561249057600080fd5b8286015b848110156124ab5780358352918301918301612494565b509695505050505050565b600082601f8301126124c757600080fd5b81356001600160401b038111156124e0576124e06123e0565b6040516124f7601f8301601f1916602001826123f6565b81815284602083860101111561250c57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561254157600080fd5b853561254c816122bb565b9450602086013561255c816122bb565b935060408601356001600160401b038082111561257857600080fd5b61258489838a01612445565b9450606088013591508082111561259a57600080fd5b6125a689838a01612445565b935060808801359150808211156125bc57600080fd5b506125c9888289016124b6565b9150509295509295909350565b6000602082840312156125e857600080fd5b8135610965816122bb565b8035801515811461260357600080fd5b919050565b60008060006060848603121561261d57600080fd5b83356001600160401b038116811461263457600080fd5b925060208401359150612649604085016125f3565b90509250925092565b6000806040838503121561266557600080fd5b82356001600160401b038082111561267c57600080fd5b818501915085601f83011261269057600080fd5b8135602061269d82612422565b6040516126aa82826123f6565b83815260059390931b85018201928281019150898411156126ca57600080fd5b948201945b838610156126f15785356126e2816122bb565b825294820194908201906126cf565b9650508601359250508082111561270757600080fd5b5061271485828601612445565b9150509250929050565b600081518084526020808501945080840160005b8381101561274e57815187529582019590820190600101612732565b509495945050505050565b602081526000610965602083018461271e565b6000806040838503121561277f57600080fd5b823561278a816122bb565b915060208301356001600160401b038111156127a557600080fd5b612714858286016124b6565b600080604083850312156127c457600080fd5b82356127cf816122bb565b91506127dd602084016125f3565b90509250929050565b600080604083850312156127f957600080fd5b823591506127dd602084016125f3565b600080600080600060a0868803121561282157600080fd5b853561282c816122bb565b9450602086013561283c816122bb565b93506040860135925060608601356001600160401b038082111561285f57600080fd5b6125a689838a016124b6565b6000806040838503121561287e57600080fd5b8235612889816122bb565b91506020830135612899816122bb565b809150509250929050565b600080600080600060a086880312156128bc57600080fd5b85356128c7816122bb565b945060208601356128d7816122bb565b9350604086013592506060860135915060808601356001600160401b0381111561290057600080fd5b6125c9888289016124b6565b600181811c9082168061292057607f821691505b60208210810361294057634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612a6a57612a6a612a42565b5060010190565b601f82111561147157600081815260208120601f850160051c81016020861015612a985750805b601f850160051c820191505b81811015610f7357828155600101612aa4565b81516001600160401b03811115612ad057612ad06123e0565b612ae481612ade845461290c565b84612a71565b602080601f831160018114612b195760008415612b015750858301515b600019600386901b1c1916600185901b178555610f73565b600085815260208120601f198616915b82811015612b4857888601518255948401946001909101908401612b29565b5085821015612b665787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b670213934b233b2b2160c51b815260008351612b9981600885016020880161232f565b634051c55b60df1b6008918401918201528351612bbd81600d84016020880161232f565b602960f81b600d9290910191820152600e01949350505050565b808201808211156105bf576105bf612a42565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081526000612c8c604083018561271e565b8281036020840152612c9e818561271e565b95945050505050565b600060208284031215612cb957600080fd5b5051919050565b600060208284031215612cd257600080fd5b8151610965816122bb565b6001600160401b03831681526040602082015260006109626040830184612353565b60008251612d1181846020870161232f565b610b9d60f21b920191825250600201919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090612daa90830184612353565b979650505050505050565b600060208284031215612dc757600080fd5b8151610965816122fc565b600060033d1115610c945760046000803e5060005160e01c90565b600060443d1015612dfb5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612e2a57505050505090565b8285019150815181811115612e425750505050505090565b843d8701016020828501011115612e5c5750505050505090565b612e6b602082860101876123f6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b0386811682528516602082015260a060408201819052600090612eea9083018661271e565b8281036060840152612efc818661271e565b90508281036080840152612f108185612353565b98975050505050505050565b60008251612f2e81846020870161232f565b919091019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c815eff88d788d0412cf5780901f394979615e0cc721245a4ee4b95f2c5355b864736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x60806040526004361061012a5760003560e01c80638456cb59116100ab578063a354b9de1161006f578063a354b9de14610312578063a86f9d9e14610332578063cbb3ddf314610352578063e1c7392a14610366578063f19e207e1461037b578063f2fde38b146103a857600080fd5b80638456cb591461027f5780638da5cb5b14610294578063910af6ed146102b257806391f3f74b146102d2578063969e15a3146102f257600080fd5b80634f1ef286116100f25780634f1ef286146101f357806352d1902d146102065780635c975abb1461022957806366ca2bc01461024a578063715018a61461026a57600080fd5b806332676bc61461012f5780633659cfe6146101645780633ab76e9f146101865780633eb6b8cf146101be5780633f4ba83a146101de575b600080fd5b34801561013b57600080fd5b5061014f61014a3660046126d3565b6103c8565b60405190151581526020015b60405180910390f35b34801561017057600080fd5b5061018461017f3660046126ff565b61042c565b005b34801561019257600080fd5b506097546101a6906001600160a01b031681565b6040516001600160a01b03909116815260200161015b565b3480156101ca57600080fd5b506101a66101d9366004612746565b610514565b3480156101ea57600080fd5b5061018461052b565b610184610201366004612883565b6105a9565b34801561021257600080fd5b5061021b610679565b60405190815260200161015b565b34801561023557600080fd5b5061014f606554610100900460ff1660021490565b34801561025657600080fd5b5061021b6102653660046128d2565b61072c565b34801561027657600080fd5b50610184610763565b34801561028b57600080fd5b50610184610777565b3480156102a057600080fd5b506033546001600160a01b03166101a6565b3480156102be57600080fd5b5061014f6102cd3660046128eb565b6107f0565b3480156102de57600080fd5b5061021b6102ed366004612989565b610b0e565b3480156102fe57600080fd5b5061018461030d3660046126d3565b610b79565b34801561031e57600080fd5b5061014f61032d3660046126d3565b610c3b565b34801561033e57600080fd5b506101a661034d3660046129ca565b610c67565b34801561035e57600080fd5b50600061014f565b34801561037257600080fd5b50610184610c74565b34801561038757600080fd5b5061021b6103963660046126ff565b60fb6020526000908152604090205481565b3480156103b457600080fd5b506101846103c33660046126ff565b610d84565b60008181036103ea5760405163c7b4b9bf60e01b815260040160405180910390fd5b6001600160a01b0383166104115760405163985389db60e01b815260040160405180910390fd5b600061041e468585610b0e565b546001149150505b92915050565b6001600160a01b037f000000000000000000000000016700800000000000000000000000000000000516300361047d5760405162461bcd60e51b8152600401610474906129f6565b60405180910390fd5b7f00000000000000000000000001670080000000000000000000000000000000056001600160a01b03166104c6600080516020612e8c833981519152546001600160a01b031690565b6001600160a01b0316146104ec5760405162461bcd60e51b815260040161047490612a42565b6104f581610dfa565b6040805160008082526020820190925261051191839190610e02565b50565b6000610521848484610f72565b90505b9392505050565b61053f606554610100900460ff1660021490565b61055c5760405163bae6e2a960e01b815260040160405180910390fd5b61056461105b565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000000051630036105f15760405162461bcd60e51b8152600401610474906129f6565b7f00000000000000000000000001670080000000000000000000000000000000056001600160a01b031661063a600080516020612e8c833981519152546001600160a01b031690565b6001600160a01b0316146106605760405162461bcd60e51b815260040161047490612a42565b61066982610dfa565b61067582826001610e02565b5050565b6000306001600160a01b037f000000000000000000000000016700800000000000000000000000000000000516146107195760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610474565b50600080516020612e8c83398151915290565b600081810361074e5760405163c7b4b9bf60e01b815260040160405180910390fd5b610759463384610b0e565b6001815592915050565b61076b61105b565b61077560006110b5565b565b61078b606554610100900460ff1660021490565b156107a95760405163bae6e2a960e01b815260040160405180910390fd5b6107b161105b565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589060200161059f565b60006001600160a01b0385161580610806575083155b8061081857506001600160401b038616155b8061082b575046866001600160401b0316145b1561083857506000610b05565b600061084683850185612a8e565b80519091506001600160a01b031615806108635750604081015151155b15610872576000915050610b05565b60005b8160600151518110156108fd578160600151818151811061089857610898612c18565b6020026020010151602001516000801b036108b857600092505050610b05565b816060015181815181106108ce576108ce612c18565b602002602001015160400151516000036108ed57600092505050610b05565b6108f681612c44565b9050610875565b50805161090a9046610c3b565b610918576000915050610b05565b80516020820151604051638cfb045960e01b81526001600160401b0390911660048201526000916001600160a01b031690638cfb045990602401608060405180830381865afa15801561096f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109939190612c5d565b60600151905060008190036109ad57600092505050610b05565b60005b826060015151811015610ab2576000836060015182815181106109d5576109d5612c18565b60209081029190910181015180516001600160a01b0316600090815260fb909252604082205490925090819003610a1457600095505050505050610b05565b6000610a1f82611107565b90506000610a368285600001518660200151610b0e565b90506000610a7d82604051602001610a5091815260200190565b60408051601f19818403018152828201825260018352600160f81b6020840152908801519091908a611173565b905080610a9557600098505050505050505050610b05565b84602001519650505050505080610aab90612c44565b90506109b0565b50610b00610ac1898989610b0e565b604051602001610ad391815260200190565b60408051601f19818403018152828201825260018352600160f81b60208401529085015190919084611173565b925050505b95945050505050565b6040516514d251d3905360d21b60208201526001600160c01b031960c085901b1660268201526bffffffffffffffffffffffff19606084901b16602e820152604281018290526000906062016040516020818303038152906040528051906020012090509392505050565b610b8161105b565b6001600160a01b038216610ba857604051635963709b60e01b815260040160405180910390fd5b6001600160a01b038216600090815260fb6020526040902054818103610be1576040516389ad61c160e01b815260040160405180910390fd5b6001600160a01b038316600081815260fb602090815260409182902085905581518481529081018590527f7abb39ef31cf9e4e81ee30577a27909b031ee95c0459c22280fb8d3468c96fdf910160405180910390a2505050565b600081158015906105245750506001600160a01b0391909116600090815260fb60205260409020541490565b6000610524468484610f72565b600054610100900460ff1615808015610c945750600054600160ff909116105b80610cae5750303b158015610cae575060005460ff166001145b610d115760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610474565b6000805460ff191660011790558015610d34576000805461ff0019166101001790555b610d3c611199565b8015610511576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b610d8c61105b565b6001600160a01b038116610df15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610474565b610511816110b5565b61051161105b565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615610e3a57610e35836111b2565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610e94575060408051601f3d908101601f19168201909252610e9191810190612cb4565b60015b610ef75760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610474565b600080516020612e8c8339815191528114610f665760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610474565b50610e3583838361124e565b6097546000906001600160a01b0316610f9e57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a9190612ccd565b90508115801561103157506001600160a01b038116155b15610524578361104084611279565b604051630d69e23960e41b8152600401610474929190612d3a565b6033546001600160a01b031633146107755760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610474565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006001600160401b0382111561116f5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610474565b5090565b60008061117f8661130c565b905061118d8186868661133e565b9150505b949350505050565b6111a161137b565b6065805461ffff1916610101179055565b6001600160a01b0381163b61121f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610474565b600080516020612e8c83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611257836113aa565b6000825111806112645750805b15610e355761127383836113ea565b50505050565b606060006112868361140f565b60010190506000816001600160401b038111156112a5576112a5612784565b6040519080825280601f01601f1916602001820160405280156112cf576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a85049450846112d9575b509392505050565b6060818051906020012060405160200161132891815260200190565b6040516020818303038152906040529050919050565b600080600061134e8786866114e7565b9150915081801561137057508051602080830191909120875191880191909120145b979650505050505050565b600054610100900460ff166113a25760405162461bcd60e51b815260040161047490612d5c565b6107756115c2565b6113b3816111b2565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606105248383604051806060016040528060278152602001612eac602791396115f2565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061144e5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061147a576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061149857662386f26fc10000830492506010015b6305f5e10083106114b0576305f5e100830492506008015b61271083106114c457612710830492506004015b606483106114d6576064830492506002015b600a83106104265760010192915050565b6000606060006114f68561166a565b90506000806000611508848a8961175a565b8151929550909350915015808061151c5750815b6115685760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610474565b60008161158457604051806020016040528060008152506115b0565b6115b086611593600188612da7565b815181106115a3576115a3612c18565b6020026020010151611b7a565b919b919a509098505050505050505050565b600054610100900460ff166115e95760405162461bcd60e51b815260040161047490612d5c565b610775336110b5565b6060600080856001600160a01b03168560405161160f9190612dba565b600060405180830381855af49150503d806000811461164a576040519150601f19603f3d011682016040523d82523d6000602084013e61164f565b606091505b509150915061166086838387611ba1565b9695505050505050565b6060600061167783611c1a565b9050600081516001600160401b0381111561169457611694612784565b6040519080825280602002602001820160405280156116d957816020015b60408051808201909152606080825260208201528152602001906001900390816116b25790505b50905060005b825181101561130457600061170c8483815181106116ff576116ff612c18565b6020026020010151611c4d565b9050604051806040016040528061172283611c1a565b81526020018281525083838151811061173d5761173d612c18565b6020026020010181905250508061175390612c44565b90506116df565b60006060600080600061176c87611cd4565b90506000869050600080611793604051806040016040528060608152602001606081525090565b60005b8c51811015611b52578c81815181106117b1576117b1612c18565b6020026020010151915082846117c79190612dd6565b93506117d4600188612dd6565b96508360000361183157848260200151805190602001201461182c5760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b6044820152606401610474565b6118f3565b60208260200151511061189857848260200151805190602001201461182c5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610474565b846118a68360200151611e0c565b146118f35760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610474565b6118ff60106001612de9565b60ff168260000151510361196d5785518414611b5257600086858151811061192957611929612c18565b01602001518351805160f89290921c92506000918390811061194d5761194d612c18565b6020026020010151905061196081611e34565b9650600194505050611b42565b81515160011901611afa57600061198383611e6a565b905060008160008151811061199a5761199a612c18565b016020015160f81c905060006119b1600283612e02565b6119bc906002612e32565b905060006119cd848360ff16611e8e565b905060006119db8b8a611e8e565b905060006119e98383611ec4565b905060ff851660021480611a00575060ff85166003145b15611a3a57808351148015611a155750808251145b15611a2757611a24818b612dd6565b99505b50600160ff1b9950611b52945050505050565b60ff85161580611a4d575060ff85166001145b15611aa35782518114611a6d5750600160ff1b9950611b52945050505050565b611a948860000151600181518110611a8757611a87612c18565b6020026020010151611e34565b9a509750611b42945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b6064820152608401610474565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610474565b611b4b81612c44565b9050611796565b50600160ff1b841486611b658786611e8e565b909e909d50909b509950505050505050505050565b8051805160609161042691611b9190600190612da7565b815181106116ff576116ff612c18565b60608315611c10578251600003611c09576001600160a01b0385163b611c095760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610474565b5081611191565b6111918383611f3e565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061042690611f68565b60606000806000611c5d85612154565b919450925090506000816001811115611c7857611c78612e4b565b14611cc55760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610474565b610b058560200151848461249e565b6060600082516002611ce69190612e61565b6001600160401b03811115611cfd57611cfd612784565b6040519080825280601f01601f191660200182016040528015611d27576020820181803683370190505b50905060005b8351811015611e05576004848281518110611d4a57611d4a612c18565b01602001516001600160f81b031916901c82611d67836002612e61565b81518110611d7757611d77612c18565b60200101906001600160f81b031916908160001a9053506010848281518110611da257611da2612c18565b0160200151611db4919060f81c612e02565b60f81b82611dc3836002612e61565b611dce906001612dd6565b81518110611dde57611dde612c18565b60200101906001600160f81b031916908160001a905350611dfe81612c44565b9050611d2d565b5092915050565b6000602082511015611e2057506020015190565b818060200190518101906104269190612cb4565b60006060602083600001511015611e5557611e4e83612546565b9050611e61565b611e5e83611c4d565b90505b61052481611e0c565b6060610426611e8983600001516000815181106116ff576116ff612c18565b611cd4565b606082518210611ead5750604080516020810190915260008152610426565b6105248383848651611ebf9190612da7565b612551565b6000805b808451118015611ed85750808351115b8015611f295750828181518110611ef157611ef1612c18565b602001015160f81c60f81b6001600160f81b031916848281518110611f1857611f18612c18565b01602001516001600160f81b031916145b1561052457611f3781612c44565b9050611ec8565b815115611f4e5781518083602001fd5b8060405162461bcd60e51b81526004016104749190612e78565b6060600080611f7684612154565b91935090915060019050816001811115611f9257611f92612e4b565b14611fdf5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610474565b6040805160208082526104208201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081611ff85790505090506000835b865181101561214957602082106120915760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b6064820152608401610474565b6000806120ce6040518060400160405280858c600001516120b29190612da7565b8152602001858c602001516120c79190612dd6565b9052612154565b5091509150604051806040016040528083836120ea9190612dd6565b8152602001848b602001516120ff9190612dd6565b81525085858151811061211457612114612c18565b602090810291909101015261212a600185612dd6565b93506121368183612dd6565b6121409084612dd6565b92505050612025565b508152949350505050565b6000806000808460000151116121ac5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610474565b6020840151805160001a607f81116121d1576000600160009450945094505050612497565b60b7811161224d5760006121e6608083612da7565b90508087600001511161223b5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610474565b60019550935060009250612497915050565b60bf811161233c57600061226260b783612da7565b9050808760000151116122b75760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610474565b600183015160208290036101000a90046122d18183612dd6565b8851116123205760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610474565b61232b826001612dd6565b965094506000935061249792505050565b60f781116123b757600061235160c083612da7565b9050808760000151116123a65760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610474565b600195509350849250612497915050565b60006123c460f783612da7565b9050808760000151116124195760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610474565b600183015160208290036101000a90046124338183612dd6565b88511161247b5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b6044820152606401610474565b612486826001612dd6565b965094506001935061249792505050565b9193909250565b60606000826001600160401b038111156124ba576124ba612784565b6040519080825280601f01601f1916602001820160405280156124e4576020820181803683370190505b50905080516000036124f7579050610524565b8484016020820160005b85811015612519578281015182820152602001612501565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b6060610426826126a8565b60608161255f81601f612dd6565b101561259e5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610474565b826125a98382612dd6565b10156125e85760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b6044820152606401610474565b6125f28284612dd6565b845110156126365760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b6044820152606401610474565b606082158015612655576040519150600082526020820160405261269f565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561268e578051835260209283019201612676565b5050858452601f01601f1916604052505b50949350505050565b606061042682602001516000846000015161249e565b6001600160a01b038116811461051157600080fd5b600080604083850312156126e657600080fd5b82356126f1816126be565b946020939093013593505050565b60006020828403121561271157600080fd5b8135610524816126be565b6001600160401b038116811461051157600080fd5b8035801515811461274157600080fd5b919050565b60008060006060848603121561275b57600080fd5b83356127668161271c565b92506020840135915061277b60408501612731565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156127bc576127bc612784565b60405290565b604051606081016001600160401b03811182821017156127bc576127bc612784565b604051601f8201601f191681016001600160401b038111828210171561280c5761280c612784565b604052919050565b600082601f83011261282557600080fd5b81356001600160401b0381111561283e5761283e612784565b612851601f8201601f19166020016127e4565b81815284602083860101111561286657600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561289657600080fd5b82356128a1816126be565b915060208301356001600160401b038111156128bc57600080fd5b6128c885828601612814565b9150509250929050565b6000602082840312156128e457600080fd5b5035919050565b60008060008060006080868803121561290357600080fd5b853561290e8161271c565b9450602086013561291e816126be565b93506040860135925060608601356001600160401b038082111561294157600080fd5b818801915088601f83011261295557600080fd5b81358181111561296457600080fd5b89602082850101111561297657600080fd5b9699959850939650602001949392505050565b60008060006060848603121561299e57600080fd5b83356129a98161271c565b925060208401356129b9816126be565b929592945050506040919091013590565b600080604083850312156129dd57600080fd5b823591506129ed60208401612731565b90509250929050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60006020808385031215612aa157600080fd5b82356001600160401b0380821115612ab857600080fd5b9084019060808287031215612acc57600080fd5b612ad461279a565b8235612adf816126be565b815282840135612aee8161271c565b81850152604083013582811115612b0457600080fd5b612b1088828601612814565b60408301525060608084013583811115612b2957600080fd5b80850194505087601f850112612b3e57600080fd5b833583811115612b5057612b50612784565b8060051b612b5f8782016127e4565b918252858101870191878101908b841115612b7957600080fd5b88880192505b83831015612c0357823587811115612b975760008081fd5b8801808d03601f1901861315612bad5760008081fd5b612bb56127c2565b8a820135612bc2816126be565b815260408201358b8201528682013589811115612bdf5760008081fd5b612bed8f8d83860101612814565b6040830152508352509188019190880190612b7f565b93850193909352509198975050505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c5657612c56612c2e565b5060010190565b600060808284031215612c6f57600080fd5b612c7761279a565b8251612c828161271c565b81526020830151612c928161271c565b6020820152604083810151908201526060928301519281019290925250919050565b600060208284031215612cc657600080fd5b5051919050565b600060208284031215612cdf57600080fd5b8151610524816126be565b60005b83811015612d05578181015183820152602001612ced565b50506000910152565b60008151808452612d26816020860160208601612cea565b601f01601f19169290920160200192915050565b6001600160401b03831681526040602082015260006105216040830184612d0e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b8181038181111561042657610426612c2e565b60008251612dcc818460208701612cea565b9190910192915050565b8082018082111561042657610426612c2e565b60ff818116838216019081111561042657610426612c2e565b600060ff831680612e2357634e487b7160e01b600052601260045260246000fd5b8060ff84160691505092915050565b60ff828116828216039081111561042657610426612c2e565b634e487b7160e01b600052602160045260246000fd5b808202811582820484141761042657610426612c2e565b6020815260006105246020830184612d0e56fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220705188df6f705b59216fb40a6136900d0c74549bbe4d0406595394fc82f56f4f64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000000005": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x0000000000000000000000000000000000000000000000000000000000000101", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0xe1ea4bb003891464eed655f99574ebf9ed4b743aaa8730cc2f046fe77b7072a6": "0x0000000000000000000000000000000000000000000000000000000000028c60", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000000005" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x6080604052600436106101d85760003560e01c80638cfb045911610102578063c7b9690811610095578063f2fde38b11610064578063f2fde38b14610654578063f535bd5614610674578063f940e38514610695578063ff4d1815146106b557600080fd5b8063c7b9690814610579578063da69d3db146105a1578063dac5df78146105c1578063e8e2c5fb146105d857600080fd5b8063a86f9d9e116100d1578063a86f9d9e146104db578063b310e9e9146104fb578063c3f909d41461051b578063c7a2fc601461055957600080fd5b80638cfb0459146104125780638da5cb5b146104775780639ee512f214610495578063a7e022d1146104bb57600080fd5b80634f1ef2861161017a578063715018a611610149578063715018a61461037b5780638456cb59146103905780638551f41e146103a55780638aff87b2146103d357600080fd5b80634f1ef286146102f357806352d1902d14610306578063591aad8a1461031b5780635c975abb1461035a57600080fd5b80633659cfe6116101b65780633659cfe6146102645780633ab76e9f146102865780633eb6b8cf146102be5780633f4ba83a146102de57600080fd5b806310da3738146101dd57806323ac7136146102245780632f98047314610244575b600080fd5b3480156101e957600080fd5b506102117f92954368afd3caa1f3ce3ead0069c1af414054aefe1ef9aeacc1bf426222ce3881565b6040519081526020015b60405180910390f35b34801561023057600080fd5b5061021161023f3660046126ce565b6106d5565b34801561025057600080fd5b5060005b604051901515815260200161021b565b34801561027057600080fd5b5061028461027f366004612700565b610735565b005b34801561029257600080fd5b506097546102a6906001600160a01b031681565b6040516001600160a01b03909116815260200161021b565b3480156102ca57600080fd5b506102a66102d936600461272b565b61081d565b3480156102ea57600080fd5b50610284610834565b6102846103013660046127b3565b6108b2565b34801561031257600080fd5b50610211610982565b34801561032757600080fd5b5061033b61033636600461285a565b610a35565b6040805160ff909416845260208401929092529082015260600161021b565b34801561036657600080fd5b50610254606554610100900460ff1660021490565b34801561038757600080fd5b50610284610c70565b34801561039c57600080fd5b50610284610c84565b3480156103b157600080fd5b506102116103c0366004612890565b61012d6020526000908152604090205481565b3480156103df57600080fd5b5060fb546103fa90600160401b90046001600160401b031681565b6040516001600160401b03909116815260200161021b565b34801561041e57600080fd5b5061043261042d3660046126ce565b610cfd565b60405161021b919060006080820190506001600160401b0380845116835280602085015116602084015250604083015160408301526060830151606083015292915050565b34801561048357600080fd5b506033546001600160a01b03166102a6565b3480156104a157600080fd5b506102a671777735367b36bc9b61c50022d9d0700db4ec81565b3480156104c757600080fd5b506102116104d63660046128c2565b610da5565b3480156104e757600080fd5b506102a66104f63660046128f7565b610dd7565b34801561050757600080fd5b5061028461051636600461291c565b610ded565b34801561052757600080fd5b5060408051808201825263039387008082526008602092830190815283519182525160ff16918101919091520161021b565b34801561056557600080fd5b5061028461057436600461295c565b610fb0565b34801561058557600080fd5b50610130546103fa90600160401b90046001600160401b031681565b3480156105ad57600080fd5b506102846105bc3660046129e0565b61120a565b3480156105cd57600080fd5b5061021161012f5481565b3480156105e457600080fd5b506106296105f3366004612890565b61012e602052600090815260409020805460018201546002909201546001600160401b0380831693600160401b90930416919084565b604080516001600160401b03958616815294909316602085015291830152606082015260800161021b565b34801561066057600080fd5b5061028461066f366004612700565b6115d9565b34801561068057600080fd5b50610130546103fa906001600160401b031681565b3480156106a157600080fd5b506102846106b0366004612a28565b61164f565b3480156106c157600080fd5b5060fb546103fa906001600160401b031681565b600043826001600160401b0316106106ef57506000919050565b6106fb61010043612a6c565b826001600160401b03161061071857506001600160401b03164090565b506001600160401b0316600090815261012d602052604090205490565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100011630036107865760405162461bcd60e51b815260040161077d90612a7f565b60405180910390fd5b7f00000000000000000000000001670080000000000000000000000000000100016001600160a01b03166107cf600080516020612dca833981519152546001600160a01b031690565b6001600160a01b0316146107f55760405162461bcd60e51b815260040161077d90612acb565b6107fe8161179a565b6040805160008082526020820190925261081a918391906117a2565b50565b600061082a848484611912565b90505b9392505050565b610848606554610100900460ff1660021490565b6108655760405163bae6e2a960e01b815260040160405180910390fd5b61086d6119fb565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100011630036108fa5760405162461bcd60e51b815260040161077d90612a7f565b7f00000000000000000000000001670080000000000000000000000000000100016001600160a01b0316610943600080516020612dca833981519152546001600160a01b031690565b6001600160a01b0316146109695760405162461bcd60e51b815260040161077d90612acb565b6109728261179a565b61097e828260016117a2565b5050565b6000306001600160a01b037f00000000000000000000000001670080000000000000000000000000000100011614610a225760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000606482015260840161077d565b50600080516020612dca83398151915290565b60008060008360ff16600114158015610a5257508360ff16600214155b15610a705760405163bcd2d90d60e01b815260040160405180910390fd5b8360ff16600114610aa1577fc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5610ac3565b7f79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817985b915060008460ff16600114610af8577fad77eceea844778cb4376153fc8f06f12f1695df4585bf75bfb17ec19ce90818610b1a565b7fb4a95509ce05fe8d45987859a067780d16a367c0e2cacf79cd301b93fb7179405b905060008560ff16600114610b4f577f71620584f61c57e688bbd3fd7a39a036e588d962c4c830f3dacbc15c917e02f2610b71565b7f45b59254b0320fd853f3f38ac574999e91bd75fd5e6cab9c22c5e71fc6d276e45b82880192831001905060ff8616600103610bab57610ba48282600170014551231950b75fc4402da1732fc9bebe19611a34565b9250610c1a565b610bf37f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1610bee8484600170014551231950b75fc4402da1732fc9bebe19611a34565b611a83565b9092509050610c178282600170014551231950b75fc4402da1732fc9bebe19611a34565b92505b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610c6757610c5e8370014551231950b75fc4402da1732fc9bebe19612a6c565b92506001851894505b50509250925092565b610c786119fb565b610c826000611aa2565b565b610c98606554610100900460ff1660021490565b15610cb65760405163bae6e2a960e01b815260040160405180910390fd5b610cbe6119fb565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016108a8565b6040805160808101825260008082526020820181905291810182905260608101829052906001600160401b03831615610d365782610d4b565b61013054600160401b90046001600160401b03165b6001600160401b03908116600090815261012e6020908152604091829020825160808101845281548086168252600160401b9004909416918401919091526001810154918301919091526002015460608201529392505050565b6000610dcf610dc860408051808201909152630393870081526008602082015290565b8484611af4565b509392505050565b6000610de4468484611912565b90505b92915050565b600054610100900460ff1615808015610e0d5750600054600160ff909116105b80610e275750303b158015610e27575060005460ff166001145b610e8a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161077d565b6000805460ff191660011790558015610ead576000805461ff0019166101001790555b610eb78484611c2e565b600146111580610ece57506001600160401b034610155b15610eec576040516306cffa2760e01b815260040160405180910390fd5b4315610f395743600103610f20576000610f07600143612a6c565b600081815261012d602052604090209040905550610f39565b604051635a0f9e4160e11b815260040160405180910390fd5b610130805467ffffffffffffffff19166001600160401b038416179055610f5f43611c97565b5061012f558015610faa576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b60fb546001600160401b03848116600160401b9092041614610fe5576040516339985e7960e11b815260040160405180910390fd5b610ff96562726964676560d01b6000610dd7565b6001600160a01b0316336001600160a01b03161461102a57604051632efb161b60e21b815260040160405180910390fd5b6000336001600160a01b031663d0496d6a6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561106a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108e9190612b17565b60fb5460408201519192506001600160401b0391821691161415806110d457506033546001600160a01b03166001600160a01b031681602001516001600160a01b031614155b156110f257604051632efb161b60e21b815260040160405180910390fd5b6000306001600160a01b0316848460405161110e929190612b7f565b6000604051808303816000865af19150503d806000811461114b576040519150601f19603f3d011682016040523d82523d6000602084013e611150565b606091505b505090508061117257604051630103c9e160e11b815260040160405180910390fd5b61117c8385612b8f565b60fb80546001600160e01b03199290921691600160401b90046001600160401b03169060086111aa83612bbf565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167f3c5c4a24a5f3333977c7d675661b0611a16f3c611b9ea63c0be82f4ffa9174c560405160405180910390a35050505050565b60655460ff16600119016112315760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff19166002179055831580611249575082155b8061125b57506001600160401b038216155b80611276575043600114158015611276575063ffffffff8116155b156112945760405163053fd54760e01b815260040160405180910390fd5b3371777735367b36bc9b61c50022d9d0700db4ec146112c657604051636494e9f760e01b815260040160405180910390fd5b60001943016000806112d783611c97565b915091508161012f54146112fe5760405163d719258d60e01b815260040160405180910390fd5b600061131e60408051808201909152630393870081526008602082015290565b9050600061132d828888611af4565b610130805467ffffffffffffffff19166001600160401b03929092169190911790559050488114611371576040516336d54d4f60e11b815260040160405180910390fd5b61138d6d7369676e616c5f7365727669636560901b6000610dd7565b6001600160a01b03166366ca2bc0896040518263ffffffff1660e01b81526004016113ba91815260200190565b6020604051808303816000875af11580156113d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fd9190612be5565b50866001600160401b0316436001600160401b03167ff35ec3b262cf74881db1b8051c635496bccb1497a1e776dacb463d0e0e2b0f518b8b60405161144c929190918252602082015260400190565b60405180910390a3844061012d6000878152602001908152602001600020819055506040518060800160405280886001600160401b03168152602001436001600160401b031681526020018a81526020018981525061012e6000896001600160401b0316815260200190815260200160002060008201518160000160006101000a8154816001600160401b0302191690836001600160401b0316021790555060208201518160000160086101000a8154816001600160401b0302191690836001600160401b0316021790555060408201518160010155606082015181600201559050508261012f819055508661013060086101000a8154816001600160401b0302191690836001600160401b031602179055507f41c3f410f5c8ac36bb46b1dccef0de0f964087c9e688795fa02ecfa2c20b3fe4854061013060009054906101000a90046001600160401b03166040516115b99291909182526001600160401b0316602082015260400190565b60405180910390a150506065805460ff1916600117905550505050505050565b6115e16119fb565b6001600160a01b0381166116465760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161077d565b61081a81611aa2565b6116576119fb565b60655460ff166001190161167e5760405163dfc60d8560e01b815260040160405180910390fd5b6065805460ff1916600217905561169f606554610100900460ff1660021490565b156116bd5760405163bae6e2a960e01b815260040160405180910390fd5b6001600160a01b0381166116e45760405163053fd54760e01b815260040160405180910390fd5b6001600160a01b03821661170a576117056001600160a01b03821647611d2a565b611789565b6040516370a0823160e01b81523060048201526117899082906001600160a01b038516906370a0823190602401602060405180830381865afa158015611754573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117789190612be5565b6001600160a01b0385169190611d35565b50506065805460ff19166001179055565b61081a6119fb565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156117da576117d583611d87565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611834575060408051601f3d908101601f1916820190925261183191810190612be5565b60015b6118975760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b606482015260840161077d565b600080516020612dca83398151915281146119065760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b606482015260840161077d565b506117d5838383611e23565b6097546000906001600160a01b031661193e57604051638ed88b2560e01b815260040160405180910390fd5b609754604051630a3dc4f360e21b81526001600160401b0386166004820152602481018590526001600160a01b03909116906328f713cc90604401602060405180830381865afa158015611996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ba9190612bfe565b9050811580156119d157506001600160a01b038116155b1561082d57836119e084611e48565b604051630d69e23960e41b815260040161077d929190612c6b565b6033546001600160a01b03163314801590611a165750333014155b15610c8257604051632efb161b60e21b815260040160405180910390fd5b600060405160408152602080820152602060408201528460608201528560808201528360a08201528260c082015260208160e08360056107d05a03fa611a7957600080fd5b5195945050505050565b6000806000198385098385029250828110838203039150509250929050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6101305460009081906001600160401b031615611c195761013054600090611b2c9063ffffffff8616906001600160401b0316612c8d565b61013054909150600090600160401b90046001600160401b031615801590611b6a5750610130546001600160401b03600160401b9091048116908716115b15611b995761013054611b8d90600160401b90046001600160401b031687612ca0565b6001600160401b031690505b8015611bd2578651600090611bb49063ffffffff1683612cc7565b9050808311611bc4576001611bce565b611bce8184612a6c565b9250505b611be3826001600160401b03611eda565b9250611c14836001600160401b0316886000015163ffffffff16896020015160ff16611c0f9190612cc7565b611eef565b935050505b81600003611c2657600191505b935093915050565b611c3782611f3a565b6001600160401b0381161580611c55575046816001600160401b0316145b15611c735760405163f49a838160e01b815260040160405180910390fd5b60fb805467ffffffffffffffff19166001600160401b039290921691909117905550565b600080611ca2612699565b60005b60ff81108015611cb85750806001018510155b15611cea576000198186030180408360ff83066101008110611cdc57611cdc612cf4565b602002015250600101611ca5565b5046611fe082015261200081209250834081611d0760ff87612d0a565b6101008110611d1857611d18612cf4565b60200201526120009020919391925050565b61097e82825a611f4b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526117d5908490611fe9565b6001600160a01b0381163b611df45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b606482015260840161077d565b600080516020612dca83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b611e2c836120bb565b600082511180611e395750805b156117d557610faa83836120fb565b60606000611e5583612120565b60010190506000816001600160401b03811115611e7457611e7461276d565b6040519080825280601f01601f191660200182016040528015611e9e576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611ea857509392505050565b6000818311611ee95782610de4565b50919050565b600081600003611f1257604051636296f1b960e11b815260040160405180910390fd5b81670de0b6b3a7640000611f2685856121f8565b611f309190612d1e565b610de49190612d1e565b611f42612248565b61081a81612261565b6001600160a01b038316611f7257604051634c67134d60e11b815260040160405180910390fd5b6000836001600160a01b0316838390604051600060405180830381858888f193505050503d8060008114611fc2576040519150601f19603f3d011682016040523d82523d6000602084013e611fc7565b606091505b5050905080610faa57604051634c67134d60e11b815260040160405180910390fd5b600061203e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166122aa9092919063ffffffff16565b8051909150156117d5578080602001905181019061205c9190612d32565b6117d55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161077d565b6120c481611d87565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060610de48383604051806060016040528060278152602001612dea602791396122b9565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061215f5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef8100000000831061218b576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106121a957662386f26fc10000830492506010015b6305f5e10083106121c1576305f5e100830492506008015b61271083106121d557612710830492506004015b606483106121e7576064830492506002015b600a8310610de75760010192915050565b6000808261220e670de0b6b3a764000086612cc7565b6122189190612d1e565b9050680755bf798b4a1bf1e48111156122375750680755bf798b4a1bf1e45b61224081612331565b949350505050565b6122506124bc565b6065805461ffff1916610101179055565b6001600160401b0346106122885760405163a12e8fa960e01b815260040160405180910390fd5b609780546001600160a01b0319166001600160a01b0392909216919091179055565b606061082a84846000856124eb565b6060600080856001600160a01b0316856040516122d69190612d4f565b600060405180830381855af49150503d8060008114612311576040519150601f19603f3d011682016040523d82523d6000602084013e612316565b606091505b5091509150612327868383876125c6565b9695505050505050565b6000680248ce36a70cb26b3e19821361234c57506000919050565b680755bf798b4a1bf1e5821261237557604051631a93c68960e11b815260040160405180910390fd5b6503782dace9d9604e83901b059150600060606bb17217f7d1cf79abc9e3b39884821b056001605f1b01901d6bb17217f7d1cf79abc9e3b39881029093036c240c330e9fb2d9cbaf0fd5aafb1981018102606090811d6d0277594991cfc85f6e2461837cd9018202811d6d1a521255e34f6a5061b25ef1c9c319018202811d6db1bbb201f443cf962f1a1d3db4a5018202811d6e02c72388d9f74f51a9331fed693f1419018202811d6e05180bb14799ab47a8a8cb2a527d57016d02d16720577bd19bf614176fe9ea6c10fe68e7fd37d0007b713f765084018402831d9081019084016d01d3967ed30fc4f89c02bab5708119010290911d6e0587f503bb6ea29d25fcb740196450019091026d360d7aeea093263ecc6e0ecb291760621b010574029d9dc38563c32e5c2f6dc192ee70ef65f9978af30260c3939093039290921c92915050565b600054610100900460ff166124e35760405162461bcd60e51b815260040161077d90612d6b565b610c8261263f565b60608247101561254c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161077d565b600080866001600160a01b031685876040516125689190612d4f565b60006040518083038185875af1925050503d80600081146125a5576040519150601f19603f3d011682016040523d82523d6000602084013e6125aa565b606091505b50915091506125bb878383876125c6565b979650505050505050565b6060831561263557825160000361262e576001600160a01b0385163b61262e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161077d565b5081612240565b612240838361266f565b600054610100900460ff166126665760405162461bcd60e51b815260040161077d90612d6b565b610c8233611aa2565b81511561267f5781518083602001fd5b8060405162461bcd60e51b815260040161077d9190612db6565b604051806120000160405280610100906020820280368337509192915050565b6001600160401b038116811461081a57600080fd5b6000602082840312156126e057600080fd5b813561082d816126b9565b6001600160a01b038116811461081a57600080fd5b60006020828403121561271257600080fd5b813561082d816126eb565b801515811461081a57600080fd5b60008060006060848603121561274057600080fd5b833561274b816126b9565b92506020840135915060408401356127628161271d565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156127ab576127ab61276d565b604052919050565b600080604083850312156127c657600080fd5b82356127d1816126eb565b91506020838101356001600160401b03808211156127ee57600080fd5b818601915086601f83011261280257600080fd5b8135818111156128145761281461276d565b612826601f8201601f19168501612783565b9150808252878482850101111561283c57600080fd5b80848401858401376000848284010152508093505050509250929050565b6000806040838503121561286d57600080fd5b82359150602083013560ff8116811461288557600080fd5b809150509250929050565b6000602082840312156128a257600080fd5b5035919050565b803563ffffffff811681146128bd57600080fd5b919050565b600080604083850312156128d557600080fd5b82356128e0816126b9565b91506128ee602084016128a9565b90509250929050565b6000806040838503121561290a57600080fd5b8235915060208301356128858161271d565b60008060006060848603121561293157600080fd5b833561293c816126eb565b9250602084013561294c816126b9565b91506040840135612762816126b9565b60008060006040848603121561297157600080fd5b833561297c816126b9565b925060208401356001600160401b038082111561299857600080fd5b818601915086601f8301126129ac57600080fd5b8135818111156129bb57600080fd5b8760208285010111156129cd57600080fd5b6020830194508093505050509250925092565b600080600080608085870312156129f657600080fd5b84359350602085013592506040850135612a0f816126b9565b9150612a1d606086016128a9565b905092959194509250565b60008060408385031215612a3b57600080fd5b8235612a46816126eb565b91506020830135612885816126eb565b634e487b7160e01b600052601160045260246000fd5b81810381811115610de757610de7612a56565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600060608284031215612b2957600080fd5b604051606081018181106001600160401b0382111715612b4b57612b4b61276d565b604052825181526020830151612b60816126eb565b60208201526040830151612b73816126b9565b60408201529392505050565b8183823760009101908152919050565b6001600160e01b03198135818116916004851015612bb75780818660040360031b1b83161692505b505092915050565b60006001600160401b03808316818103612bdb57612bdb612a56565b6001019392505050565b600060208284031215612bf757600080fd5b5051919050565b600060208284031215612c1057600080fd5b815161082d816126eb565b60005b83811015612c36578181015183820152602001612c1e565b50506000910152565b60008151808452612c57816020860160208601612c1b565b601f01601f19169290920160200192915050565b6001600160401b038316815260406020820152600061082a6040830184612c3f565b80820180821115610de757610de7612a56565b6001600160401b03828116828216039080821115612cc057612cc0612a56565b5092915050565b8082028115828204841417610de757610de7612a56565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600082612d1957612d19612cde565b500690565b600082612d2d57612d2d612cde565b500490565b600060208284031215612d4457600080fd5b815161082d8161271d565b60008251612d61818460208701612c1b565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b602081526000610de46020830184612c3f56fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122076b52e7878d08f567e8949c0ef1ef22e0029f1465213d13936a495089d1b0db464736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000010001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000001670080000000000000000000000000000010002", + "0x00000000000000000000000000000000000000000000000000000000000000fb": "0x0000000000000000000000000000000000000000000000000000000000004268", + "0x0000000000000000000000000000000000000000000000000000000000000130": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000000000000000000000000000000000000000012f": "0xcba89937559a0fd2dc6072d1dbd087a2a2ddc3f15e3e33ce15f1f55c29c89534", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000010001" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190" + }, + "code": "0x6080604052600436106100a75760003560e01c8063715018a611610064578063715018a6146101b45780638456cb59146101c95780638da5cb5b146101de578063d8f4648f146101fc578063e1c7392a1461021c578063f2fde38b1461023157600080fd5b806328f713cc146100ac5780633659cfe6146101165780633f4ba83a146101385780634f1ef2861461014d57806352d1902d146101605780635c975abb14610183575b600080fd5b3480156100b857600080fd5b506100f96100c7366004610ce9565b67ffffffffffffffff91909116600090815260976020908152604080832093835292905220546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561012257600080fd5b50610136610131366004610d2a565b610251565b005b34801561014457600080fd5b50610136610339565b61013661015b366004610d5b565b6103b7565b34801561016c57600080fd5b50610175610487565b60405190815260200161010d565b34801561018f57600080fd5b506101a4606554610100900460ff1660021490565b604051901515815260200161010d565b3480156101c057600080fd5b5061013661053a565b3480156101d557600080fd5b5061013661054e565b3480156101ea57600080fd5b506033546001600160a01b03166100f9565b34801561020857600080fd5b50610136610217366004610e1d565b6105c7565b34801561022857600080fd5b50610136610654565b34801561023d57600080fd5b5061013661024c366004610d2a565b610764565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100021630036102a25760405162461bcd60e51b815260040161029990610e59565b60405180910390fd5b7f00000000000000000000000001670080000000000000000000000000000100026001600160a01b03166102eb600080516020610fc9833981519152546001600160a01b031690565b6001600160a01b0316146103115760405162461bcd60e51b815260040161029990610ea5565b61031a816107da565b60408051600080825260208201909252610336918391906107e2565b50565b61034d606554610100900460ff1660021490565b61036a5760405163bae6e2a960e01b815260040160405180910390fd5b610372610952565b6065805461ff0019166101001790556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6001600160a01b037f00000000000000000000000001670080000000000000000000000000000100021630036103ff5760405162461bcd60e51b815260040161029990610e59565b7f00000000000000000000000001670080000000000000000000000000000100026001600160a01b0316610448600080516020610fc9833981519152546001600160a01b031690565b6001600160a01b03161461046e5760405162461bcd60e51b815260040161029990610ea5565b610477826107da565b610483828260016107e2565b5050565b6000306001600160a01b037f000000000000000000000000016700800000000000000000000000000001000216146105275760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610299565b50600080516020610fc983398151915290565b610542610952565b61054c60006109ac565b565b610562606554610100900460ff1660021490565b156105805760405163bae6e2a960e01b815260040160405180910390fd5b610588610952565b6065805461ff0019166102001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016103ad565b6105cf610952565b67ffffffffffffffff8316600081815260976020908152604080832086845282529182902080546001600160a01b038681166001600160a01b0319831681179093558451928352169181018290529092859290917f500dcd607a98daece9bccc2511bf6032471252929de73caf507aae0e082f8453910160405180910390a350505050565b600054610100900460ff16158080156106745750600054600160ff909116105b8061068e5750303b15801561068e575060005460ff166001145b6106f15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610299565b6000805460ff191660011790558015610714576000805461ff0019166101001790555b61071c6109fe565b8015610336576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a150565b61076c610952565b6001600160a01b0381166107d15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610299565b610336816109ac565b610336610952565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561081a5761081583610a17565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610874575060408051601f3d908101601f1916820190925261087191810190610ef1565b60015b6108d75760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610299565b600080516020610fc983398151915281146109465760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610299565b50610815838383610ab3565b6033546001600160a01b0316331461054c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610299565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b610a06610ade565b6065805461ffff1916610101179055565b6001600160a01b0381163b610a845760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610299565b600080516020610fc983398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b610abc83610b0d565b600082511180610ac95750805b1561081557610ad88383610b4d565b50505050565b600054610100900460ff16610b055760405162461bcd60e51b815260040161029990610f0a565b61054c610b79565b610b1681610a17565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060610b728383604051806060016040528060278152602001610fe960279139610ba9565b9392505050565b600054610100900460ff16610ba05760405162461bcd60e51b815260040161029990610f0a565b61054c336109ac565b6060600080856001600160a01b031685604051610bc69190610f79565b600060405180830381855af49150503d8060008114610c01576040519150601f19603f3d011682016040523d82523d6000602084013e610c06565b606091505b5091509150610c1786838387610c21565b9695505050505050565b60608315610c90578251600003610c89576001600160a01b0385163b610c895760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610299565b5081610c9a565b610c9a8383610ca2565b949350505050565b815115610cb25781518083602001fd5b8060405162461bcd60e51b81526004016102999190610f95565b803567ffffffffffffffff81168114610ce457600080fd5b919050565b60008060408385031215610cfc57600080fd5b610d0583610ccc565b946020939093013593505050565b80356001600160a01b0381168114610ce457600080fd5b600060208284031215610d3c57600080fd5b610b7282610d13565b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610d6e57600080fd5b610d7783610d13565b9150602083013567ffffffffffffffff80821115610d9457600080fd5b818501915085601f830112610da857600080fd5b813581811115610dba57610dba610d45565b604051601f8201601f19908116603f01168101908382118183101715610de257610de2610d45565b81604052828152886020848701011115610dfb57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b600080600060608486031215610e3257600080fd5b610e3b84610ccc565b925060208401359150610e5060408501610d13565b90509250925092565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600060208284031215610f0357600080fd5b5051919050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60005b83811015610f70578181015183820152602001610f58565b50506000910152565b60008251610f8b818460208701610f55565b9190910192915050565b6020815260008251806020840152610fb4816040850160208701610f55565b601f01601f1916919091016040019291505056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212204e2030d9883d08dca7ecdc1d78b36ee54b3130abcb1c45646b02f76d950ff54a64736f6c63430008140033", + "balance": "0x0" + }, + "0x1670080000000000000000000000000000010002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x0000000000000000000000001d2d1bb9d180541e88a6a682acf3f61c1605b190", + "0x94555ab63188e8b4764fc4f82f2c4233aef599e74a8259d1932a012388b30959": "0x0000000000000000000000001670080000000000000000000000000000010001", + "0xcffa903d987c324286ac7635484e4c4cfab2b3bddddb45773db47593d56d5616": "0x0000000000000000000000001670080000000000000000000000000000000001", + "0x72cf3566ee7eea8d37039862c9f5956b8622ca74729c83890cfd90fc8645bdcc": "0x0000000000000000000000001670080000000000000000000000000000000005", + "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc": "0x0167008000000000000000000000000000010002" + }, + "code": "0x608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea264697066735822122086939faa9cc2f3fe1410043eff38cc933fdbaa97744a116ffa0de4487915f87464736f6c63430008140033", + "balance": "0x0" + }, + "0x0167008000000000000000000000000000010099": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x526567756c617245524332300000000000000000000000000000000000000018", + "0x0000000000000000000000000000000000000000000000000000000000000004": "0x52474c0000000000000000000000000000000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000000000000000000000000000000000000001f4000", + "0x5498fa9c17918e5d4d0816fce6e97d920fe93d661d3e60d5efd74f67cd7323ec": "0x00000000000000000000000000000000000000000000000000000000000fa000", + "0x69525d8dc81450841f00770b54dbac752c8f05bb6322429f864610dd9f952781": "0x00000000000000000000000000000000000000000000000000000000000fa000" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069c565b60405180910390f35b6100df6100da366004610706565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610730565b61024c565b604051601281526020016100c3565b6100df610131366004610706565b610270565b6100f361014436600461076c565b6001600160a01b031660009081526020819052604090205490565b6100b6610292565b6100df610175366004610706565b6102a1565b6100df610188366004610706565b610321565b6100f361019b36600461078e565b61032f565b6060600380546101af906107c1565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c1565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b60003361024081858561035a565b60019150505b92915050565b60003361025a85828561047e565b6102658585856104f8565b506001949350505050565b600033610240818585610283838361032f565b61028d91906107fb565b61035a565b6060600480546101af906107c1565b600033816102af828661032f565b9050838110156103145760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b610265828686840361035a565b6000336102408185856104f8565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103bc5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161030b565b6001600160a01b03821661041d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161030b565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061048a848461032f565b905060001981146104f257818110156104e55760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161030b565b6104f2848484840361035a565b50505050565b6001600160a01b03831661055c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161030b565b6001600160a01b0382166105be5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161030b565b6001600160a01b038316600090815260208190526040902054818110156106365760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161030b565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f2565b600060208083528351808285015260005b818110156106c9578581018301518582016040015282016106ad565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461070157600080fd5b919050565b6000806040838503121561071957600080fd5b610722836106ea565b946020939093013593505050565b60008060006060848603121561074557600080fd5b61074e846106ea565b925061075c602085016106ea565b9150604084013590509250925092565b60006020828403121561077e57600080fd5b610787826106ea565b9392505050565b600080604083850312156107a157600080fd5b6107aa836106ea565b91506107b8602084016106ea565b90509250929050565b600181811c908216806107d557607f821691505b6020821081036107f557634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561024657634e487b7160e01b600052601160045260246000fdfea26469706673582212201c8a1209aa9600f67ac28ebd0e9b08eed67368c03df4c3b80ea4d635a1f925d564736f6c63430008140033", + "balance": "0x0" + } +} diff --git a/crates/primitives/res/genesis/taiko/snaefellsjokull.json b/crates/primitives/res/genesis/taiko/snaefellsjokull.json new file mode 100644 index 000000000000..c2a60f23e004 --- /dev/null +++ b/crates/primitives/res/genesis/taiko/snaefellsjokull.json @@ -0,0 +1,89 @@ +{ + "0x26250179C8e8E12104e556C4Cd03bCF4dabd51b9": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x9D716db5fF59f8dd903D44a56C41BcbE99bA666c": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x11f080128e565c07caD6fF7ADbb50Be1f62B84DB": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x617138FAdFEeE2E57f87cCba7dd6D6902aB0427d": { + "balance": "0xfffffffffffffacbbb7ca13a7fffffff" + }, + "0x5fa99CB8C2201B2a8CFfe2edfbF11ed6B78cb069": { + "balance": "0x8ac7230489e80000" + }, + "0xC5d653E17c24928B788a17838F11d2AcF0c922A3": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063960304391461003a575b600080fd5b61004d6100483660046119a5565b61004f565b005b60008061005e83850185611b39565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b166020820152919350915060009081906100b490603401604051602081830303815290604052858c6101d3565b915091508161010a5760405162461bcd60e51b815260206004820152601960248201527f4c54503a696e76616c6964206163636f756e742070726f6f660000000000000060448201526064015b60405180910390fd5b6000610115826101fc565b9050600061013c8260028151811061012f5761012f611b9d565b6020026020010151610235565b905060006101758b60405160200161015691815260200190565b60405160208183030381529060405261016e8c610338565b888561034b565b9050806101c45760405162461bcd60e51b815260206004820152601960248201527f4c54503a696e76616c69642073746f726167652070726f6f66000000000000006044820152606401610101565b50505050505050505050505050565b6000606060006101e286610365565b90506101ef818686610397565b9250925050935093915050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061022f90610472565b92915050565b600060218260000151111561028c5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b600080600061029a85610671565b9194509250905060008160018111156102b5576102b5611bcc565b146103025760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610101565b60008386602001516103149190611c2a565b8051909150602084101561032e5760208490036101000a90045b9695505050505050565b606061022f610346836109c2565b610b2d565b60008061035786610365565b905061032e81868686610b9c565b6060818051906020012060405160200161038191815260200190565b6040516020818303038152906040529050919050565b6000606060006103a685610bd9565b905060008060006103b8848a89610cd4565b815192955090935091501580806103cc5750815b6104185760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610101565b6000816104345760405180602001604052806000815250610460565b61046086610443600188611c42565b8151811061045357610453611b9d565b602002602001015161116f565b919b919a509098505050505050505050565b606060008061048084610671565b9193509091506001905081600181111561049c5761049c611bcc565b146104e95760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610101565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816105025790505090506000835b865181101561066657602082106105ae5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e000000000000000000000000000000000000000000006064820152608401610101565b6000806105eb6040518060400160405280858c600001516105cf9190611c42565b8152602001858c602001516105e49190611c2a565b9052610671565b5091509150604051806040016040528083836106079190611c2a565b8152602001848b6020015161061c9190611c2a565b81525085858151811061063157610631611b9d565b6020908102919091010152610647600185611c2a565b93506106538183611c2a565b61065d9084611c2a565b9250505061052f565b508152949350505050565b6000806000808460000151116106c95760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610101565b6020840151805160001a607f81116106ee5760006001600094509450945050506109bb565b60b7811161076a576000610703608083611c42565b9050808760000151116107585760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610101565b600195509350600092506109bb915050565b60bf811161085957600061077f60b783611c42565b9050808760000151116107d45760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610101565b600183015160208290036101000a90046107ee8183611c2a565b88511161083d5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610101565b610848826001611c2a565b96509450600093506109bb92505050565b60f781116108d457600061086e60c083611c42565b9050808760000151116108c35760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610101565b6001955093508492506109bb915050565b60006108e160f783611c42565b9050808760000151116109365760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610101565b600183015160208290036101000a90046109508183611c2a565b88511161099f5760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e000000000000000000006044820152606401610101565b6109aa826001611c2a565b96509450600193506109bb92505050565b9193909250565b60606000826040516020016109d991815260200190565b604051602081830303815290604052905060005b6020811015610a4b57818181518110610a0857610a08611b9d565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615610a3957610a4b565b80610a4381611c59565b9150506109ed565b6000610a58826020611c42565b67ffffffffffffffff811115610a7057610a70611a5f565b6040519080825280601f01601f191660200182016040528015610a9a576020820181803683370190505b50905060005b8151811015610b24578383610ab481611c59565b945081518110610ac657610ac6611b9d565b602001015160f81c60f81b828281518110610ae357610ae3611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080610b1c81611c59565b915050610aa0565b50949350505050565b60608082516001148015610b5b5750608083600081518110610b5157610b51611b9d565b016020015160f81c105b15610b6757508161022f565b610b7383516080611199565b83604051602001610b85929190611ccd565b604051602081830303815290604052905092915050565b6000806000610bac878686610397565b91509150818015610bce57508051602080830191909120875191880191909120145b979650505050505050565b60606000610be6836101fc565b90506000815167ffffffffffffffff811115610c0457610c04611a5f565b604051908082528060200260200182016040528015610c4957816020015b6040805180820190915260608082526020820152815260200190600190039081610c225790505b50905060005b8251811015610ccc576000610c7c848381518110610c6f57610c6f611b9d565b6020026020010151611390565b90506040518060400160405280828152602001610c98836101fc565b815250838381518110610cad57610cad611b9d565b6020026020010181905250508080610cc490611c59565b915050610c4f565b509392505050565b60006060818080610ce487611420565b90506000869050600080610d0b604051806040016040528060608152602001606081525090565b60005b8c5181101561112b578c8181518110610d2957610d29611b9d565b602002602001015191508284610d3f9190611c2a565b9350610d4c600188611c2a565b965083610db057815180516020909101208514610dab5760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f7420686173680000000000000000000000000000006044820152606401610101565b610e6d565b815151602011610e1257815180516020909101208514610dab5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610101565b84610e2083600001516115a3565b14610e6d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610101565b610e7960106001611c2a565b8260200151511415610ef2578551841415610e935761112b565b6000868581518110610ea757610ea7611b9d565b602001015160f81c60f81b60f81c9050600083602001518260ff1681518110610ed257610ed2611b9d565b60200260200101519050610ee5816115cb565b9650600194505050611119565b600282602001515114156110d1576000610f0b83611601565b9050600081600081518110610f2257610f22611b9d565b016020015160f81c90506000610f39600283611d19565b610f44906002611d3b565b90506000610f55848360ff16611625565b90506000610f638b8a611625565b90506000610f71838361165b565b905060ff851660021480610f88575060ff85166003145b15610fde57808351148015610f9d5750808251145b15610faf57610fac818b611c2a565b99505b507f8000000000000000000000000000000000000000000000000000000000000000995061112b945050505050565b60ff85161580610ff1575060ff85166001145b15611063578251811461102d57507f8000000000000000000000000000000000000000000000000000000000000000995061112b945050505050565b611054886020015160018151811061104757611047611b9d565b60200260200101516115cb565b9a509750611119945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f70726566697800000000000000000000000000000000000000000000000000006064820152608401610101565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610101565b8061112381611c59565b915050610d0e565b507f800000000000000000000000000000000000000000000000000000000000000084148661115a8786611625565b909e909d50909b509950505050505050505050565b6020810151805160609161022f9161118990600190611c42565b81518110610c6f57610c6f611b9d565b606080603884101561121857604080516001808252818301909252906020820181803683370190505090506111ce8385611d5e565b60f81b816000815181106111e4576111e4611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611389565b600060015b6112278187611d83565b1561124d578161123681611c59565b9250611246905061010082611d97565b905061121d565b611258826001611c2a565b67ffffffffffffffff81111561127057611270611a5f565b6040519080825280601f01601f19166020018201604052801561129a576020820181803683370190505b5092506112a78583611d5e565b6112b2906037611d5e565b60f81b836000815181106112c8576112c8611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b818111611386576101006113108284611c42565b61131c90610100611ef4565b6113269088611d83565b6113309190611f00565b60f81b83828151811061134557611345611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508061137e81611c59565b9150506112fc565b50505b9392505050565b606060008060006113a085610671565b9194509250905060008160018111156113bb576113bb611bcc565b146114085760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610101565b61141785602001518484611707565b95945050505050565b60606000825160026114329190611d97565b67ffffffffffffffff81111561144a5761144a611a5f565b6040519080825280601f01601f191660200182016040528015611474576020820181803683370190505b50905060005b835181101561159c57600484828151811061149757611497611b9d565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c826114cc836002611d97565b815181106114dc576114dc611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350601084828151811061151f5761151f611b9d565b0160200151611531919060f81c611d19565b60f81b82611540836002611d97565b61154b906001611c2a565b8151811061155b5761155b611b9d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508061159481611c59565b91505061147a565b5092915050565b60006020825110156115b757506020015190565b8180602001905181019061022f9190611f14565b600060606020836000015110156115ec576115e5836117e6565b90506115f8565b6115f583611390565b90505b611389816115a3565b606061022f6116208360200151600081518110610c6f57610c6f611b9d565b611420565b606082518210611644575060408051602081019091526000815261022f565b61138983838486516116569190611c42565b6117f1565b6000805b80845111801561166f5750808351115b80156116f0575082818151811061168857611688611b9d565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168482815181106116c7576116c7611b9d565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b1561138957806116ff81611c59565b91505061165f565b606060008267ffffffffffffffff81111561172457611724611a5f565b6040519080825280601f01601f19166020018201604052801561174e576020820181803683370190505b509050805160001415611762579050611389565b600061176e8587611c2a565b90506020820160005b611782602087611d83565b8110156117b95782518252611798602084611c2a565b92506117a5602083611c2a565b9150806117b181611c59565b915050611777565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b606061022f8261198f565b6060816117ff81601f611c2a565b101561184d5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610101565b826118588382611c2a565b10156118a65760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610101565b6118b08284611c2a565b845110156119005760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610101565b60608215801561191f5760405191506000825260208201604052610b24565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611958578051835260209283019201611940565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0166040525050949350505050565b606061022f826020015160008460000151611707565b60008060008060008060a087890312156119be57600080fd5b86359550602087013573ffffffffffffffffffffffffffffffffffffffff811681146119e957600080fd5b94506040870135935060608701359250608087013567ffffffffffffffff80821115611a1457600080fd5b818901915089601f830112611a2857600080fd5b813581811115611a3757600080fd5b8a6020828501011115611a4957600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112611a9f57600080fd5b813567ffffffffffffffff80821115611aba57611aba611a5f565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b0057611b00611a5f565b81604052838152866020858801011115611b1957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b4c57600080fd5b823567ffffffffffffffff80821115611b6457600080fd5b611b7086838701611a8e565b93506020850135915080821115611b8657600080fd5b50611b9385828601611a8e565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611c3d57611c3d611bfb565b500190565b600082821015611c5457611c54611bfb565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611c8b57611c8b611bfb565b5060010190565b6000815160005b81811015611cb35760208185018101518683015201611c99565b81811115611cc2576000828601525b509290920192915050565b6000611ce2611cdc8386611c92565b84611c92565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680611d2c57611d2c611cea565b8060ff84160691505092915050565b600060ff821660ff841680821015611d5557611d55611bfb565b90039392505050565b600060ff821660ff84168060ff03821115611d7b57611d7b611bfb565b019392505050565b600082611d9257611d92611cea565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611dcf57611dcf611bfb565b500290565b600181815b80851115611e2d57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611e1357611e13611bfb565b80851615611e2057918102915b93841c9390800290611dd9565b509250929050565b600082611e445750600161022f565b81611e515750600061022f565b8160018114611e675760028114611e7157611e8d565b600191505061022f565b60ff841115611e8257611e82611bfb565b50506001821b61022f565b5060208310610133831016604e8410600b8410161715611eb0575081810a61022f565b611eba8383611dd4565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611eec57611eec611bfb565b029392505050565b60006113898383611e35565b600082611f0f57611f0f611cea565b500690565b600060208284031215611f2657600080fd5b505191905056fea2646970667358221220f7f04c88df651530a5c547edaa8d0ac57b5adf851950adbf06f8245338f8d71564736f6c63430008090033", + "balance": "0x0" + }, + "0x8A9E82Ebf0E219BBdB4fBBd50FEd45d098a8Ba1e": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c806346eb9db51461003a575b600080fd5b81801561004657600080fd5b5061005a6100553660046107f9565b61005c565b005b610140820135158061006b5750805b156101195761008060a0830160808401610880565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f423a64656e69656400000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600061012c610127846109a8565b610432565b90506001600082815260018701602052604090205460ff16600381111561015557610155610aaa565b146101bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f423a6e6f74466f756e64000000000000000000000000000000000000000000006044820152606401610110565b6040517f461a447800000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f65746865725f7661756c74000000000000000000000000000000000000000000604482015260009073ffffffffffffffffffffffffffffffffffffffff86169063461a44789060640160206040518083038186803b15801561025257600080fd5b505afa158015610266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061028a9190610ad9565b905073ffffffffffffffffffffffffffffffffffffffff81161561032d576040517f1efa4ec0000000000000000000000000000000000000000000000000000000008152610100850135600482015273ffffffffffffffffffffffffffffffffffffffff821690631efa4ec090602401600060405180830381600087803b15801561031457600080fd5b505af1158015610328573d6000803e3d6000fd5b505050505b6103418661033a866109a8565b845a610462565b156103575761035286836002610634565b61042a565b82156103e95761036986836003610634565b60008061037c60e0870160c08801610880565b73ffffffffffffffffffffffffffffffffffffffff16146103ac576103a760e0860160c08701610880565b6103bc565b6103bc60a0860160808701610880565b90506103e373ffffffffffffffffffffffffffffffffffffffff8216610100870135610700565b5061042a565b73ffffffffffffffffffffffffffffffffffffffff81161561042a5761042a73ffffffffffffffffffffffffffffffffffffffff8216610100860135610700565b505050505050565b6000816040516020016104459190610b70565b604051602081830303815290604052805190602001209050919050565b60008082116104cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f423a6761734c696d6974000000000000000000000000000000000000000000006044820152606401610110565b6040805160608101825284815260208681015173ffffffffffffffffffffffffffffffffffffffff90811691830182905287840151928401839052600389018790556004890180547fffffffffffffffffffffffff000000000000000000000000000000000000000016909217909155600588019190915560a08601516101008701516101608801519351919092169285929161056a9190610d04565b600060405180830381858888f193505050503d80600081146105a8576040519150601f19603f3d011682016040523d82523d6000602084013e6105ad565b606091505b5050604080516060810182526001808252602082018190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91909201819052600388018290556004880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690921790915560059096019590955550929392505050565b80600381111561064657610646610aaa565b600083815260018501602052604090205460ff16600381111561066b5761066b610aaa565b146106fb57600082815260018085016020526040909120805483927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116908360038111156106bd576106bd610aaa565b0217905550817f6c51882bc2ed67617f77a1e9b9a25d2caad8448647ecb093b357a603b2575634826040516106f29190610d20565b60405180910390a25b505050565b80156107d05760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610760576040519150601f19603f3d011682016040523d82523d6000602084013e610765565b606091505b50509050806106fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610110565b5050565b73ffffffffffffffffffffffffffffffffffffffff811681146107f657600080fd5b50565b6000806000806080858703121561080f57600080fd5b843593506020850135610821816107d4565b9250604085013567ffffffffffffffff81111561083d57600080fd5b85016101a0818803121561085057600080fd5b91506060850135801515811461086557600080fd5b939692955090935050565b803561087b816107d4565b919050565b60006020828403121561089257600080fd5b813561089d816107d4565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff811182821017156108f7576108f76108a4565b60405290565b600082601f83011261090e57600080fd5b813567ffffffffffffffff80821115610929576109296108a4565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561096f5761096f6108a4565b8160405283815286602085880101111561098857600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101a082360312156109bb57600080fd5b6109c36108d3565b823581526109d360208401610870565b602082015260408301356040820152606083013560608201526109f860808401610870565b6080820152610a0960a08401610870565b60a0820152610a1a60c08401610870565b60c082015260e083810135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013567ffffffffffffffff80821115610a6757600080fd5b610a73368388016108fd565b83850152610180925082860135915080821115610a8f57600080fd5b50610a9c368287016108fd565b918301919091525092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060208284031215610aeb57600080fd5b815161089d816107d4565b60005b83811015610b11578181015183820152602001610af9565b83811115610b20576000848401525b50505050565b60008151808452610b3e816020860160208601610af6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60408152601460408201527f5441494b4f5f4252494447455f4d4553534147450000000000000000000000006060820152608060208201528151608082015260006020830151610bd860a084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015160c0830152606083015160e08301526080830151610100610c168185018373ffffffffffffffffffffffffffffffffffffffff169052565b60a08501519150610120610c418186018473ffffffffffffffffffffffffffffffffffffffff169052565b60c08601519250610140610c6c8187018573ffffffffffffffffffffffffffffffffffffffff169052565b60e0870151610160878101919091529287015161018080880191909152918701516101a080880191909152908701516101c0870152918601516101e0860192909252909150610cbf610220850183610b26565b908501518482037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001610200860152909150610cfb8282610b26565b95945050505050565b60008251610d16818460208701610af6565b9190910192915050565b6020810160048310610d5b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9190529056fea2646970667358221220ef77fa8abe15893a91d42d96908d637a4ee0724e51d926aff79565effe20a22c64736f6c63430008090033", + "balance": "0x0" + }, + "0xf7c52068c40213E7C49313B0d6FCc11Cb2C45dbF": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063c0249e2d1461003a575b600080fd5b81801561004657600080fd5b5061005a6100553660046119c3565b61005c565b005b61014083013561010f5761007660a0840160808501611a8d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461010f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f423a666f7262696464656e00000000000000000000000000000000000000000060448201526064015b60405180910390fd5b4683606001351461017c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f423a64657374436861696e4964000000000000000000000000000000000000006044820152606401610106565b600061018f61018a85611bf5565b61073d565b905060008082815260018801602052604090205460ff1660038111156101b7576101b7611cf7565b1461021e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f423a7374617475730000000000000000000000000000000000000000000000006044820152606401610106565b604080517ff16c79340000000000000000000000000000000000000000000000000000000081528186013560048201526024810191909152600660448201527f6272696467650000000000000000000000000000000000000000000000000000606482015260009073ffffffffffffffffffffffffffffffffffffffff87169063f16c79349060840160206040518083038186803b1580156102bf57600080fd5b505afa1580156102d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102f79190611d26565b905061030786828385888861076d565b61036d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f423a6e6f745265636569766564000000000000000000000000000000000000006044820152606401610106565b6040517f461a447800000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f65746865725f7661756c74000000000000000000000000000000000000000000604482015260009073ffffffffffffffffffffffffffffffffffffffff88169063461a44789060640160206040518083038186803b15801561040357600080fd5b505afa158015610417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043b9190611d26565b905073ffffffffffffffffffffffffffffffffffffffff8116156104e95773ffffffffffffffffffffffffffffffffffffffff8116631efa4ec061012088013561048e6101008a013560e08b0135611d72565b6104989190611d72565b6040518263ffffffff1660e01b81526004016104b691815260200190565b600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b505050505b61051d60e087013561050160a0890160808a01611a8d565b73ffffffffffffffffffffffffffffffffffffffff1690610b33565b6000803061053160c08a0160a08b01611a8d565b73ffffffffffffffffffffffffffffffffffffffff1614806105785750600061056060c08a0160a08b01611a8d565b73ffffffffffffffffffffffffffffffffffffffff16145b1561058d57506002905061010087013561064f565b600061059f60a08a0160808b01611a8d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146105dc578861014001356105de565b5a5b905060006105f68c6105ef8c611bf5565b8985610c09565b90508015610607576002935061064c565b6001935073ffffffffffffffffffffffffffffffffffffffff85161561064c5761064c73ffffffffffffffffffffffffffffffffffffffff86166101008c0135610b33565b50505b61065a8a8684610dbd565b60008061066d60e08b0160c08c01611a8d565b73ffffffffffffffffffffffffffffffffffffffff161461069d5761069860e08a0160c08b01611a8d565b6106ad565b6106ad60a08a0160808b01611a8d565b90503373ffffffffffffffffffffffffffffffffffffffff82161415610701576106fc6106df6101208b013584611d72565b73ffffffffffffffffffffffffffffffffffffffff831690610b33565b610730565b610710336101208b0135610b33565b61073073ffffffffffffffffffffffffffffffffffffffff821683610b33565b5050505050505050505050565b6000816040516020016107509190611e04565b604051602081830303815290604052805190602001209050919050565b6000848473ffffffffffffffffffffffffffffffffffffffff82166107ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f423a73656e6465720000000000000000000000000000000000000000000000006044820152606401610106565b80610855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f423a7369676e616c0000000000000000000000000000000000000000000000006044820152606401610106565b73ffffffffffffffffffffffffffffffffffffffff88166108d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f423a7372634272696467650000000000000000000000000000000000000000006044820152606401610106565b60006108e08587018761203e565b905073C5d653E17c24928B788a17838F11d2AcF0c922A363960304398260000151606001518b6109108c8c610e88565b60208601516040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152610953949392916001916004016121d7565b60006040518083038186803b15801561096b57600080fd5b505af415801561097f573d6000803e3d6000fd5b50506040517f461a447800000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f7461696b6f00000000000000000000000000000000000000000000000000000060448201526000925073ffffffffffffffffffffffffffffffffffffffff8d16915063461a44789060640160206040518083038186803b158015610a1957600080fd5b505afa158015610a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a519190611d26565b825161010001516040517f25bf86f20000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff91909116906325bf86f29060240160206040518083038186803b158015610ad257600080fd5b505afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190612223565b90508015801590610b2457508151610b2190610ee3565b81145b9b9a5050505050505050505050565b8015610c055760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610b93576040519150601f19603f3d011682016040523d82523d6000602084013e610b98565b606091505b5050905080610c03576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610106565b505b5050565b6000808211610c74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f423a6761734c696d6974000000000000000000000000000000000000000000006044820152606401610106565b6040805160608101825284815260208681015173ffffffffffffffffffffffffffffffffffffffff90811691830182905287840151928401839052600389018790556004890180547fffffffffffffffffffffffff000000000000000000000000000000000000000016909217909155600588019190915560a086015161010087015161016088015193519190921692859291610d11919061223c565b600060405180830381858888f193505050503d8060008114610d4f576040519150601f19603f3d011682016040523d82523d6000602084013e610d54565b606091505b50506040805160608101825260018082526020820181905260001991909201819052600388018290556004880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690921790915560059096019590955550929392505050565b806003811115610dcf57610dcf611cf7565b600083815260018501602052604090205460ff166003811115610df457610df4611cf7565b14610c0357600082815260018085016020526040909120805483927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911690836003811115610e4657610e46611cf7565b0217905550817f6c51882bc2ed67617f77a1e9b9a25d2caad8448647ecb093b357a603b257563482604051610e7b9190612258565b60405180910390a2505050565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b166020820152603481018290526000906054016040516020818303038152906040528051906020012090505b92915050565b60006060826101e0015160001415610f285760408051600f808252610200820190925290816020015b6060815260200190600190039081610f0c579050509050610f57565b604080516010808252610220820190925290816020015b6060815260200190600190039081610f3f5790505090505b8251610f629061129d565b81600081518110610f7557610f75612299565b6020026020010181905250610f8d836020015161129d565b81600181518110610fa057610fa0612299565b6020026020010181905250610fb883604001516112b0565b81600281518110610fcb57610fcb612299565b6020026020010181905250610fe3836060015161129d565b81600381518110610ff657610ff6612299565b602002602001018190525061100e836080015161129d565b8160048151811061102157611021612299565b60200260200101819052506110398360a0015161129d565b8160058151811061104c5761104c612299565b60200260200101819052506110838360c0015160405160200161106f91906122c8565b6040516020818303038152906040526112ec565b8160068151811061109657611096612299565b60200260200101819052506110ae8360e0015161135b565b816007815181106110c1576110c1612299565b60200260200101819052506110ec8361010001516fffffffffffffffffffffffffffffffff1661135b565b816008815181106110ff576110ff612299565b6020026020010181905250611118836101200151611369565b8160098151811061112b5761112b612299565b6020026020010181905250611144836101400151611369565b81600a8151811061115757611157612299565b6020026020010181905250611170836101600151611369565b81600b8151811061118357611183612299565b602002602001018190525061119c8361018001516112ec565b81600c815181106111af576111af612299565b60200260200101819052506111c8836101a0015161129d565b81600d815181106111db576111db612299565b602002602001018190525061122a836101c0015160405160200161106f919060c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016815260080190565b81600e8151811061123d5761123d612299565b6020026020010181905250826101e0015160001461128257611263836101e0015161135b565b81600f8151811061127657611276612299565b60200260200101819052505b600061128d82611381565b8051602090910120949350505050565b6060610edd6112ab836113c5565b6112ec565b604051606082811b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602083015290610edd9060340161106f565b6060808251600114801561131a575060808360008151811061131057611310612299565b016020015160f81c105b15611326575081610edd565b611332835160806114b8565b836040516020016113449291906122fd565b604051602081830303815290604052905092915050565b6060610edd6112ab836116af565b6060610edd6112ab8367ffffffffffffffff166116af565b6060600061138e83611811565b905061139c815160c06114b8565b816040516020016113ae9291906122fd565b604051602081830303815290604052915050919050565b60606000826040516020016113dc91815260200190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260208084528383019092529250600091829160208201818036833701905050905060005b81518110156114af57838361143f8161232c565b94508151811061145157611451612299565b602001015160f81c60f81b82828151811061146e5761146e612299565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806114a78161232c565b91505061142b565b50949350505050565b606080603884101561153757604080516001808252818301909252906020820181803683370190505090506114ed8385612347565b60f81b8160008151811061150357611503612299565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506116a8565b600060015b611546818761239b565b1561156c57816115558161232c565b92506115659050610100826123af565b905061153c565b611577826001611d72565b67ffffffffffffffff81111561158f5761158f611aaa565b6040519080825280601f01601f1916602001820160405280156115b9576020820181803683370190505b5092506115c68583612347565b6115d1906037612347565b60f81b836000815181106115e7576115e7612299565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b8181116116a55761010061162f82846123ce565b61163b906101006124c9565b611645908861239b565b61164f91906124d5565b60f81b83828151811061166457611664612299565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508061169d8161232c565b91505061161b565b50505b9392505050565b60606000826040516020016116c691815260200190565b604051602081830303815290604052905060005b6020811015611738578181815181106116f5576116f5612299565b01602001517fff00000000000000000000000000000000000000000000000000000000000000161561172657611738565b806117308161232c565b9150506116da565b60006117458260206123ce565b67ffffffffffffffff81111561175d5761175d611aaa565b6040519080825280601f01601f191660200182016040528015611787576020820181803683370190505b50905060005b81518110156114af5783836117a18161232c565b9450815181106117b3576117b3612299565b602001015160f81c60f81b8282815181106117d0576117d0612299565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806118098161232c565b91505061178d565b606081516000141561183157505060408051600081526020810190915290565b6000805b83518110156118785783818151811061185057611850612299565b602002602001015151826118649190611d72565b9150806118708161232c565b915050611835565b60008267ffffffffffffffff81111561189357611893611aaa565b6040519080825280601f01601f1916602001820160405280156118bd576020820181803683370190505b50600092509050602081015b85518310156114af5760008684815181106118e6576118e6612299565b60200260200101519050600060208201905061190483828451611941565b87858151811061191657611916612299565b6020026020010151518361192a9190611d72565b9250505082806119399061232c565b9350506118c9565b8282825b6020811061197d578151835261195c602084611d72565b9250611969602083611d72565b91506119766020826123ce565b9050611945565b905182516020929092036101000a6000190180199091169116179052505050565b73ffffffffffffffffffffffffffffffffffffffff811681146119c057600080fd5b50565b6000806000806000608086880312156119db57600080fd5b8535945060208601356119ed8161199e565b9350604086013567ffffffffffffffff80821115611a0a57600080fd5b908701906101a0828a031215611a1f57600080fd5b90935060608701359080821115611a3557600080fd5b818801915088601f830112611a4957600080fd5b813581811115611a5857600080fd5b896020828501011115611a6a57600080fd5b9699959850939650602001949392505050565b8035611a888161199e565b919050565b600060208284031215611a9f57600080fd5b81356116a88161199e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff81118282101715611afd57611afd611aaa565b60405290565b6040805190810167ffffffffffffffff81118282101715611afd57611afd611aaa565b604051610200810167ffffffffffffffff81118282101715611afd57611afd611aaa565b600082601f830112611b5b57600080fd5b813567ffffffffffffffff80821115611b7657611b76611aaa565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611bbc57611bbc611aaa565b81604052838152866020858801011115611bd557600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101a08236031215611c0857600080fd5b611c10611ad9565b82358152611c2060208401611a7d565b60208201526040830135604082015260608301356060820152611c4560808401611a7d565b6080820152611c5660a08401611a7d565b60a0820152611c6760c08401611a7d565b60c082015260e083810135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013567ffffffffffffffff80821115611cb457600080fd5b611cc036838801611b4a565b83850152610180925082860135915080821115611cdc57600080fd5b50611ce936828701611b4a565b918301919091525092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600060208284031215611d3857600080fd5b81516116a88161199e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611d8557611d85611d43565b500190565b60005b83811015611da5578181015183820152602001611d8d565b83811115611db4576000848401525b50505050565b60008151808452611dd2816020860160208601611d8a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60408152601460408201527f5441494b4f5f4252494447455f4d4553534147450000000000000000000000006060820152608060208201528151608082015260006020830151611e6c60a084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015160c0830152606083015160e08301526080830151610100611eaa8185018373ffffffffffffffffffffffffffffffffffffffff169052565b60a08501519150610120611ed58186018473ffffffffffffffffffffffffffffffffffffffff169052565b60c08601519250610140611f008187018573ffffffffffffffffffffffffffffffffffffffff169052565b60e0870151610160878101919091529287015161018080880191909152918701516101a080880191909152908701516101c0870152918601516101e0860192909252909150611f53610220850183611dba565b908501518482037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001610200860152909150611f8f8282611dba565b95945050505050565b600082601f830112611fa957600080fd5b60405161010080820182811067ffffffffffffffff82111715611fce57611fce611aaa565b60405283018185821115611fe157600080fd5b845b82811015611ffb578035825260209182019101611fe3565b509195945050505050565b80356fffffffffffffffffffffffffffffffff81168114611a8857600080fd5b803567ffffffffffffffff81168114611a8857600080fd5b60006020828403121561205057600080fd5b813567ffffffffffffffff8082111561206857600080fd5b908301906040828603121561207c57600080fd5b612084611b03565b82358281111561209357600080fd5b83016102e081880312156120a657600080fd5b6120ae611b26565b81358152602082013560208201526120c860408301611a7d565b6040820152606082013560608201526080820135608082015260a082013560a08201526120f88860c08401611f98565b60c08201526101c08083013560e08301526101e0612117818501612006565b61010084015261212a6102008501612026565b61012084015261213d6102208501612026565b6101408401526121506102408501612026565b6101608401526102608401358681111561216957600080fd5b6121758b828701611b4a565b610180850152506102808401356101a08401526121956102a08501612026565b828401526102c084013581840152505080835250506020830135828111156121bc57600080fd5b6121c887828601611b4a565b60208301525095945050505050565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015283604082015282606082015260a06080820152600061221860a0830184611dba565b979650505050505050565b60006020828403121561223557600080fd5b5051919050565b6000825161224e818460208701611d8a565b9190910192915050565b6020810160048310612293577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008183825b60088110156122ed5781518352602092830192909101906001016122ce565b5050506101008201905092915050565b6000835161230f818460208801611d8a565b835190830190612323818360208801611d8a565b01949350505050565b600060001982141561234057612340611d43565b5060010190565b600060ff821660ff84168060ff0382111561236457612364611d43565b019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826123aa576123aa61236c565b500490565b60008160001904831182151516156123c9576123c9611d43565b500290565b6000828210156123e0576123e0611d43565b500390565b600181815b8085111561242057816000190482111561240657612406611d43565b8085161561241357918102915b93841c93908002906123ea565b509250929050565b60008261243757506001610edd565b8161244457506000610edd565b816001811461245a576002811461246457612480565b6001915050610edd565b60ff84111561247557612475611d43565b50506001821b610edd565b5060208310610133831016604e8410600b84101617156124a3575081810a610edd565b6124ad83836123e5565b80600019048211156124c1576124c1611d43565b029392505050565b60006116a88383612428565b6000826124e4576124e461236c565b50069056fea264697066735822122014b842a0757d4ec0c7768c8c29fec84d20bd7c03ad1a5e3376215194d1c9806464736f6c63430008090033", + "balance": "0x0" + }, + "0x1FEEE7d2A4da93fE4899fFf3ff844A224b1A143d": { + "storage": {}, + "code": "0x73000000000000000000000000000000000000000030146080604052600436106100405760003560e01c80632cb6101a14610045578063dae029d31461006e575b600080fd5b6100586100533660046117b8565b61008e565b6040516100659190611925565b60405180910390f35b61008161007c3660046119de565b610218565b6040516100659190611aad565b604080516020810190915260608152816100a757610212565b60006100e884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104e092505050565b90506000815167ffffffffffffffff811115610106576101066119af565b60405190808252806020026020018201604052801561019b57816020015b610188604051806101000160405280600060ff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160008152602001600060ff1681526020016000815260200160008152602001606081525090565b8152602001906001900390816101245790505b50905060005b82518110156101ff576101cf61007c8483815181106101c2576101c2611ac0565b6020026020010151610513565b8282815181106101e1576101e1611ac0565b602002602001018190525080806101f790611b1e565b9150506101a1565b5060408051602081019091529081529150505b92915050565b61027c604051806101000160405280600060ff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160008152602001600060ff1681526020016000815260200160008152602001606081525090565b602082015160e0820183905260001a60c081108015906102a0575060fe8160ff1611155b156103265760008083526102b3846104e0565b905060006102c0826105a3565b60408082015160608088019190915282015173ffffffffffffffffffffffffffffffffffffffff16602087015260c08083015160ff16608088015260e083015160a080890191909152610100840151918801919091529091015190850152506104da9050565b607f8160ff16116104925760ff81168252600061034c6103478560016107bd565b6104e0565b90508160ff16600114156103c4576000610365826107fa565b6060808201519086015260808082015173ffffffffffffffffffffffffffffffffffffffff16602087015261010082015160ff169086015261012081015160a086015261014081015160c080870191909152015160408501525061048c565b826000015160ff166002141561043f5760006103df82610a3b565b608080820151606087015260a08083015173ffffffffffffffffffffffffffffffffffffffff16602088015261012083015160ff16918701919091526101408201519086015261016081015160c086015260e0015160408501525061048c565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074785479706500000000000000000000000000000000000060448201526064015b60405180910390fd5b506104da565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964207072656669780000000000000000000000000000000000006044820152606401610483565b50919050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061021290610c90565b6060600080600061052385610e8f565b91945092509050600081600181111561053e5761053e611b57565b1461058b5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610483565b61059a856020015184846111e0565b95945050505050565b61060b604051806101200160405280600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160608152602001600060ff16815260200160008152602001600081525090565b815160091461065c5760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e6774680000000000000000000000006044820152606401610483565b61067f8260008151811061067257610672611ac0565b60200260200101516112d9565b8152815161069a908390600190811061067257610672611ac0565b602082015281516106b8908390600290811061067257610672611ac0565b604082015281516106e390839060039081106106d6576106d6611ac0565b60200260200101516112e4565b73ffffffffffffffffffffffffffffffffffffffff1660608201528151610717908390600490811061067257610672611ac0565b6080820152815161073590839060059081106101c2576101c2611ac0565b60a082015261074862028c5b6002611b86565b61075e8360068151811061067257610672611ac0565b6107689190611bc3565b610773906023611bda565b60ff1660c08201528151610794908390600790811061067257610672611ac0565b60e082015281516107b2908390600890811061067257610672611ac0565b610100820152919050565b6060825182106107dc5750604080516020810190915260008152610212565b6107f383838486516107ee9190611bc3565b611353565b9392505050565b61087060405180610160016040528060008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016060815260200160608152602001600060ff16815260200160008152602001600081525090565b8151600b146108c15760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e6774680000000000000000000000006044820152606401610483565b6108d78260008151811061067257610672611ac0565b815281516108f2908390600190811061067257610672611ac0565b60208201528151610910908390600290811061067257610672611ac0565b6040820152815161092e908390600390811061067257610672611ac0565b6060820152815161094c90839060049081106106d6576106d6611ac0565b73ffffffffffffffffffffffffffffffffffffffff1660808201528151610980908390600590811061067257610672611ac0565b60a0820152815161099e90839060069081106101c2576101c2611ac0565b8160c001819052506109d16109cc836007815181106109bf576109bf611ac0565b6020026020010151610c90565b6114f2565b8160e001819052506109ef8260088151811061067257610672611ac0565b60ff166101008201528151610a11908390600990811061067257610672611ac0565b6101208201528151610a30908390600a90811061067257610672611ac0565b610140820152919050565b610ab86040518061018001604052806000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016060815260200160608152602001600060ff16815260200160008152602001600081525090565b8151600c14610b095760405162461bcd60e51b815260206004820152601460248201527f696e76616c6964206974656d73206c656e6774680000000000000000000000006044820152606401610483565b610b1f8260008151811061067257610672611ac0565b81528151610b3a908390600190811061067257610672611ac0565b60208201528151610b58908390600290811061067257610672611ac0565b60408201528151610b76908390600390811061067257610672611ac0565b60608201528151610b94908390600490811061067257610672611ac0565b60808201528151610bb290839060059081106106d6576106d6611ac0565b73ffffffffffffffffffffffffffffffffffffffff1660a08201528151610be6908390600690811061067257610672611ac0565b60c08201528151610c0490839060079081106101c2576101c2611ac0565b8160e00181905250610c256109cc836008815181106109bf576109bf611ac0565b816101000181905250610c448260098151811061067257610672611ac0565b60ff166101208201528151610c66908390600a90811061067257610672611ac0565b6101408201528151610c85908390600b90811061067257610672611ac0565b610160820152919050565b6060600080610c9e84610e8f565b91935090915060019050816001811115610cba57610cba611b57565b14610d075760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610483565b6040805160208082526104208201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081610d205790505090506000835b8651811015610e845760208210610dcc5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e000000000000000000000000000000000000000000006064820152608401610483565b600080610e096040518060400160405280858c60000151610ded9190611bc3565b8152602001858c60200151610e029190611bda565b9052610e8f565b509150915060405180604001604052808383610e259190611bda565b8152602001848b60200151610e3a9190611bda565b815250858581518110610e4f57610e4f611ac0565b6020908102919091010152610e65600185611bda565b9350610e718183611bda565b610e7b9084611bda565b92505050610d4d565b508152949350505050565b600080600080846000015111610ee75760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610483565b6020840151805160001a607f8111610f0c5760006001600094509450945050506111d9565b60b78111610f88576000610f21608083611bc3565b905080876000015111610f765760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610483565b600195509350600092506111d9915050565b60bf8111611077576000610f9d60b783611bc3565b905080876000015111610ff25760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610483565b600183015160208290036101000a900461100c8183611bda565b88511161105b5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610483565b611066826001611bda565b96509450600093506111d992505050565b60f781116110f257600061108c60c083611bc3565b9050808760000151116110e15760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610483565b6001955093508492506111d9915050565b60006110ff60f783611bc3565b9050808760000151116111545760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610483565b600183015160208290036101000a900461116e8183611bda565b8851116111bd5760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e000000000000000000006044820152606401610483565b6111c8826001611bda565b96509450600193506111d992505050565b9193909250565b606060008267ffffffffffffffff8111156111fd576111fd6119af565b6040519080825280601f01601f191660200182016040528015611227576020820181803683370190505b50905080516000141561123b5790506107f3565b60006112478587611bda565b90506020820160005b61125b602087611bf2565b8110156112925782518252611271602084611bda565b925061127e602083611bda565b91508061128a81611b1e565b915050611250565b5080519151601f959095166020036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019182169119909416179092525092915050565b6000610212826116b5565b8051600090600114156112f957506000919050565b815160151461134a5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e0000000000006044820152606401610483565b610212826112d9565b60608161136181601f611bda565b10156113af5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610483565b826113ba8382611bda565b10156114085760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610483565b6114128284611bda565b845110156114625760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610483565b60608215801561148157604051915060008252602082016040526114e9565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156114ba5780518352602092830192016114a2565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b6060815167ffffffffffffffff81111561150e5761150e6119af565b60405190808252806020026020018201604052801561155457816020015b60408051808201909152600081526060602082015281526020019060019003908161152c5790505b50905060005b82518110156104da57600061157a8483815181106109bf576109bf611ac0565b90506000611594826000815181106106d6576106d6611ac0565b905060006115ae836001815181106109bf576109bf611ac0565b90506000815167ffffffffffffffff8111156115cc576115cc6119af565b6040519080825280602002602001820160405280156115f5578160200160208202803683370190505b50905060005b82518110156116555761162683828151811061161957611619611ac0565b60200260200101516116b5565b82828151811061163857611638611ac0565b60209081029190910101528061164d81611b1e565b9150506115fb565b5060405180604001604052808473ffffffffffffffffffffffffffffffffffffffff1681526020018281525086868151811061169357611693611ac0565b60200260200101819052505050505080806116ad90611b1e565b91505061155a565b600060218260000151111561170c5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610483565b600080600061171a85610e8f565b91945092509050600081600181111561173557611735611b57565b146117825760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610483565b60008386602001516117949190611bda565b805190915060208410156117ae5760208490036101000a90045b9695505050505050565b600080602083850312156117cb57600080fd5b823567ffffffffffffffff808211156117e357600080fd5b818501915085601f8301126117f757600080fd5b81358181111561180657600080fd5b86602082850101111561181857600080fd5b60209290920196919550909350505050565b6000815180845260005b8181101561185057602081850181015186830182015201611834565b81811115611862576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600061010060ff835116845273ffffffffffffffffffffffffffffffffffffffff602084015116602085015260408301518160408601526118d88286018261182a565b9150506060830151606085015260808301516118f9608086018260ff169052565b5060a083015160a085015260c083015160c085015260e083015184820360e086015261059a828261182a565b60006020808352604083018451828386015281815180845260608701915060608160051b8801019350848301925060005b818110156119a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888603018352611990858551611895565b94509285019291850191600101611956565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156119f057600080fd5b813567ffffffffffffffff80821115611a0857600080fd5b818401915084601f830112611a1c57600080fd5b813581811115611a2e57611a2e6119af565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611a7457611a746119af565b81604052828152876020848701011115611a8d57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6020815260006107f36020830184611895565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611b5057611b50611aef565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611bbe57611bbe611aef565b500290565b600082821015611bd557611bd5611aef565b500390565b60008219821115611bed57611bed611aef565b500190565b600082611c28577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220ce05fa3cbf6e91edf039ea061baf84063d7d321bf9eb0101e512c682c93dd08f64736f6c63430008090033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000006": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x00000000000000000000000026250179c8e8e12104e556c4cd03bcf4dabd51b9", + "0x9e150550d912c06ad86bcac5075c8239136cbee2772f59805934f638390787fd": "0x0000000000000000000000000000777700000000000000000000000000000001", + "0xdf0a4e0e7239b530f3a9e9f04f6a2a1d6919446d7589e04de0d7da7f18f5d05a": "0x0000000000000000000000000000777700000000000000000000000000000004", + "0x20beed59eb6fea4f4c6192069320a80e7e285095b80b0603151a98cc480424ce": "0x0000000000000000000000000000777700000000000000000000000000000002", + "0x3d81277ccd96113ddd1d87267c98b973367fd126e1b94b601a82a8474494f54f": "0x0000000000000000000000000000777700000000000000000000000000000003" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063bf40fac111610050578063bf40fac1146100d7578063e1c7392a146100ea578063f2fde38b146100f257600080fd5b8063715018a6146100775780638da5cb5b146100815780639b2ea4bd146100c4575b600080fd5b61007f610105565b005b60335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61007f6100d23660046107d8565b610119565b61009b6100e5366004610826565b6101ec565b61007f610228565b61007f610100366004610863565b6103bf565b61010d610473565b61011760006104f4565b565b610121610473565b600061012c8361056b565b60008181526065602052604090819020805473ffffffffffffffffffffffffffffffffffffffff8681167fffffffffffffffffffffffff00000000000000000000000000000000000000008316179092559151929350169061018f908590610885565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f9416a153a346f93d95f94b064ae3f148b6460473c6e82b3f9fc2521b873fcd6c910160405180910390a250505050565b6000606560006101fb8461056b565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1692915050565b600054610100900460ff16158080156102485750600054600160ff909116105b806102625750303b158015610262575060005460ff166001145b6102f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561035157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61035961059b565b80156103bc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6103c7610473565b73ffffffffffffffffffffffffffffffffffffffff811661046a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102ea565b6103bc816104f4565b60335473ffffffffffffffffffffffffffffffffffffffff163314610117576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102ea565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60008160405160200161057e9190610885565b604051602081830303815290604052805190602001209050919050565b600054610100900460ff16610632576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102ea565b610117600054610100900460ff166106cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102ea565b610117336104f4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261071557600080fd5b813567ffffffffffffffff80821115610730576107306106d5565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610776576107766106d5565b8160405283815286602085880101111561078f57600080fd5b836020870160208301376000602085830101528094505050505092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146107d357600080fd5b919050565b600080604083850312156107eb57600080fd5b823567ffffffffffffffff81111561080257600080fd5b61080e85828601610704565b92505061081d602084016107af565b90509250929050565b60006020828403121561083857600080fd5b813567ffffffffffffffff81111561084f57600080fd5b61085b84828501610704565b949350505050565b60006020828403121561087557600080fd5b61087e826107af565b9392505050565b6000825160005b818110156108a6576020818601810151858301520161088c565b818111156108b5576000828501525b50919091019291505056fea264697066735822122073e1836383d35ef46f9abd6688521406480eb2e7754e7387e4dd208fb4d7c6e464736f6c63430008090033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000001": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000777700000000000000000000000000000006", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0x7eb68e48c9bb3d707a9aba14662dab6ddd0a07c15abb07e83f02d11a86c15560" + }, + "code": "0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80639a295e7311610081578063dac5df781161005b578063dac5df78146101f2578063ee82ac5e146101fb578063f16c79341461020e57600080fd5b80639a295e7314610170578063a0ca2d08146101d6578063c8d772ab146101e957600080fd5b8063461a4478116100b2578063461a4478146101405780635155ce9f14610153578063975e09a01461015b57600080fd5b806325bf86f2146100ce5780633ab76e9f14610101575b600080fd5b6100ee6100dc366004611e7a565b60009081526034602052604090205490565b6040519081526020015b60405180910390f35b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f8565b61011b61014e366004611fbe565b610221565b6036546100ee565b61016e610169366004611ff3565b610233565b005b604080516001815262028c5b6020820152610801918101919091526014606082015260006080820152600560a0820152624c4b4060c0820152606460e0820152620927c06101008201526152086101208201526203d090610140820152610160016100f8565b61016e6101e4366004612080565b6102ec565b6100ee60365481565b6100ee60355481565b6100ee610209366004611e7a565b61034c565b61011b61021c3660046120a2565b610399565b600061022d4683610456565b92915050565b600061024185858585610531565b90506000816006811115610257576102576120e9565b14156102aa5760405162461bcd60e51b815260206004820152600960248201527f4c323a726561736f6e000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6102b261082f565b6102bc8585610952565b6040517f64b299ff9f8ba674288abb53380419048a4271dda03b837ecba6b40e6ddea4a290600090a25050505050565b6102f461082f565b60008281526034602052604090819020829055603682905551829043907f930c750845026c7bb04c0e3d9111d512b4c86981713c4944a35a10a4a7a854f3906103409085815260200190565b60405180910390a35050565b600043821061035d57506000919050565b4382108015610377575061037361010043612147565b8210155b1561038157504090565b5060009081526033602052604090205490565b919050565b60006103a58383610456565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff811661040f5760405162461bcd60e51b815260206004820152600e60248201527f41523a7a65726f4164647265737300000000000000000000000000000000000060448201526064016102a1565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008061046284610974565b8360405160200161047492919061218e565b60408051601f19818403018152908290526000547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac1906104d99084906004016121e6565b60206040518083038186803b1580156104f157600080fd5b505afa158015610505573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610529919061223d565b949350505050565b6000620927c084111561054657506001610529565b6040517f2cb6101a000000000000000000000000000000000000000000000000000000008152731FEEE7d2A4da93fE4899fFf3ff844A224b1A143d90632cb6101a906105989088908890600401612258565b60006040518083038186803b1580156105b057600080fd5b505af49250505080156105e557506040513d6000823e601f3d908101601f191682016040526105e291908101906122dd565b60015b610623573d808015610613576040519150601f19603f3d011682016040523d82523d6000602084013e610618565b606091505b506002915050610529565b80515160641015610638576003915050610529565b624c4b4061064582610aa6565b1115610655576004915050610529565b80515183106106a65760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642074784964780000000000000000000000000000000000000060448201526064016102a1565b6000816000015184815181106106be576106be61247d565b60200260200101519050600560068111156106db576106db6120e9565b8560068111156106ed576106ed6120e9565b141561076c5760006106fe82610afa565b73ffffffffffffffffffffffffffffffffffffffff16146107615760405162461bcd60e51b815260206004820152601760248201527f6261642068696e742054585f494e56414c49445f53494700000000000000000060448201526064016102a1565b600592505050610529565b6006856006811115610780576107806120e9565b14156107e757615208816060015110156107dc5760405162461bcd60e51b815260206004820152600860248201527f6261642068696e7400000000000000000000000000000000000000000000000060448201526064016102a1565b600692505050610529565b60405162461bcd60e51b815260206004820152601e60248201527f6661696c656420746f2070726f76652074786c69737420696e76616c6964000060448201526064016102a1565b610837611e5b565b434660025b610100811115801561084e5750808310155b1561089c5761085d8184612147565b408460ff61086b8487612147565b61087591906124db565b60ff81106108855761088561247d565b602002015280610894816124ef565b91505061083c565b5060006108aa600184612147565b905080406108bb8383600088610b89565b6035541461090b5760405162461bcd60e51b815260206004820152601260248201527f4c323a7075626c6963496e70757448617368000000000000000000000000000060448201526064016102a1565b808561091860ff856124db565b60ff81106109285761092861247d565b602002015261093a8385600088610b89565b60355560009182526033602052604090912055505050565b60008282604051610964929190612528565b6040518091039020905092915050565b6060816109b457505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156109de57806109c8816124ef565b91506109d79050600a83612538565b91506109b8565b60008167ffffffffffffffff8111156109f9576109f9611e93565b6040519080825280601f01601f191660200182016040528015610a23576020820181803683370190505b5090505b841561052957610a38600183612147565b9150610a45600a866124db565b610a5090603061254c565b60f81b818381518110610a6557610a6561247d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610a9f600a86612538565b9450610a27565b8051600090815b8151811015610af357818181518110610ac857610ac861247d565b60200260200101516060015183610adf919061254c565b925080610aeb816124ef565b915050610aad565b5050919050565b60006001610b0783610bc2565b6080840151610b1790601b612564565b60a085015160c0860151604080516000815260200190819052610b56949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610b78573d6000803e3d6000fd5b5050604051601f1901519392505050565b600084848484604051602001610ba29493929190612589565b604051602081830303815290604052805190602001209050949350505050565b805160009060609060ff16610be557610bde8360e00151610fb5565b9050610bff565b610bfc610bf78460e001516001610fe8565b610fb5565b90505b825160ff16610c5e578051600914610c595760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d7300000000000000000000000000000060448201526064016102a1565b610d68565b826000015160ff1660011415610cbf578051600b14610c595760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d7300000000000000000000000000000060448201526064016102a1565b826000015160ff1660021415610d20578051600c14610c595760405162461bcd60e51b815260206004820152601160248201527f696e76616c696420726c70206974656d7300000000000000000000000000000060448201526064016102a1565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c69642074785479706500000000000000000000000000000000000060448201526064016102a1565b825160009060ff1615610d885760038251610d839190612147565b610d8b565b81515b67ffffffffffffffff811115610da357610da3611e93565b604051908082528060200260200182016040528015610dd657816020015b6060815260200190600190039081610dc15790505b50905060005b8151811015610f6357845160ff1615801590610e04575060018251610e019190612147565b81145b15610e4d57610e2b838281518110610e1e57610e1e61247d565b602002602001015161101e565b828281518110610e3d57610e3d61247d565b6020026020010181905250610f51565b610e77610e72848381518110610e6557610e6561247d565b6020026020010151611029565b6110b9565b828281518110610e8957610e8961247d565b6020908102919091010152845160ff16158015610eb2575060048251610eaf9190612147565b81145b15610f5157610ec362028c5b611128565b82610ecf83600161254c565b81518110610edf57610edf61247d565b6020026020010181905250610ef46000611136565b82610f0083600261254c565b81518110610f1057610f1061247d565b6020026020010181905250610f256000611136565b82610f3183600361254c565b81518110610f4157610f4161247d565b6020026020010181905250610f63565b80610f5b816124ef565b915050610ddc565b506000610f6f8261114e565b855190915060ff1615610fa5578451604051610f939160f81b9083906020016125d4565b60405160208183030381529060405290505b8051602090910120949350505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061022d90611192565b606082518210611007575060408051602081019091526000815261022d565b6103a583838486516110199190612147565b611391565b606061022d82611512565b6060600080600061103985611528565b919450925090506000816001811115611054576110546120e9565b146110a15760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e000000000000000060448201526064016102a1565b6110b085602001518484611879565b95945050505050565b606080825160011480156110e757506080836000815181106110dd576110dd61247d565b016020015160f81c105b156110f357508161022d565b6110ff83516080611958565b8360405160200161111192919061261c565b604051602081830303815290604052905092915050565b606061022d610e7283611b4e565b606061022d610e728367ffffffffffffffff16611b4e565b6060600061115b83611cb0565b9050611169815160c0611958565b8160405160200161117b92919061261c565b604051602081830303815290604052915050919050565b60606000806111a084611528565b919350909150600190508160018111156111bc576111bc6120e9565b146112095760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e00000000000000000060448201526064016102a1565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816112225790505090506000835b865181101561138657602082106112ce5760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e0000000000000000000000000000000000000000000060648201526084016102a1565b60008061130b6040518060400160405280858c600001516112ef9190612147565b8152602001858c60200151611304919061254c565b9052611528565b509150915060405180604001604052808383611327919061254c565b8152602001848b6020015161133c919061254c565b8152508585815181106113515761135161247d565b602090810291909101015261136760018561254c565b9350611373818361254c565b61137d908461254c565b9250505061124f565b508152949350505050565b60608161139f81601f61254c565b10156113ed5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f7700000000000000000000000000000000000060448201526064016102a1565b826113f8838261254c565b10156114465760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f7700000000000000000000000000000000000060448201526064016102a1565b611450828461254c565b845110156114a05760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e647300000000000000000000000000000060448201526064016102a1565b6060821580156114bf5760405191506000825260208201604052611509565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156114f85780518352602092830192016114e0565b5050858452601f01601f1916604052505b50949350505050565b606061022d826020015160008460000151611879565b6000806000808460000151116115805760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e000000000000000060448201526064016102a1565b6020840151805160001a607f81116115a5576000600160009450945094505050611872565b60b781116116215760006115ba608083612147565b90508087600001511161160f5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e0000000000000060448201526064016102a1565b60019550935060009250611872915050565b60bf811161171057600061163660b783612147565b90508087600001511161168b5760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e0060448201526064016102a1565b600183015160208290036101000a90046116a5818361254c565b8851116116f45760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e000000000000000060448201526064016102a1565b6116ff82600161254c565b965094506000935061187292505050565b60f7811161178b57600061172560c083612147565b90508087600001511161177a5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e00000000000000000060448201526064016102a1565b600195509350849250611872915050565b600061179860f783612147565b9050808760000151116117ed5760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e00000060448201526064016102a1565b600183015160208290036101000a9004611807818361254c565b8851116118565760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e0000000000000000000060448201526064016102a1565b61186182600161254c565b965094506001935061187292505050565b9193909250565b606060008267ffffffffffffffff81111561189657611896611e93565b6040519080825280601f01601f1916602001820160405280156118c0576020820181803683370190505b5090508051600014156118d45790506103a5565b60006118e0858761254c565b90506020820160005b6118f4602087612538565b81101561192b578251825261190a60208461254c565b925061191760208361254c565b915080611923816124ef565b9150506118e9565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b60608060388410156119d7576040805160018082528183019092529060208201818036833701905050905061198d8385612564565b60f81b816000815181106119a3576119a361247d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506103a5565b600060015b6119e68187612538565b15611a0c57816119f5816124ef565b9250611a0590506101008261264b565b90506119dc565b611a1782600161254c565b67ffffffffffffffff811115611a2f57611a2f611e93565b6040519080825280601f01601f191660200182016040528015611a59576020820181803683370190505b509250611a668583612564565b611a71906037612564565b60f81b83600081518110611a8757611a8761247d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b818111611b4557610100611acf8284612147565b611adb906101006127a8565b611ae59088612538565b611aef91906124db565b60f81b838281518110611b0457611b0461247d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080611b3d816124ef565b915050611abb565b50509392505050565b6060600082604051602001611b6591815260200190565b604051602081830303815290604052905060005b6020811015611bd757818181518110611b9457611b9461247d565b01602001517fff000000000000000000000000000000000000000000000000000000000000001615611bc557611bd7565b80611bcf816124ef565b915050611b79565b6000611be4826020612147565b67ffffffffffffffff811115611bfc57611bfc611e93565b6040519080825280601f01601f191660200182016040528015611c26576020820181803683370190505b50905060005b8151811015611509578383611c40816124ef565b945081518110611c5257611c5261247d565b602001015160f81c60f81b828281518110611c6f57611c6f61247d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080611ca8816124ef565b915050611c2c565b6060815160001415611cd057505060408051600081526020810190915290565b6000805b8351811015611d1757838181518110611cef57611cef61247d565b60200260200101515182611d03919061254c565b915080611d0f816124ef565b915050611cd4565b60008267ffffffffffffffff811115611d3257611d32611e93565b6040519080825280601f01601f191660200182016040528015611d5c576020820181803683370190505b50600092509050602081015b8551831015611509576000868481518110611d8557611d8561247d565b602002602001015190506000602082019050611da383828451611de0565b878581518110611db557611db561247d565b60200260200101515183611dc9919061254c565b925050508280611dd8906124ef565b935050611d68565b8282825b60208110611e1c5781518352611dfb60208461254c565b9250611e0860208361254c565b9150611e15602082612147565b9050611de4565b905182516020929092036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199091169116179052505050565b60405180611fe0016040528060ff906020820280368337509192915050565b600060208284031215611e8c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516020810167ffffffffffffffff81118282101715611ee557611ee5611e93565b60405290565b604051610100810167ffffffffffffffff81118282101715611ee557611ee5611e93565b604051601f8201601f1916810167ffffffffffffffff81118282101715611f3857611f38611e93565b604052919050565b600067ffffffffffffffff821115611f5a57611f5a611e93565b50601f01601f191660200190565b600082601f830112611f7957600080fd5b8135611f8c611f8782611f40565b611f0f565b818152846020838601011115611fa157600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215611fd057600080fd5b813567ffffffffffffffff811115611fe757600080fd5b61052984828501611f68565b6000806000806060858703121561200957600080fd5b843567ffffffffffffffff8082111561202157600080fd5b818701915087601f83011261203557600080fd5b81358181111561204457600080fd5b88602082850101111561205657600080fd5b602092830196509450508501356007811061207057600080fd5b9396929550929360400135925050565b6000806040838503121561209357600080fd5b50508035926020909101359150565b600080604083850312156120b557600080fd5b82359150602083013567ffffffffffffffff8111156120d357600080fd5b6120df85828601611f68565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561215957612159612118565b500390565b60005b83811015612179578181015183820152602001612161565b83811115612188576000848401525b50505050565b600083516121a081846020880161215e565b7f2e0000000000000000000000000000000000000000000000000000000000000090830190815283516121da81600184016020880161215e565b01600101949350505050565b602081526000825180602084015261220581604085016020870161215e565b601f01601f19169190910160400192915050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461039457600080fd5b60006020828403121561224f57600080fd5b6103a582612219565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b805160ff8116811461039457600080fd5b600082601f8301126122a957600080fd5b81516122b7611f8782611f40565b8181528460208386010111156122cc57600080fd5b61052982602083016020870161215e565b600060208083850312156122f057600080fd5b825167ffffffffffffffff8082111561230857600080fd5b818501915082828703121561231c57600080fd5b612324611ec2565b82518281111561233357600080fd5b80840193505086601f84011261234857600080fd5b82518281111561235a5761235a611e93565b8060051b612369868201611f0f565b918252848101860191868101908a84111561238357600080fd5b87870192505b8383101561246d578251868111156123a057600080fd5b8701610100818d03601f19018113156123b857600080fd5b6123c0611eeb565b6123cb8b8401612287565b81526123d960408401612219565b8b8201526060830151898111156123ef57600080fd5b6123fd8f8d83870101612298565b6040830152506080830151606082015260a061241a818501612287565b608083015260c0808501518284015260e091508185015181840152508284015192508983111561244a5760008081fd5b6124588f8d85870101612298565b90820152845250509187019190870190612389565b8452509198975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826124ea576124ea6124ac565b500690565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561252157612521612118565b5060010190565b8183823760009101908152919050565b600082612547576125476124ac565b500490565b6000821982111561255f5761255f612118565b500190565b600060ff821660ff84168060ff0382111561258157612581612118565b019392505050565b848152600060208581840152846040840152606083018460005b60ff8110156125c0578151835291830191908301906001016125a3565b505050506120408201905095945050505050565b7fff00000000000000000000000000000000000000000000000000000000000000831681526000825161260e81600185016020870161215e565b919091016001019392505050565b6000835161262e81846020880161215e565b83519083019061264281836020880161215e565b01949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561268357612683612118565b500290565b600181815b808511156126e157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156126c7576126c7612118565b808516156126d457918102915b93841c939080029061268d565b509250929050565b6000826126f85750600161022d565b816127055750600061022d565b816001811461271b576002811461272557612741565b600191505061022d565b60ff84111561273657612736612118565b50506001821b61022d565b5060208310610133831016604e8410600b8410161715612764575081810a61022d565b61276e8383612688565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156127a0576127a0612118565b029392505050565b60006103a583836126e956fea264697066735822122033da65b31403f3528dc6eca551c4217b5ea7512d6e8827e9af8f7449068335bf64736f6c63430008090033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000004": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000026250179c8e8e12104e556c4cd03bcf4dabd51b9", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006" + }, + "code": "0x6080604052600436106101485760003560e01c80636950f0de116100c0578063d0496d6a11610074578063f2fde38b11610059578063f2fde38b14610421578063f980391914610441578063fee99b221461046157600080fd5b8063d0496d6a14610385578063f16c79341461040157600080fd5b80638da5cb5b116100a55780638da5cb5b1461031957806396e1785214610344578063a4444efd1461036557600080fd5b80636950f0de146102e4578063715018a61461030457600080fd5b8063461a447811610117578063540be6a3116100fc578063540be6a3146102745780635d0bd9861461029457806366ca2bc0146102c457600080fd5b8063461a4478146102175780635075a9d41461023757600080fd5b806319ab453c1461015457806332676bc6146101765780633ab76e9f146101ab5780633aec8585146101f757600080fd5b3661014f57005b600080fd5b34801561016057600080fd5b5061017461016f36600461260a565b610481565b005b34801561018257600080fd5b50610196610191366004612627565b610600565b60405190151581526020015b60405180910390f35b3480156101b757600080fd5b5060975473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a2565b34801561020357600080fd5b5061019661021236600461269c565b610615565b34801561022357600080fd5b506101d2610232366004612851565b610672565b34801561024357600080fd5b50610267610252366004612886565b600090815260ca602052604090205460ff1690565b6040516101a2919061289f565b34801561028057600080fd5b5061019661028f366004612886565b61067e565b3480156102a057600080fd5b506101966102af366004612886565b600090815260c9602052604090205460ff1690565b3480156102d057600080fd5b506101746102df366004612886565b61068a565b3480156102f057600080fd5b506101746102ff3660046128f0565b6106d0565b34801561031057600080fd5b5061017461073c565b34801561032557600080fd5b5060655473ffffffffffffffffffffffffffffffffffffffff166101d2565b610357610352366004612935565b610750565b6040519081526020016101a2565b34801561037157600080fd5b5061019661038036600461296a565b6107c8565b34801561039157600080fd5b50604080516060808201835260008083526020808401829052928401528251808201845260cc5480825260cd5473ffffffffffffffffffffffffffffffffffffffff90811683860190815260ce5493870193845286519283525116938101939093525192820192909252016101a2565b34801561040d57600080fd5b506101d261041c3660046129bd565b610824565b34801561042d57600080fd5b5061017461043c36600461260a565b610830565b34801561044d57600080fd5b5061017461045c366004612a04565b6108cd565b34801561046d57600080fd5b5061017461047c366004612a49565b6109b4565b600054610100900460ff16158080156104a15750600054600160ff909116105b806104bb5750303b1580156104bb575060005460ff166001145b6105325760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561059057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61059982610a9e565b80156105fc57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061060c8383610ab7565b90505b92915050565b600080610657866040518060400160405280600681526020017f6272696467650000000000000000000000000000000000000000000000000000815250610824565b90506106673082878a8888610bc9565b979650505050505050565b600061060f4683610f96565b600061060f3083610ab7565b610694338261108f565b60408051338152602081018390527ff0958489d2a32db2b0faf27a72a31fdf28f2636ca5532f1b077ddc2f51b20d1d910160405180910390a150565b600260015414156107235760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610529565b600260015561073460c9838361119d565b505060018055565b61074461126d565b61074e60006112d4565b565b6000600260015414156107a55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610529565b60026001556107be60c9306107b985612ab2565b61134b565b6001805592915050565b60008061080a856040518060400160405280600681526020017f6272696467650000000000000000000000000000000000000000000000000000815250610824565b905061081a308283898888610bc9565b9695505050505050565b600061060c8383610f96565b61083861126d565b73ffffffffffffffffffffffffffffffffffffffff81166108c15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610529565b6108ca816112d4565b50565b600260015414156109205760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610529565b60026001556040517f46eb9db5000000000000000000000000000000000000000000000000000000008152738A9E82Ebf0E219BBdB4fBBd50FEd45d098a8Ba1e906346eb9db59061097c9060c990309087908790600401612d8e565b60006040518083038186803b15801561099457600080fd5b505af41580156109a8573d6000803e3d6000fd5b50505050505060018055565b60026001541415610a075760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610529565b60026001556040517fc0249e2d00000000000000000000000000000000000000000000000000000000815273f7c52068c40213E7C49313B0d6FCc11Cb2C45dbF9063c0249e2d90610a659060c9903090889088908890600401612dd6565b60006040518083038186803b158015610a7d57600080fd5b505af4158015610a91573d6000803e3d6000fd5b5050505050506001805550565b610aa6611626565b610aae6116ab565b6108ca81611730565b6000828273ffffffffffffffffffffffffffffffffffffffff8216610b1e5760405162461bcd60e51b815260206004820152600860248201527f423a73656e6465720000000000000000000000000000000000000000000000006044820152606401610529565b80610b6b5760405162461bcd60e51b815260206004820152600860248201527f423a7369676e616c0000000000000000000000000000000000000000000000006044820152606401610529565b50506040805160609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208086019190915260348086019490945281518086039094018452605490940190525080519101205460011490565b6000848473ffffffffffffffffffffffffffffffffffffffff8216610c305760405162461bcd60e51b815260206004820152600860248201527f423a73656e6465720000000000000000000000000000000000000000000000006044820152606401610529565b80610c7d5760405162461bcd60e51b815260206004820152600860248201527f423a7369676e616c0000000000000000000000000000000000000000000000006044820152606401610529565b73ffffffffffffffffffffffffffffffffffffffff8816610ce05760405162461bcd60e51b815260206004820152600b60248201527f423a7372634272696467650000000000000000000000000000000000000000006044820152606401610529565b6000610cee85870187612ed0565b905073C5d653E17c24928B788a17838F11d2AcF0c922A363960304398260000151606001518b610d738c8c6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1660208201526034810182905260009060540160405160208183030381529060405280519060200120905092915050565b60208601516040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b168152610db6949392916001916004016130e3565b60006040518083038186803b158015610dce57600080fd5b505af4158015610de2573d6000803e3d6000fd5b50506040517f461a447800000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f7461696b6f00000000000000000000000000000000000000000000000000000060448201526000925073ffffffffffffffffffffffffffffffffffffffff8d16915063461a44789060640160206040518083038186803b158015610e7c57600080fd5b505afa158015610e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb49190613124565b825161010001516040517f25bf86f20000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff91909116906325bf86f29060240160206040518083038186803b158015610f3557600080fd5b505afa158015610f49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6d9190613141565b90508015801590610f8757508151610f84906117da565b81145b9b9a5050505050505050505050565b600080610fa284611b94565b83604051602001610fb492919061315a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac1906110379084906004016131b2565b60206040518083038186803b15801561104f57600080fd5b505afa158015611063573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110879190613124565b949350505050565b818173ffffffffffffffffffffffffffffffffffffffff82166110f45760405162461bcd60e51b815260206004820152600860248201527f423a73656e6465720000000000000000000000000000000000000000000000006044820152606401610529565b806111415760405162461bcd60e51b815260206004820152600860248201527f423a7369676e616c0000000000000000000000000000000000000000000000006044820152606401610529565b50506040805160609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020808501919091526034808501939093528151808503909301835260549093019052805191012060019055565b6000821180156111ad5750468214155b6111f95760405162461bcd60e51b815260206004820152600960248201527f423a636861696e496400000000000000000000000000000000000000000000006044820152606401610529565b6000828152602084815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016841515908117909155915191825283917f9f391218c06d4fc365ceb15f340bb3d77306b28ac0b8d4e519aec2654794536d910160405180910390a2505050565b60655473ffffffffffffffffffffffffffffffffffffffff16331461074e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610529565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b608081015160009073ffffffffffffffffffffffffffffffffffffffff166113b55760405162461bcd60e51b815260206004820152600760248201527f423a6f776e6572000000000000000000000000000000000000000000000000006044820152606401610529565b468260600151141580156113dc5750606082015160009081526020859052604090205460ff165b6114285760405162461bcd60e51b815260206004820152600d60248201527f423a64657374436861696e4964000000000000000000000000000000000000006044820152606401610529565b60008261012001518361010001518460e0015161144591906131f4565b61144f91906131f4565b90503481146114a05760405162461bcd60e51b815260206004820152600760248201527f423a76616c7565000000000000000000000000000000000000000000000000006044820152606401610529565b6040517f461a447800000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f65746865725f7661756c74000000000000000000000000000000000000000000604482015260009073ffffffffffffffffffffffffffffffffffffffff86169063461a44789060640160206040518083038186803b15801561153657600080fd5b505afa15801561154a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156e9190613124565b905073ffffffffffffffffffffffffffffffffffffffff8116156115ac576115ac73ffffffffffffffffffffffffffffffffffffffff821683611cc6565b6002860180549060006115be8361320c565b9091555084523360208501524660408501526115d984611d81565b92506115e5308461108f565b827f47866f7dacd4a276245be6ed543cae03c9c17eb17e6980cee28e3dd168b7f9f3856040516116159190613362565b60405180910390a250509392505050565b600054610100900460ff166116a35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610529565b61074e611db1565b600054610100900460ff166117285760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610529565b61074e611e34565b73ffffffffffffffffffffffffffffffffffffffff81166117935760405162461bcd60e51b815260206004820152600e60248201527f41523a7a65726f416464726573730000000000000000000000000000000000006044820152606401610529565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006060826101e001516000141561181f5760408051600f808252610200820190925290816020015b606081526020019060019003908161180357905050905061184e565b604080516010808252610220820190925290816020015b60608152602001906001900390816118365790505090505b825161185990611eba565b8160008151811061186c5761186c613375565b60200260200101819052506118848360200151611eba565b8160018151811061189757611897613375565b60200260200101819052506118af8360400151611ecd565b816002815181106118c2576118c2613375565b60200260200101819052506118da8360600151611eba565b816003815181106118ed576118ed613375565b60200260200101819052506119058360800151611eba565b8160048151811061191857611918613375565b60200260200101819052506119308360a00151611eba565b8160058151811061194357611943613375565b602002602001018190525061197a8360c0015160405160200161196691906133a4565b604051602081830303815290604052611f09565b8160068151811061198d5761198d613375565b60200260200101819052506119a58360e00151611f78565b816007815181106119b8576119b8613375565b60200260200101819052506119e38361010001516fffffffffffffffffffffffffffffffff16611f78565b816008815181106119f6576119f6613375565b6020026020010181905250611a0f836101200151611f86565b81600981518110611a2257611a22613375565b6020026020010181905250611a3b836101400151611f86565b81600a81518110611a4e57611a4e613375565b6020026020010181905250611a67836101600151611f86565b81600b81518110611a7a57611a7a613375565b6020026020010181905250611a93836101800151611f09565b81600c81518110611aa657611aa6613375565b6020026020010181905250611abf836101a00151611eba565b81600d81518110611ad257611ad2613375565b6020026020010181905250611b21836101c00151604051602001611966919060c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016815260080190565b81600e81518110611b3457611b34613375565b6020026020010181905250826101e00151600014611b7957611b5a836101e00151611f78565b81600f81518110611b6d57611b6d613375565b60200260200101819052505b6000611b8482611f9e565b8051602090910120949350505050565b606081611bd457505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115611bfe5780611be88161320c565b9150611bf79050600a83613408565b9150611bd8565b60008167ffffffffffffffff811115611c1957611c19612706565b6040519080825280601f01601f191660200182016040528015611c43576020820181803683370190505b5090505b841561108757611c5860018361341c565b9150611c65600a86613433565b611c709060306131f4565b60f81b818381518110611c8557611c85613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350611cbf600a86613408565b9450611c47565b80156105fc5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611d26576040519150601f19603f3d011682016040523d82523d6000602084013e611d2b565b606091505b5050905080611d7c5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610529565b505050565b600081604051602001611d949190613447565b604051602081830303815290604052805190602001209050919050565b600054610100900460ff16611e2e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610529565b60018055565b600054610100900460ff16611eb15760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610529565b61074e336112d4565b606061060f611ec883611fe2565b611f09565b604051606082811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208301529061060f90603401611966565b60608082516001148015611f375750608083600081518110611f2d57611f2d613375565b016020015160f81c105b15611f4357508161060f565b611f4f835160806120d5565b83604051602001611f6192919061348e565b604051602081830303815290604052905092915050565b606061060f611ec8836122cb565b606061060f611ec88367ffffffffffffffff166122cb565b60606000611fab8361242d565b9050611fb9815160c06120d5565b81604051602001611fcb92919061348e565b604051602081830303815290604052915050919050565b6060600082604051602001611ff991815260200190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815260208084528383019092529250600091829160208201818036833701905050905060005b81518110156120cc57838361205c8161320c565b94508151811061206e5761206e613375565b602001015160f81c60f81b82828151811061208b5761208b613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806120c48161320c565b915050612048565b50949350505050565b6060806038841015612154576040805160018082528183019092529060208201818036833701905050905061210a83856134bd565b60f81b8160008151811061212057612120613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061060c565b600060015b6121638187613408565b1561218957816121728161320c565b92506121829050610100826134e2565b9050612159565b6121948260016131f4565b67ffffffffffffffff8111156121ac576121ac612706565b6040519080825280601f01601f1916602001820160405280156121d6576020820181803683370190505b5092506121e385836134bd565b6121ee9060376134bd565b60f81b8360008151811061220457612204613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b8181116122c25761010061224c828461341c565b6122589061010061363f565b6122629088613408565b61226c9190613433565b60f81b83828151811061228157612281613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806122ba8161320c565b915050612238565b50509392505050565b60606000826040516020016122e291815260200190565b604051602081830303815290604052905060005b60208110156123545781818151811061231157612311613375565b01602001517fff00000000000000000000000000000000000000000000000000000000000000161561234257612354565b8061234c8161320c565b9150506122f6565b600061236182602061341c565b67ffffffffffffffff81111561237957612379612706565b6040519080825280601f01601f1916602001820160405280156123a3576020820181803683370190505b50905060005b81518110156120cc5783836123bd8161320c565b9450815181106123cf576123cf613375565b602001015160f81c60f81b8282815181106123ec576123ec613375565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350806124258161320c565b9150506123a9565b606081516000141561244d57505060408051600081526020810190915290565b6000805b83518110156124945783818151811061246c5761246c613375565b6020026020010151518261248091906131f4565b91508061248c8161320c565b915050612451565b60008267ffffffffffffffff8111156124af576124af612706565b6040519080825280601f01601f1916602001820160405280156124d9576020820181803683370190505b50600092509050602081015b85518310156120cc57600086848151811061250257612502613375565b6020026020010151905060006020820190506125208382845161255d565b87858151811061253257612532613375565b6020026020010151518361254691906131f4565b9250505082806125559061320c565b9350506124e5565b8282825b6020811061259957815183526125786020846131f4565b92506125856020836131f4565b915061259260208261341c565b9050612561565b905182516020929092036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0180199091169116179052505050565b73ffffffffffffffffffffffffffffffffffffffff811681146108ca57600080fd5b8035612605816125d8565b919050565b60006020828403121561261c57600080fd5b813561060c816125d8565b6000806040838503121561263a57600080fd5b8235612645816125d8565b946020939093013593505050565b60008083601f84011261266557600080fd5b50813567ffffffffffffffff81111561267d57600080fd5b60208301915083602082850101111561269557600080fd5b9250929050565b6000806000806000608086880312156126b457600080fd5b853594506020860135935060408601356126cd816125d8565b9250606086013567ffffffffffffffff8111156126e957600080fd5b6126f588828901612653565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101a0810167ffffffffffffffff8111828210171561275957612759612706565b60405290565b6040805190810167ffffffffffffffff8111828210171561275957612759612706565b604051610200810167ffffffffffffffff8111828210171561275957612759612706565b600082601f8301126127b757600080fd5b813567ffffffffffffffff808211156127d2576127d2612706565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561281857612818612706565b8160405283815286602085880101111561283157600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121561286357600080fd5b813567ffffffffffffffff81111561287a57600080fd5b611087848285016127a6565b60006020828403121561289857600080fd5b5035919050565b60208101600483106128da577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b8035801515811461260557600080fd5b6000806040838503121561290357600080fd5b82359150612913602084016128e0565b90509250929050565b60006101a0828403121561292f57600080fd5b50919050565b60006020828403121561294757600080fd5b813567ffffffffffffffff81111561295e57600080fd5b6110878482850161291c565b6000806000806060858703121561298057600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156129a557600080fd5b6129b187828801612653565b95989497509550505050565b600080604083850312156129d057600080fd5b82359150602083013567ffffffffffffffff8111156129ee57600080fd5b6129fa858286016127a6565b9150509250929050565b60008060408385031215612a1757600080fd5b823567ffffffffffffffff811115612a2e57600080fd5b612a3a8582860161291c565b925050612913602084016128e0565b600080600060408486031215612a5e57600080fd5b833567ffffffffffffffff80821115612a7657600080fd5b612a828783880161291c565b94506020860135915080821115612a9857600080fd5b50612aa586828701612653565b9497909650939450505050565b60006101a08236031215612ac557600080fd5b612acd612735565b82358152612add602084016125fa565b60208201526040830135604082015260608301356060820152612b02608084016125fa565b6080820152612b1360a084016125fa565b60a0820152612b2460c084016125fa565b60c082015260e083810135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013567ffffffffffffffff80821115612b7157600080fd5b612b7d368388016127a6565b83850152610180925082860135915080821115612b9957600080fd5b50612ba6368287016127a6565b918301919091525092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612be957600080fd5b830160208101925035905067ffffffffffffffff811115612c0957600080fd5b80360383131561269557600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60006101a082358452612c76602084016125fa565b73ffffffffffffffffffffffffffffffffffffffff81166020860152506040830135604085015260608301356060850152612cb3608084016125fa565b73ffffffffffffffffffffffffffffffffffffffff166080850152612cda60a084016125fa565b73ffffffffffffffffffffffffffffffffffffffff1660a0850152612d0160c084016125fa565b73ffffffffffffffffffffffffffffffffffffffff1660c085015260e08381013590850152610100808401359085015261012080840135908501526101408084013590850152610160612d5681850185612bb4565b8383880152612d688488018284612c18565b9350505050610180612d7c81850185612bb4565b86840383880152610667848284612c18565b84815273ffffffffffffffffffffffffffffffffffffffff84166020820152608060408201526000612dc36080830185612c61565b9050821515606083015295945050505050565b85815273ffffffffffffffffffffffffffffffffffffffff85166020820152608060408201526000612e0b6080830186612c61565b8281036060840152612e1e818587612c18565b98975050505050505050565b600082601f830112612e3b57600080fd5b60405161010080820182811067ffffffffffffffff82111715612e6057612e60612706565b60405283018185821115612e7357600080fd5b845b82811015612e8d578035825260209182019101612e75565b509195945050505050565b80356fffffffffffffffffffffffffffffffff8116811461260557600080fd5b803567ffffffffffffffff8116811461260557600080fd5b600060208284031215612ee257600080fd5b813567ffffffffffffffff80821115612efa57600080fd5b9083019060408286031215612f0e57600080fd5b612f1661275f565b823582811115612f2557600080fd5b83016102e08188031215612f3857600080fd5b612f40612782565b8135815260208201356020820152612f5a604083016125fa565b6040820152606082013560608201526080820135608082015260a082013560a0820152612f8a8860c08401612e2a565b60c08201526101c08083013560e08301526101e0612fa9818501612e98565b610100840152612fbc6102008501612eb8565b610120840152612fcf6102208501612eb8565b610140840152612fe26102408501612eb8565b61016084015261026084013586811115612ffb57600080fd5b6130078b8287016127a6565b610180850152506102808401356101a08401526130276102a08501612eb8565b828401526102c0840135818401525050808352505060208301358281111561304e57600080fd5b61305a878286016127a6565b60208301525095945050505050565b60005b8381101561308457818101518382015260200161306c565b83811115613093576000848401525b50505050565b600081518084526130b1816020860160208601613069565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b85815273ffffffffffffffffffffffffffffffffffffffff8516602082015283604082015282606082015260a06080820152600061066760a0830184613099565b60006020828403121561313657600080fd5b815161060c816125d8565b60006020828403121561315357600080fd5b5051919050565b6000835161316c818460208801613069565b7f2e0000000000000000000000000000000000000000000000000000000000000090830190815283516131a6816001840160208801613069565b01600101949350505050565b60208152600061060c6020830184613099565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115613207576132076131c5565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561323e5761323e6131c5565b5060010190565b60006101a0825184526020830151613275602086018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015160408501526060830151606085015260808301516132b1608086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08301516132d960a086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015161330160c086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083810151908501526101008084015190850152610120808401519085015261014080840151908501526101608084015181860183905261334683870182613099565b92505050610180808401518583038287015261081a8382613099565b60208152600061060c6020830184613245565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008183825b60088110156133c95781518352602092830192909101906001016133aa565b5050506101008201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613417576134176133d9565b500490565b60008282101561342e5761342e6131c5565b500390565b600082613442576134426133d9565b500690565b60408152601460408201527f5441494b4f5f4252494447455f4d455353414745000000000000000000000000606082015260806020820152600061060c6080830184613245565b600083516134a0818460208801613069565b8351908301906134b4818360208801613069565b01949350505050565b600060ff821660ff84168060ff038211156134da576134da6131c5565b019392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561351a5761351a6131c5565b500290565b600181815b8085111561357857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561355e5761355e6131c5565b8085161561356b57918102915b93841c9390800290613524565b509250929050565b60008261358f5750600161060f565b8161359c5750600061060f565b81600181146135b257600281146135bc576135d8565b600191505061060f565b60ff8411156135cd576135cd6131c5565b50506001821b61060f565b5060208310610133831016604e8410600b84101617156135fb575081810a61060f565b613605838361351f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115613637576136376131c5565b029392505050565b600061060c838361358056fea2646970667358221220d5e1fe055176dc14480cf9170f5a503d79f8793c534119929c5bbb34db12f54764736f6c63430008090033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000002": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000026250179c8e8e12104e556c4cd03bcf4dabd51b9", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006" + }, + "code": "0x6080604052600436106100d25760003560e01c8063715018a61161007f578063c287e57811610059578063c287e57814610228578063ee1490b214610268578063f16c79341461027b578063f2fde38b1461029b57600080fd5b8063715018a6146101c45780638da5cb5b146101d95780639aa8605c146101f757600080fd5b80633ab76e9f116100b05780633ab76e9f1461012c578063461a44781461016357806367090ccf1461018357600080fd5b80630c6fab82146100d757806319ab453c146100f957806339da33ba14610119575b600080fd5b3480156100e357600080fd5b506100f76100f2366004612459565b6102bb565b005b34801561010557600080fd5b506100f76101143660046124c8565b6105f9565b6100f76101273660046125c3565b610773565b34801561013857600080fd5b506097546001600160a01b03165b6040516001600160a01b0390911681526020015b60405180910390f35b34801561016f57600080fd5b5061014661017e366004612641565b610ad1565b34801561018f57600080fd5b5061014661019e366004612676565b60cb6020908152600092835260408084209091529082529020546001600160a01b031681565b3480156101d057600080fd5b506100f7610ae3565b3480156101e557600080fd5b506065546001600160a01b0316610146565b34801561020357600080fd5b506102176102123660046124c8565b610af7565b60405161015a9594939291906126fe565b34801561023457600080fd5b506102586102433660046124c8565b60c96020526000908152604090205460ff1681565b604051901515815260200161015a565b6100f761027636600461274d565b610c59565b34801561028757600080fd5b506101466102963660046127e9565b611682565b3480156102a757600080fd5b506100f76102b63660046124c8565b611695565b600260015414156103135760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260015560408051808201909152600681527f6272696467650000000000000000000000000000000000000000000000000000602082015261035581610ad1565b6001600160a01b0316336001600160a01b0316146103b55760405162461bcd60e51b815260206004820152600960248201527f41523a64656e6965640000000000000000000000000000000000000000000000604482015260640161030a565b6000336001600160a01b031663d0496d6a6040518163ffffffff1660e01b815260040160606040518083038186803b1580156103f057600080fd5b505afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190612830565b905061046d81604001516040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250611682565b6001600160a01b031681602001516001600160a01b0316146104d15760405162461bcd60e51b815260206004820152600860248201527f563a73656e646572000000000000000000000000000000000000000000000000604482015260640161030a565b60008635461415610507576104ec60408801602089016124c8565b90506105026001600160a01b0382168686611725565b610590565b610510876117d3565b6040517f42e91bb30000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201879052919250908216906342e91bb390604401600060405180830381600087803b15801561057757600080fd5b505af115801561058b573d6000803e3d6000fd5b505050505b60408281015181516001600160a01b038981168252602082019290925283821681840152606081018790529151908716917f485a7041eaecffd5ef478f291c05a2a47a1e6af7e7780e46578f18bf03e1bf3f919081900360800190a25050600180555050505050565b600054610100900460ff16158080156106195750600054600160ff909116105b806106335750303b158015610633575060005460ff166001145b6106a55760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161030a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561070357600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61070c8261182c565b801561076f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600260015414156107c65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030a565b60026001556001600160a01b03851615801590610833575061081d866040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250611682565b6001600160a01b0316856001600160a01b031614155b6108815760405162461bcd60e51b815260040161030a9060208082526004908201527f563a746f00000000000000000000000000000000000000000000000000000000604082015260600190565b8234116108d05760405162461bcd60e51b815260206004820152600a60248201527f563a6d736756616c756500000000000000000000000000000000000000000000604482015260640161030a565b61095f604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018790523360808201526001600160a01b03861660a08201526101408101859052610120810184905261099584346128c1565b60e08201526001600160a01b03831660c0820152610180810182905260408051808201909152600681527f627269646765000000000000000000000000000000000000000000000000000060208201526000906109f190610ad1565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b8152600401610a1d91906128d8565b6020604051808303818588803b158015610a3657600080fd5b505af1158015610a4a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610a6f91906129d2565b60e0830151604080518b8152602081019290925281018290529091506001600160a01b038816907fc4f150c33b1c9146a833662318b1e72e3d07a471886bb6f3a547a8e0bc3a7cfa9060600160405180910390a2505060018055505050505050565b6000610add4683611845565b92915050565b610aeb611913565b610af5600061196d565b565b60ca6020526000908152604090208054600182015460028301805492936001600160a01b038316937401000000000000000000000000000000000000000090930460ff1692909190610b48906129eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610b74906129eb565b8015610bc15780601f10610b9657610100808354040283529160200191610bc1565b820191906000526020600020905b815481529060010190602001808311610ba457829003601f168201915b505050505090806003018054610bd6906129eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610c02906129eb565b8015610c4f5780601f10610c2457610100808354040283529160200191610c4f565b820191906000526020600020905b815481529060010190602001808311610c3257829003601f168201915b5050505050905085565b60026001541415610cac5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030a565b60026001556001600160a01b03871615801590610d195750610d03886040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250611682565b6001600160a01b0316876001600160a01b031614155b610d675760405162461bcd60e51b815260040161030a9060208082526004908201527f563a746f00000000000000000000000000000000000000000000000000000000604082015260600190565b6001600160a01b038616610dbd5760405162461bcd60e51b815260206004820152600760248201527f563a746f6b656e00000000000000000000000000000000000000000000000000604482015260640161030a565b60008511610e0d5760405162461bcd60e51b815260206004820152600860248201527f563a616d6f756e74000000000000000000000000000000000000000000000000604482015260640161030a565b6040805160a08101825260008082526020820181905291810191909152606080820181905260808201526001600160a01b038716600090815260c9602052604081205460ff16156110bd576040517f77be18a8000000000000000000000000000000000000000000000000000000008152336004820152602481018890526001600160a01b038916906377be18a890604401600060405180830381600087803b158015610eb957600080fd5b505af1158015610ecd573d6000803e3d6000fd5b505050506001600160a01b03888116600090815260ca6020908152604091829020825160a081018452815481526001820154948516928101929092527401000000000000000000000000000000000000000090930460ff1691810191909152600282018054919291606084019190610f44906129eb565b80601f0160208091040260200160405190810160405280929190818152602001828054610f70906129eb565b8015610fbd5780601f10610f9257610100808354040283529160200191610fbd565b820191906000526020600020905b815481529060010190602001808311610fa057829003601f168201915b50505050508152602001600382018054610fd6906129eb565b80601f0160208091040260200160405190810160405280929190818152602001828054611002906129eb565b801561104f5780601f106110245761010080835404028352916020019161104f565b820191906000526020600020905b81548152906001019060200180831161103257829003601f168201915b5050509190925250505060208101519092506001600160a01b03166110b65760405162461bcd60e51b815260206004820152601060248201527f563a63616e6f6e6963616c546f6b656e00000000000000000000000000000000604482015260640161030a565b508561139a565b60008890506040518060a001604052804681526020018a6001600160a01b03168152602001826001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561111b57600080fd5b505afa15801561112f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111539190612a4e565b60ff168152602001826001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561119457600080fd5b505afa1580156111a8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111d09190810190612a6b565b8152602001826001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b15801561120e57600080fd5b505afa158015611222573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261124a9190810190612a6b565b90526040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529093506000906001600160a01b038316906370a082319060240160206040518083038186803b1580156112aa57600080fd5b505afa1580156112be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112e291906129d2565b90506112f96001600160a01b03831633308c6119d7565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038416906370a082319060240160206040518083038186803b15801561135357600080fd5b505afa158015611367573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138b91906129d2565b61139591906128c1565b925050505b611429604051806101a001604052806000815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b606081018b905233608082015260408051808201909152600b81527f746f6b656e5f7661756c740000000000000000000000000000000000000000006020820152611475908c90611682565b6001600160a01b031660a082015260808101516040517f0c6fab8200000000000000000000000000000000000000000000000000000000916114c0918691908e908790602401612ae2565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526101608201526101408101879052610120810186905261153f86346128c1565b60e08201526001600160a01b03851660c0820152610180810184905260408051808201909152600681527f6272696467650000000000000000000000000000000000000000000000000000602082015260009061159b90610ad1565b6001600160a01b03166396e1785234846040518363ffffffff1660e01b81526004016115c791906128d8565b6020604051808303818588803b1580156115e057600080fd5b505af11580156115f4573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061161991906129d2565b604080518e81526001600160a01b038d81166020830152918101869052606081018390529192508c16907ffd41c851d9a68cdf761055c8f7cb21010b653b27f89f6e3fa224a75eb82a40ac9060800160405180910390a250506001805550505050505050505050565b600061168e8383611845565b9392505050565b61169d611913565b6001600160a01b0381166117195760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161030a565b6117228161196d565b50565b6040516001600160a01b0383166024820152604481018290526117ce9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611a2e565b505050565b8035600090815260cb602090815260408083208392909183916117fa9187019087016124c8565b6001600160a01b03908116825260208201929092526040016000205416905080610add5761182783611b13565b61168e565b611834611dd0565b61183c611e55565b61172281611eda565b60008061185184611f6a565b83604051602001611863929190612b99565b60408051601f19818403018152908290526097547fbf40fac10000000000000000000000000000000000000000000000000000000083529092506001600160a01b03169063bf40fac1906118bb908490600401612bf1565b60206040518083038186803b1580156118d357600080fd5b505afa1580156118e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190b9190612c04565b949350505050565b6065546001600160a01b03163314610af55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161030a565b606580546001600160a01b038381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6040516001600160a01b0380851660248301528316604482015260648101829052611a289085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161176a565b50505050565b6000611a83826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661209c9092919063ffffffff16565b8051909150156117ce5780806020019051810190611aa19190612c21565b6117ce5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161030a565b6000808235611b2860408501602086016124c8565b604051602001611b6792919091825260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602082015260340190565b604051602081830303815290604052805190602001209050611bad60008260405180602001611b9590612437565b601f1982820381018352601f909101166040526120ab565b6097549092506001600160a01b0380841691636c0db62b9116611bd660408701602088016124c8565b8635611be86060890160408a01612c43565b611bf560608a018a612c60565b611c0260808c018c612c60565b604051611c169291908e3590602001612ccc565b6040516020818303038152906040526040518863ffffffff1660e01b8152600401611c479796959493929190612d7a565b600060405180830381600087803b158015611c6157600080fd5b505af1158015611c75573d6000803e3d6000fd5b5050506001600160a01b038316600090815260c96020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905560ca9091529020849150611cd08282612f21565b50508235600090815260cb60209081526040808320859390929091611cfa919088019088016124c8565b6001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b0316836020016020810190611d5b91906124c8565b6001600160a01b031684357f9e465b29e576a3e01584e31d607353f21b80c055e813af907c0a495f6cf4f7bc611d946060880188612c60565b611da160808a018a612c60565b611db160608c0160408d01612c43565b604051611dc2959493929190612ff9565b60405180910390a450919050565b600054610100900460ff16611e4d5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161030a565b610af56121ad565b600054610100900460ff16611ed25760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161030a565b610af5612230565b6001600160a01b038116611f305760405162461bcd60e51b815260206004820152600e60248201527f41523a7a65726f41646472657373000000000000000000000000000000000000604482015260640161030a565b609780547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b606081611faa57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115611fd45780611fbe81613036565b9150611fcd9050600a8361309e565b9150611fae565b60008167ffffffffffffffff811115611fef57611fef6124e5565b6040519080825280601f01601f191660200182016040528015612019576020820181803683370190505b5090505b841561190b5761202e6001836128c1565b915061203b600a866130b2565b6120469060306130c6565b60f81b81838151811061205b5761205b6130de565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612095600a8661309e565b945061201d565b606061190b84846000856122b6565b600080844710156120fe5760405162461bcd60e51b815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e6365000000604482015260640161030a565b825161214c5760405162461bcd60e51b815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f604482015260640161030a565b8383516020850187f590506001600160a01b03811661190b5760405162461bcd60e51b815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f7900000000000000604482015260640161030a565b600054610100900460ff1661222a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161030a565b60018055565b600054610100900460ff166122ad5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161030a565b610af53361196d565b60608247101561232e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161030a565b6001600160a01b0385163b6123855760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161030a565b600080866001600160a01b031685876040516123a1919061310d565b60006040518083038185875af1925050503d80600081146123de576040519150601f19603f3d011682016040523d82523d6000602084013e6123e3565b606091505b50915091506123f38282866123fe565b979650505050505050565b6060831561240d57508161168e565b82511561241d5782518084602001fd5b8160405162461bcd60e51b815260040161030a9190612bf1565b6120a08061312a83390190565b6001600160a01b038116811461172257600080fd5b6000806000806080858703121561246f57600080fd5b843567ffffffffffffffff81111561248657600080fd5b850160a0818803121561249857600080fd5b935060208501356124a881612444565b925060408501356124b881612444565b9396929550929360600135925050565b6000602082840312156124da57600080fd5b813561168e81612444565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561253d5761253d6124e5565b604052919050565b600067ffffffffffffffff82111561255f5761255f6124e5565b50601f01601f191660200190565b600082601f83011261257e57600080fd5b813561259161258c82612545565b612514565b8181528460208386010111156125a657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156125dc57600080fd5b8635955060208701356125ee81612444565b94506040870135935060608701359250608087013561260c81612444565b915060a087013567ffffffffffffffff81111561262857600080fd5b61263489828a0161256d565b9150509295509295509295565b60006020828403121561265357600080fd5b813567ffffffffffffffff81111561266a57600080fd5b61190b8482850161256d565b6000806040838503121561268957600080fd5b82359150602083013561269b81612444565b809150509250929050565b60005b838110156126c15781810151838201526020016126a9565b83811115611a285750506000910152565b600081518084526126ea8160208601602086016126a6565b601f01601f19169290920160200192915050565b8581526001600160a01b038516602082015260ff8416604082015260a06060820152600061272f60a08301856126d2565b828103608084015261274181856126d2565b98975050505050505050565b600080600080600080600080610100898b03121561276a57600080fd5b88359750602089013561277c81612444565b9650604089013561278c81612444565b9550606089013594506080890135935060a0890135925060c08901356127b181612444565b915060e089013567ffffffffffffffff8111156127cd57600080fd5b6127d98b828c0161256d565b9150509295985092959890939650565b600080604083850312156127fc57600080fd5b82359150602083013567ffffffffffffffff81111561281a57600080fd5b6128268582860161256d565b9150509250929050565b60006060828403121561284257600080fd5b6040516060810181811067ffffffffffffffff82111715612865576128656124e5565b60405282518152602083015161287a81612444565b60208201526040928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156128d3576128d3612892565b500390565b6020815281516020820152600060208301516128ff60408401826001600160a01b03169052565b506040830151606083015260608301516080830152608083015161292e60a08401826001600160a01b03169052565b5060a08301516001600160a01b03811660c08401525060c08301516001600160a01b03811660e08401525060e0830151610100838101919091528301516101208084019190915283015161014080840191909152830151610160808401919091528301516101a06101808085018290526129ac6101c08601846126d2565b90860151858203601f1901838701529092506129c883826126d2565b9695505050505050565b6000602082840312156129e457600080fd5b5051919050565b600181811c908216806129ff57607f821691505b60208210811415612a39577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60ff8116811461172257600080fd5b600060208284031215612a6057600080fd5b815161168e81612a3f565b600060208284031215612a7d57600080fd5b815167ffffffffffffffff811115612a9457600080fd5b8201601f81018413612aa557600080fd5b8051612ab361258c82612545565b818152856020838501011115612ac857600080fd5b612ad98260208301602086016126a6565b95945050505050565b6080815284516080820152600060208601516001600160a01b0380821660a085015260ff60408901511660c08501526060880151915060a060e0850152612b2d6101208501836126d2565b915060808801517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8085840301610100860152612b6983826126d2565b9188166020860152506001600160a01b03861660408501529150612b8a9050565b82606083015295945050505050565b60008351612bab8184602088016126a6565b7f2e000000000000000000000000000000000000000000000000000000000000009083019081528351612be58160018401602088016126a6565b01600101949350505050565b60208152600061168e60208301846126d2565b600060208284031215612c1657600080fd5b815161168e81612444565b600060208284031215612c3357600080fd5b8151801515811461168e57600080fd5b600060208284031215612c5557600080fd5b813561168e81612a3f565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612c9557600080fd5b83018035915067ffffffffffffffff821115612cb057600080fd5b602001915036819003821315612cc557600080fd5b9250929050565b828482377f286272696467656400000000000000000000000000000000000000000000000092019182527ff09f8c88000000000000000000000000000000000000000000000000000000006008830152600c8201527f2900000000000000000000000000000000000000000000000000000000000000602c820152602d01919050565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b60006001600160a01b03808a16835280891660208401525086604083015260ff8616606083015260c06080830152612db660c083018587612d4f565b82810360a0840152612dc881856126d2565b9a9950505050505050505050565b601f8211156117ce57600081815260208120601f850160051c81016020861015612dfd5750805b601f850160051c820191505b81811015612e1c57828155600101612e09565b505050505050565b67ffffffffffffffff831115612e3c57612e3c6124e5565b612e5083612e4a83546129eb565b83612dd6565b6000601f841160018114612ea25760008515612e6c5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355612f1a565b600083815260209020601f19861690835b82811015612ed35786850135825560209485019460019092019101612eb3565b5086821015612f0e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b81358155600181016020830135612f3781612444565b6001600160a01b03811690508154817fffffffffffffffffffffffff000000000000000000000000000000000000000082161783556040850135612f7a81612a3f565b74ff00000000000000000000000000000000000000008160a01b16837fffffffffffffffffffffff00000000000000000000000000000000000000000084161717845550505050612fce6060830183612c60565b612fdc818360028601612e24565b5050612feb6080830183612c60565b611a28818360038601612e24565b60608152600061300d606083018789612d4f565b8281036020840152613020818688612d4f565b91505060ff831660408301529695505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561306857613068612892565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826130ad576130ad61306f565b500490565b6000826130c1576130c161306f565b500690565b600082198211156130d9576130d9612892565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000825161311f8184602087016126a6565b919091019291505056fe608060405234801561001057600080fd5b50612080806100206000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c80636c0db62b116100e357806395d89b411161008c578063dd62ed3e11610066578063dd62ed3e146103b0578063f16c7934146103f6578063f2fde38b1461040957600080fd5b806395d89b4114610382578063a457c2d71461038a578063a9059cbb1461039d57600080fd5b806377be18a8116100bd57806377be18a8146103315780637cf8ed0d146103445780638da5cb5b1461036457600080fd5b80636c0db62b146102e057806370a08231146102f3578063715018a61461032957600080fd5b80633950935111610145578063461a44781161011f578063461a44781461027457806349d126051461028757806367e828bf1461029057600080fd5b8063395093511461020d5780633ab76e9f1461022057806342e91bb31461025f57600080fd5b806318160ddd1161017657806318160ddd146101d357806323b872dd146101e5578063313ce567146101f857600080fd5b806306fdde0314610192578063095ea7b3146101b0575b600080fd5b61019a61041c565b6040516101a79190611b2e565b60405180910390f35b6101c36101be366004611ba1565b6104ae565b60405190151581526020016101a7565b60cb545b6040519081526020016101a7565b6101c36101f3366004611bcd565b6104c6565b60ce5460405160ff90911681526020016101a7565b6101c361021b366004611ba1565b610546565b60975473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a7565b61027261026d366004611ba1565b610592565b005b61023a610282366004611ce8565b6106aa565b6101d760fc5481565b6102b460fb5460fc5473ffffffffffffffffffffffffffffffffffffffff90911691565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016101a7565b6102726102ee366004611d1d565b6106bc565b6101d7610301366004611dc7565b73ffffffffffffffffffffffffffffffffffffffff16600090815260c9602052604090205490565b610272610921565b61027261033f366004611ba1565b610935565b60fb5461023a9073ffffffffffffffffffffffffffffffffffffffff1681565b60655473ffffffffffffffffffffffffffffffffffffffff1661023a565b61019a610a40565b6101c3610398366004611ba1565b610a4f565b6101c36103ab366004611ba1565b610b11565b6101d76103be366004611de4565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260ca6020908152604080832093909416825291909152205490565b61023a610404366004611e1d565b610b8a565b610272610417366004611dc7565b610b96565b606060cc805461042b90611e64565b80601f016020809104026020016040519081016040528092919081815260200182805461045790611e64565b80156104a45780601f10610479576101008083540402835291602001916104a4565b820191906000526020600020905b81548152906001019060200180831161048757829003601f168201915b5050505050905090565b6000336104bc818585610c33565b5060019392505050565b600073ffffffffffffffffffffffffffffffffffffffff83163014156105335760405162461bcd60e51b815260206004820152600560248201527f42453a746f00000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b61053e848484610db2565b949350505050565b33600081815260ca6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906104bc908290869061058d908790611ee7565b610c33565b6040518060400160405280600b81526020017f746f6b656e5f7661756c740000000000000000000000000000000000000000008152506105d1816106aa565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461064b5760405162461bcd60e51b815260206004820152600960248201527f41523a64656e6965640000000000000000000000000000000000000000000000604482015260640161052a565b6106558383610dcb565b8273ffffffffffffffffffffffffffffffffffffffff167f397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa68360405161069d91815260200190565b60405180910390a2505050565b60006106b64683610e89565b92915050565b600054610100900460ff16158080156106dc5750600054600160ff909116105b806106f65750303b1580156106f6575060005460ff166001145b6107685760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161052a565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156107c657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b73ffffffffffffffffffffffffffffffffffffffff8616158015906107ea57508415155b80156107f65750468514155b8015610803575060008351115b8015610810575060008251115b61085c5760405162461bcd60e51b815260206004820152600960248201527f42453a706172616d730000000000000000000000000000000000000000000000604482015260640161052a565b61086587610f7a565b610870828486610f93565b60fb80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff881617905560fc859055801561091857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b610929611020565b6109336000611087565b565b6040518060400160405280600b81526020017f746f6b656e5f7661756c74000000000000000000000000000000000000000000815250610974816106aa565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146109ee5760405162461bcd60e51b815260206004820152600960248201527f41523a64656e6965640000000000000000000000000000000000000000000000604482015260640161052a565b6109f883836110fe565b8273ffffffffffffffffffffffffffffffffffffffff167f9b5b9a05e4726d8bb959f1440e05c6b8109443f2083bc4e386237d76545265538360405161069d91815260200190565b606060cd805461042b90611e64565b33600081815260ca6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610af95760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f000000000000000000000000000000000000000000000000000000606482015260840161052a565b610b068286868403610c33565b506001949350505050565b600073ffffffffffffffffffffffffffffffffffffffff8316301415610b795760405162461bcd60e51b815260206004820152600560248201527f42453a746f000000000000000000000000000000000000000000000000000000604482015260640161052a565b610b83838361126f565b9392505050565b6000610b838383610e89565b610b9e611020565b73ffffffffffffffffffffffffffffffffffffffff8116610c275760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161052a565b610c3081611087565b50565b73ffffffffffffffffffffffffffffffffffffffff8316610cbb5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f7265737300000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff8216610d445760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260ca602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600033610dc085828561127d565b610b0685858561133a565b73ffffffffffffffffffffffffffffffffffffffff8216610e2e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161052a565b8060cb6000828254610e409190611ee7565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260c9602052604081208054839290610e7a908490611ee7565b90915550610e859050565b5050565b600080610e958461159f565b83604051602001610ea7929190611eff565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac190610f2a908490600401611b2e565b60206040518083038186803b158015610f4257600080fd5b505afa158015610f56573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053e9190611f57565b610f826116d1565b610f8a611756565b610c30816117db565b600054610100900460ff166110105760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b61101b838383611885565b505050565b60655473ffffffffffffffffffffffffffffffffffffffff1633146109335760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161052a565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b73ffffffffffffffffffffffffffffffffffffffff82166111875760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f7300000000000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260c96020526040902054818110156112235760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f6365000000000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260c960205260408120838303905560cb805484929061125f908490611f74565b9091555061101b90508360008483565b6000336104bc81858561133a565b73ffffffffffffffffffffffffffffffffffffffff838116600090815260ca60209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461133457818110156113275760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161052a565b6113348484848403610c33565b50505050565b73ffffffffffffffffffffffffffffffffffffffff83166113c35760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f6472657373000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff821661144c5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f6573730000000000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260c96020526040902054818110156114e85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e63650000000000000000000000000000000000000000000000000000606482015260840161052a565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260c9602052604080822085850390559185168152908120805484929061152c908490611ee7565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161159291815260200190565b60405180910390a3611334565b6060816115df57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561160957806115f381611f8b565b91506116029050600a83611ff3565b91506115e3565b60008167ffffffffffffffff81111561162457611624611c0e565b6040519080825280601f01601f19166020018201604052801561164e576020820181803683370190505b5090505b841561053e57611663600183611f74565b9150611670600a86612007565b61167b906030611ee7565b60f81b8183815181106116905761169061201b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506116ca600a86611ff3565b9450611652565b600054610100900460ff1661174e5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b610933611960565b600054610100900460ff166117d35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b6109336119e3565b73ffffffffffffffffffffffffffffffffffffffff811661183e5760405162461bcd60e51b815260206004820152600e60248201527f41523a7a65726f41646472657373000000000000000000000000000000000000604482015260640161052a565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600054610100900460ff166119025760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b82516119159060cc906020860190611a69565b5081516119299060cd906020850190611a69565b5060ce80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff929092169190911790555050565b600054610100900460ff166119dd5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b60018055565b600054610100900460ff16611a605760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161052a565b61093333611087565b828054611a7590611e64565b90600052602060002090601f016020900481019282611a975760008555611add565b82601f10611ab057805160ff1916838001178555611add565b82800160010185558215611add579182015b82811115611add578251825591602001919060010190611ac2565b50611ae9929150611aed565b5090565b5b80821115611ae95760008155600101611aee565b60005b83811015611b1d578181015183820152602001611b05565b838111156113345750506000910152565b6020815260008251806020840152611b4d816040850160208701611b02565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c3057600080fd5b60008060408385031215611bb457600080fd5b8235611bbf81611b7f565b946020939093013593505050565b600080600060608486031215611be257600080fd5b8335611bed81611b7f565b92506020840135611bfd81611b7f565b929592945050506040919091013590565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112611c4e57600080fd5b813567ffffffffffffffff80821115611c6957611c69611c0e565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611caf57611caf611c0e565b81604052838152866020858801011115611cc857600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215611cfa57600080fd5b813567ffffffffffffffff811115611d1157600080fd5b61053e84828501611c3d565b60008060008060008060c08789031215611d3657600080fd5b8635611d4181611b7f565b95506020870135611d5181611b7f565b945060408701359350606087013560ff81168114611d6e57600080fd5b9250608087013567ffffffffffffffff80821115611d8b57600080fd5b611d978a838b01611c3d565b935060a0890135915080821115611dad57600080fd5b50611dba89828a01611c3d565b9150509295509295509295565b600060208284031215611dd957600080fd5b8135610b8381611b7f565b60008060408385031215611df757600080fd5b8235611e0281611b7f565b91506020830135611e1281611b7f565b809150509250929050565b60008060408385031215611e3057600080fd5b82359150602083013567ffffffffffffffff811115611e4e57600080fd5b611e5a85828601611c3d565b9150509250929050565b600181811c90821680611e7857607f821691505b60208210811415611eb2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611efa57611efa611eb8565b500190565b60008351611f11818460208801611b02565b7f2e000000000000000000000000000000000000000000000000000000000000009083019081528351611f4b816001840160208801611b02565b01600101949350505050565b600060208284031215611f6957600080fd5b8151610b8381611b7f565b600082821015611f8657611f86611eb8565b500390565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611fbd57611fbd611eb8565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261200257612002611fc4565b500490565b60008261201657612016611fc4565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea2646970667358221220f24dcb708d1867134df56fe5efc5ccc3a875e0deca527b2af220b5bde7e6b93664736f6c63430008090033a2646970667358221220abf8c5a35e42ce1f54480f59a3b073492445c3fe339322ddb4639465be6e49ee64736f6c63430008090033", + "balance": "0x0" + }, + "0x0000777700000000000000000000000000000003": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000065": "0x00000000000000000000000026250179c8e8e12104e556c4cd03bcf4dabd51b9", + "0x0000000000000000000000000000000000000000000000000000000000000097": "0x0000000000000000000000000000777700000000000000000000000000000006", + "0x029ae2e2f1d6964720a0fa7e6ffa902f995c156242f4f5a930aa9d9765d167d0": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "code": "0x6080604052600436106100b55760003560e01c8063715018a611610069578063f16c79341161004e578063f16c79341461023f578063f2fde38b1461025f578063fe9fbb801461027f57600080fd5b8063715018a6146101ff5780638da5cb5b1461021457600080fd5b80632d1fb3891161009a5780632d1fb3891461016e5780633ab76e9f1461018e578063461a4478146101df57600080fd5b806319ab453c1461012e5780631efa4ec01461014e57600080fd5b36610129574715806100d6575033600090815260c9602052604090205460ff165b6101275760405162461bcd60e51b815260206004820152600960248201527f45563a64656e696564000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b005b600080fd5b34801561013a57600080fd5b50610127610149366004610dd8565b6102d5565b34801561015a57600080fd5b50610127610169366004610df5565b61044f565b34801561017a57600080fd5b50610127610189366004610e0e565b610517565b34801561019a57600080fd5b5060975473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101eb57600080fd5b506101b56101fa366004610f26565b610646565b34801561020b57600080fd5b50610127610658565b34801561022057600080fd5b5060655473ffffffffffffffffffffffffffffffffffffffff166101b5565b34801561024b57600080fd5b506101b561025a366004610f5b565b61066c565b34801561026b57600080fd5b5061012761027a366004610dd8565b61067f565b34801561028b57600080fd5b506102c561029a366004610dd8565b73ffffffffffffffffffffffffffffffffffffffff16600090815260c9602052604090205460ff1690565b60405190151581526020016101d6565b600054610100900460ff16158080156102f55750600054600160ff909116105b8061030f5750303b15801561030f575060005460ff166001145b6103815760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840161011e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156103df57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6103e88261071c565b801561044b57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b33600090815260c9602052604090205460ff166104ae5760405162461bcd60e51b815260206004820152600960248201527f45563a64656e6965640000000000000000000000000000000000000000000000604482015260640161011e565b600260015414156105015760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161011e565b60026001556105103382610735565b5060018055565b61051f6107f0565b73ffffffffffffffffffffffffffffffffffffffff821615801590610570575073ffffffffffffffffffffffffffffffffffffffff8216600090815260c9602052604090205460ff16151581151514155b6105bc5760405162461bcd60e51b815260206004820152600860248201527f45563a706172616d000000000000000000000000000000000000000000000000604482015260640161011e565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260c9602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f4c0079b9bcd37cd5d29a13938effd97c881798cbc6bd52a3026a29d94b27d1bf910160405180910390a25050565b60006106524683610857565b92915050565b6106606107f0565b61066a6000610950565b565b60006106788383610857565b9392505050565b6106876107f0565b73ffffffffffffffffffffffffffffffffffffffff81166107105760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161011e565b61071981610950565b50565b6107246109c7565b61072c610a4c565b61071981610ad1565b801561044b5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610795576040519150601f19603f3d011682016040523d82523d6000602084013e61079a565b606091505b50509050806107eb5760405162461bcd60e51b815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161011e565b505050565b60655473ffffffffffffffffffffffffffffffffffffffff16331461066a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161011e565b60008061086384610b7b565b83604051602001610875929190610fd2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526097547fbf40fac100000000000000000000000000000000000000000000000000000000835290925073ffffffffffffffffffffffffffffffffffffffff169063bf40fac1906108f890849060040161102a565b60206040518083038186803b15801561091057600080fd5b505afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610948919061107b565b949350505050565b6065805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff16610a445760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161011e565b61066a610cad565b600054610100900460ff16610ac95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161011e565b61066a610d30565b73ffffffffffffffffffffffffffffffffffffffff8116610b345760405162461bcd60e51b815260206004820152600e60248201527f41523a7a65726f41646472657373000000000000000000000000000000000000604482015260640161011e565b609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b606081610bbb57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115610be55780610bcf816110c7565b9150610bde9050600a8361112f565b9150610bbf565b60008167ffffffffffffffff811115610c0057610c00610e4c565b6040519080825280601f01601f191660200182016040528015610c2a576020820181803683370190505b5090505b841561094857610c3f600183611143565b9150610c4c600a8661115a565b610c5790603061116e565b60f81b818381518110610c6c57610c6c611186565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350610ca6600a8661112f565b9450610c2e565b600054610100900460ff16610d2a5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161011e565b60018055565b600054610100900460ff16610dad5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161011e565b61066a33610950565b73ffffffffffffffffffffffffffffffffffffffff8116811461071957600080fd5b600060208284031215610dea57600080fd5b813561067881610db6565b600060208284031215610e0757600080fd5b5035919050565b60008060408385031215610e2157600080fd5b8235610e2c81610db6565b915060208301358015158114610e4157600080fd5b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610e8c57600080fd5b813567ffffffffffffffff80821115610ea757610ea7610e4c565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610eed57610eed610e4c565b81604052838152866020858801011115610f0657600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610f3857600080fd5b813567ffffffffffffffff811115610f4f57600080fd5b61094884828501610e7b565b60008060408385031215610f6e57600080fd5b82359150602083013567ffffffffffffffff811115610f8c57600080fd5b610f9885828601610e7b565b9150509250929050565b60005b83811015610fbd578181015183820152602001610fa5565b83811115610fcc576000848401525b50505050565b60008351610fe4818460208801610fa2565b7f2e00000000000000000000000000000000000000000000000000000000000000908301908152835161101e816001840160208801610fa2565b01600101949350505050565b6020815260008251806020840152611049816040850160208701610fa2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561108d57600080fd5b815161067881610db6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156110f9576110f9611098565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261113e5761113e611100565b500490565b60008282101561115557611155611098565b500390565b60008261116957611169611100565b500690565b6000821982111561118157611181611098565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea2646970667358221220a9a80c6d09a8fe0110adcdabd6682b37ae15ded4282fed28d917343fa3f34e2564736f6c63430008090033", + "balance": "0xffffffffffffffc87d2531626fffffff" + } +} diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index f257ee8bb89a..00a067bd1a26 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -38,8 +38,8 @@ impl TryFrom for Block { )) }) .collect(), - alloy_rpc_types::BlockTransactions::Hashes(_) | - alloy_rpc_types::BlockTransactions::Uncle => { + alloy_rpc_types::BlockTransactions::Hashes(_) + | alloy_rpc_types::BlockTransactions::Uncle => { // alloy deserializes empty blocks into `BlockTransactions::Hashes`, if the tx // root is the empty root then we can just return an empty vec. if block.header.transactions_root == EMPTY_TRANSACTIONS { @@ -82,7 +82,7 @@ impl TryFrom for Transaction { return Err(ConversionError::Eip2718Error( RlpError::Custom("EIP-1559 fields are present in a legacy transaction") .into(), - )) + )); } // extract the chain id if possible @@ -98,7 +98,7 @@ impl TryFrom for Transaction { .map_err(|err| ConversionError::Eip2718Error(err.into()))? .1 } else { - return Err(ConversionError::MissingChainId) + return Err(ConversionError::MissingChainId); } } }; @@ -151,6 +151,7 @@ impl TryFrom for Transaction { value: tx.value, access_list: tx.access_list.ok_or(ConversionError::MissingAccessList)?, input: tx.input, + is_anchor: false, })) } Some(TxType::Eip4844) => { diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 9b5e172e8fc2..345b301666d7 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -171,7 +171,7 @@ impl Block { } } -#[cfg(feature = "arbitrary")] +#[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for Block { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { // first generate up to 100 txs @@ -614,7 +614,7 @@ impl From for BlockBody { } } -#[cfg(feature = "arbitrary")] +#[cfg(any(test, feature = "arbitrary"))] impl<'a> arbitrary::Arbitrary<'a> for BlockBody { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { // first generate up to 100 txs diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 59fec9702991..128f0a1041a2 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -14,8 +14,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] @@ -113,17 +111,17 @@ pub use arbitrary; #[cfg(feature = "c-kzg")] pub use c_kzg as kzg; +#[cfg(feature = "taiko")] +mod taiko; + +#[cfg(feature = "taiko")] +pub use taiko::*; + /// Optimism specific re-exports #[cfg(feature = "optimism")] mod optimism { pub use crate::transaction::{TxDeposit, DEPOSIT_TX_TYPE_ID}; - pub use reth_chainspec::{ - net::{ - base_nodes, base_testnet_nodes, op_nodes, op_testnet_nodes, OP_BOOTNODES, - OP_TESTNET_BOOTNODES, - }, - BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA, - }; + pub use reth_chainspec::{BASE_MAINNET, BASE_SEPOLIA, OP_MAINNET, OP_SEPOLIA}; } #[cfg(feature = "optimism")] diff --git a/crates/primitives/src/proofs.rs b/crates/primitives/src/proofs.rs index 5521fedecf97..9e0a0357905f 100644 --- a/crates/primitives/src/proofs.rs +++ b/crates/primitives/src/proofs.rs @@ -4,9 +4,8 @@ use crate::{ constants::EMPTY_OMMER_ROOT_HASH, keccak256, Header, Receipt, ReceiptWithBloom, ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, }; -use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; - use alloy_eips::eip7685::Encodable7685; +use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; #[cfg(not(feature = "std"))] use alloc::vec::Vec; @@ -50,8 +49,9 @@ pub fn calculate_receipt_root_optimism( // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the // receipts before calculating the receipt root. This was corrected in the Canyon // hardfork. - if chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Canyon, timestamp) + if chain_spec.is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Regolith, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Canyon, timestamp) { let receipts = receipts .iter() @@ -98,8 +98,9 @@ pub fn calculate_receipt_root_no_memo_optimism( // encoding. In the Regolith Hardfork, we must strip the deposit nonce from the // receipts before calculating the receipt root. This was corrected in the Canyon // hardfork. - if chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Regolith, timestamp) && - !chain_spec.is_fork_active_at_timestamp(reth_chainspec::Hardfork::Canyon, timestamp) + if chain_spec.is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Regolith, timestamp) && + !chain_spec + .is_fork_active_at_timestamp(reth_chainspec::OptimismHardfork::Canyon, timestamp) { let receipts = receipts .iter() diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index 1a9d917d62f7..fb2d8a98338c 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -31,17 +31,17 @@ pub struct Receipt { pub cumulative_gas_used: u64, /// Log send from contracts. pub logs: Vec, - /// Deposit nonce for Optimism deposit transactions - #[cfg(feature = "optimism")] - pub deposit_nonce: Option, - /// Deposit receipt version for Optimism deposit transactions - /// - /// - /// The deposit receipt version was introduced in Canyon to indicate an update to how - /// receipt hashes should be computed when set. The state transition process - /// ensures this is only set for post-Canyon deposit transactions. - #[cfg(feature = "optimism")] - pub deposit_receipt_version: Option, + // /// Deposit nonce for Optimism deposit transactions + // #[cfg(feature = "optimism")] + // pub deposit_nonce: Option, + // /// Deposit receipt version for Optimism deposit transactions + // /// + // /// + // /// The deposit receipt version was introduced in Canyon to indicate an update to how + // /// receipt hashes should be computed when set. The state transition process + // /// ensures this is only set for post-Canyon deposit transactions. + // #[cfg(feature = "optimism")] + // pub deposit_receipt_version: Option, } impl Receipt { diff --git a/crates/primitives/src/revm/config.rs b/crates/primitives/src/revm/config.rs deleted file mode 100644 index 5914dbf59348..000000000000 --- a/crates/primitives/src/revm/config.rs +++ /dev/null @@ -1,303 +0,0 @@ -use reth_chainspec::ChainSpec; -use reth_ethereum_forks::{Hardfork, Head}; - -/// Returns the spec id at the given timestamp. -/// -/// Note: This is only intended to be used after the merge, when hardforks are activated by -/// timestamp. -pub fn revm_spec_by_timestamp_after_merge( - chain_spec: &ChainSpec, - timestamp: u64, -) -> revm_primitives::SpecId { - #[cfg(feature = "optimism")] - if chain_spec.is_optimism() { - return if chain_spec.fork(Hardfork::Fjord).active_at_timestamp(timestamp) { - revm_primitives::FJORD - } else if chain_spec.fork(Hardfork::Ecotone).active_at_timestamp(timestamp) { - revm_primitives::ECOTONE - } else if chain_spec.fork(Hardfork::Canyon).active_at_timestamp(timestamp) { - revm_primitives::CANYON - } else if chain_spec.fork(Hardfork::Regolith).active_at_timestamp(timestamp) { - revm_primitives::REGOLITH - } else { - revm_primitives::BEDROCK - } - } - - if chain_spec.is_prague_active_at_timestamp(timestamp) { - revm_primitives::PRAGUE - } else if chain_spec.is_cancun_active_at_timestamp(timestamp) { - revm_primitives::CANCUN - } else if chain_spec.is_shanghai_active_at_timestamp(timestamp) { - revm_primitives::SHANGHAI - } else { - revm_primitives::MERGE - } -} - -/// return `revm_spec` from spec configuration. -pub fn revm_spec(chain_spec: &ChainSpec, block: Head) -> revm_primitives::SpecId { - #[cfg(feature = "optimism")] - if chain_spec.is_optimism() { - if chain_spec.fork(Hardfork::Fjord).active_at_head(&block) { - return revm_primitives::FJORD - } else if chain_spec.fork(Hardfork::Ecotone).active_at_head(&block) { - return revm_primitives::ECOTONE - } else if chain_spec.fork(Hardfork::Canyon).active_at_head(&block) { - return revm_primitives::CANYON - } else if chain_spec.fork(Hardfork::Regolith).active_at_head(&block) { - return revm_primitives::REGOLITH - } else if chain_spec.fork(Hardfork::Bedrock).active_at_head(&block) { - return revm_primitives::BEDROCK - } - } - - if chain_spec.fork(Hardfork::Prague).active_at_head(&block) { - revm_primitives::PRAGUE - } else if chain_spec.fork(Hardfork::Cancun).active_at_head(&block) { - revm_primitives::CANCUN - } else if chain_spec.fork(Hardfork::Shanghai).active_at_head(&block) { - revm_primitives::SHANGHAI - } else if chain_spec.fork(Hardfork::Paris).active_at_head(&block) { - revm_primitives::MERGE - } else if chain_spec.fork(Hardfork::London).active_at_head(&block) { - revm_primitives::LONDON - } else if chain_spec.fork(Hardfork::Berlin).active_at_head(&block) { - revm_primitives::BERLIN - } else if chain_spec.fork(Hardfork::Istanbul).active_at_head(&block) { - revm_primitives::ISTANBUL - } else if chain_spec.fork(Hardfork::Petersburg).active_at_head(&block) { - revm_primitives::PETERSBURG - } else if chain_spec.fork(Hardfork::Byzantium).active_at_head(&block) { - revm_primitives::BYZANTIUM - } else if chain_spec.fork(Hardfork::SpuriousDragon).active_at_head(&block) { - revm_primitives::SPURIOUS_DRAGON - } else if chain_spec.fork(Hardfork::Tangerine).active_at_head(&block) { - revm_primitives::TANGERINE - } else if chain_spec.fork(Hardfork::Homestead).active_at_head(&block) { - revm_primitives::HOMESTEAD - } else if chain_spec.fork(Hardfork::Frontier).active_at_head(&block) { - revm_primitives::FRONTIER - } else { - panic!( - "invalid hardfork chainspec: expected at least one hardfork, got {:?}", - chain_spec.hardforks - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::U256; - use reth_chainspec::{ChainSpecBuilder, MAINNET}; - - #[test] - fn test_revm_spec_by_timestamp_after_merge() { - assert_eq!( - revm_spec_by_timestamp_after_merge( - &ChainSpecBuilder::mainnet().cancun_activated().build(), - 0 - ), - revm_primitives::CANCUN - ); - assert_eq!( - revm_spec_by_timestamp_after_merge( - &ChainSpecBuilder::mainnet().shanghai_activated().build(), - 0 - ), - revm_primitives::SHANGHAI - ); - assert_eq!( - revm_spec_by_timestamp_after_merge(&ChainSpecBuilder::mainnet().build(), 0), - revm_primitives::MERGE - ); - #[cfg(feature = "optimism")] - { - #[inline(always)] - fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec { - let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)); - f(cs).build() - } - assert_eq!( - revm_spec_by_timestamp_after_merge(&op_cs(|cs| cs.fjord_activated()), 0), - revm_primitives::FJORD - ); - assert_eq!( - revm_spec_by_timestamp_after_merge(&op_cs(|cs| cs.ecotone_activated()), 0), - revm_primitives::ECOTONE - ); - assert_eq!( - revm_spec_by_timestamp_after_merge(&op_cs(|cs| cs.canyon_activated()), 0), - revm_primitives::CANYON - ); - assert_eq!( - revm_spec_by_timestamp_after_merge(&op_cs(|cs| cs.bedrock_activated()), 0), - revm_primitives::BEDROCK - ); - assert_eq!( - revm_spec_by_timestamp_after_merge(&op_cs(|cs| cs.regolith_activated()), 0), - revm_primitives::REGOLITH - ); - } - } - - #[test] - fn test_to_revm_spec() { - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().cancun_activated().build(), Head::default()), - revm_primitives::CANCUN - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().shanghai_activated().build(), Head::default()), - revm_primitives::SHANGHAI - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), Head::default()), - revm_primitives::MERGE - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), Head::default()), - revm_primitives::LONDON - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), Head::default()), - revm_primitives::BERLIN - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), Head::default()), - revm_primitives::ISTANBUL - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().petersburg_activated().build(), Head::default()), - revm_primitives::PETERSBURG - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), Head::default()), - revm_primitives::BYZANTIUM - ); - assert_eq!( - revm_spec( - &ChainSpecBuilder::mainnet().spurious_dragon_activated().build(), - Head::default() - ), - revm_primitives::SPURIOUS_DRAGON - ); - assert_eq!( - revm_spec( - &ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(), - Head::default() - ), - revm_primitives::TANGERINE - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), Head::default()), - revm_primitives::HOMESTEAD - ); - assert_eq!( - revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), Head::default()), - revm_primitives::FRONTIER - ); - #[cfg(feature = "optimism")] - { - #[inline(always)] - fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec { - let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)); - f(cs).build() - } - assert_eq!( - revm_spec(&op_cs(|cs| cs.fjord_activated()), Head::default()), - revm_primitives::FJORD - ); - assert_eq!( - revm_spec(&op_cs(|cs| cs.ecotone_activated()), Head::default()), - revm_primitives::ECOTONE - ); - assert_eq!( - revm_spec(&op_cs(|cs| cs.canyon_activated()), Head::default()), - revm_primitives::CANYON - ); - assert_eq!( - revm_spec(&op_cs(|cs| cs.bedrock_activated()), Head::default()), - revm_primitives::BEDROCK - ); - assert_eq!( - revm_spec(&op_cs(|cs| cs.regolith_activated()), Head::default()), - revm_primitives::REGOLITH - ); - } - } - - #[test] - fn test_eth_spec() { - assert_eq!( - revm_spec(&MAINNET, Head { timestamp: 1710338135, ..Default::default() }), - revm_primitives::CANCUN - ); - assert_eq!( - revm_spec(&MAINNET, Head { timestamp: 1681338455, ..Default::default() }), - revm_primitives::SHANGHAI - ); - - assert_eq!( - revm_spec( - &MAINNET, - Head { - total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128), - difficulty: U256::from(10_u128), - ..Default::default() - } - ), - revm_primitives::MERGE - ); - // TTD trumps the block number - assert_eq!( - revm_spec( - &MAINNET, - Head { - number: 15537394 - 10, - total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128), - difficulty: U256::from(10_u128), - ..Default::default() - } - ), - revm_primitives::MERGE - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 15537394 - 10, ..Default::default() }), - revm_primitives::LONDON - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 12244000 + 10, ..Default::default() }), - revm_primitives::BERLIN - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 12244000 - 10, ..Default::default() }), - revm_primitives::ISTANBUL - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 7280000 + 10, ..Default::default() }), - revm_primitives::PETERSBURG - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 7280000 - 10, ..Default::default() }), - revm_primitives::BYZANTIUM - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 2675000 + 10, ..Default::default() }), - revm_primitives::SPURIOUS_DRAGON - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 2675000 - 10, ..Default::default() }), - revm_primitives::TANGERINE - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 1150000 + 10, ..Default::default() }), - revm_primitives::HOMESTEAD - ); - assert_eq!( - revm_spec(&MAINNET, Head { number: 1150000 - 10, ..Default::default() }), - revm_primitives::FRONTIER - ); - } -} diff --git a/crates/primitives/src/revm/env.rs b/crates/primitives/src/revm/env.rs index bbd4cffd35fb..ada7894513ed 100644 --- a/crates/primitives/src/revm/env.rs +++ b/crates/primitives/src/revm/env.rs @@ -245,10 +245,7 @@ where tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.gas_price); tx_env.gas_priority_fee = None; - tx_env.transact_to = match tx.to { - TxKind::Call(to) => TxKind::Call(to), - TxKind::Create => TxKind::Create, - }; + tx_env.transact_to = tx.to; tx_env.value = tx.value; tx_env.data = tx.input.clone(); tx_env.chain_id = tx.chain_id; @@ -261,17 +258,13 @@ where tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.gas_price); tx_env.gas_priority_fee = None; - tx_env.transact_to = match tx.to { - TxKind::Call(to) => TxKind::Call(to), - TxKind::Create => TxKind::Create, - }; + tx_env.transact_to = tx.to; tx_env.value = tx.value; tx_env.data = tx.input.clone(); tx_env.chain_id = Some(tx.chain_id); tx_env.nonce = Some(tx.nonce); tx_env.access_list = tx .access_list - .0 .iter() .map(|l| { (l.address, l.storage_keys.iter().map(|k| U256::from_be_bytes(k.0)).collect()) @@ -284,17 +277,13 @@ where tx_env.gas_limit = tx.gas_limit; tx_env.gas_price = U256::from(tx.max_fee_per_gas); tx_env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); - tx_env.transact_to = match tx.to { - TxKind::Call(to) => TxKind::Call(to), - TxKind::Create => TxKind::Create, - }; + tx_env.transact_to = tx.to; tx_env.value = tx.value; tx_env.data = tx.input.clone(); tx_env.chain_id = Some(tx.chain_id); tx_env.nonce = Some(tx.nonce); tx_env.access_list = tx .access_list - .0 .iter() .map(|l| { (l.address, l.storage_keys.iter().map(|k| U256::from_be_bytes(k.0)).collect()) @@ -314,7 +303,6 @@ where tx_env.nonce = Some(tx.nonce); tx_env.access_list = tx .access_list - .0 .iter() .map(|l| { (l.address, l.storage_keys.iter().map(|k| U256::from_be_bytes(k.0)).collect()) diff --git a/crates/primitives/src/revm/mod.rs b/crates/primitives/src/revm/mod.rs index 9937a209b93e..40fc719c950b 100644 --- a/crates/primitives/src/revm/mod.rs +++ b/crates/primitives/src/revm/mod.rs @@ -1,8 +1,5 @@ //! Helpers for working with revm. -/// Reth block execution/validation configuration and constants -pub mod config; - /// The `env` module provides utility methods for filling revm transaction and block environments. /// /// It includes functions to fill transaction and block environments with relevant data, prepare diff --git a/crates/primitives/src/taiko.rs b/crates/primitives/src/taiko.rs new file mode 100644 index 000000000000..e39441337d4a --- /dev/null +++ b/crates/primitives/src/taiko.rs @@ -0,0 +1,44 @@ +#![allow(missing_docs)] + +use revm_primitives::{Address, Bytes, B256}; +use serde::{Deserialize, Serialize}; + +pub const L1_ORIGIN_PREFIX: &str = "TKO:L1O"; +pub const HEAD_L1_ORIGIN_KEY: &str = "TKO:LastL1O"; + +/// BlockMetadata represents a `BlockMetadata` struct defined in protocol. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct TaikoBlockMetadata { + pub beneficiary: Address, + pub gas_limit: u64, + pub timestamp: u64, + pub mix_hash: B256, + #[serde(skip_serializing_if = "Option::is_none")] + pub tx_list: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub highest_block_id: Option, + pub extra_data: Vec, +} + +/// L1Origin represents a L1Origin of a L2 block. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct L1Origin { + pub block_id: u64, + pub l2_block_hash: B256, + pub l1_block_height: u64, + pub l1_block_hash: B256, +} + +impl L1Origin { + /// l1OriginKey calculates the L1Origin key. + /// l1OriginPrefix + l2HeaderHash -> l1OriginKey + pub fn key(block_id: u64) -> String { + format!("{L1_ORIGIN_PREFIX}{block_id}") + } + + pub fn head_key() -> String { + HEAD_L1_ORIGIN_KEY.to_string() + } +} diff --git a/crates/primitives/src/transaction/eip1559.rs b/crates/primitives/src/transaction/eip1559.rs index cce6f0ca22fc..c93c6675756f 100644 --- a/crates/primitives/src/transaction/eip1559.rs +++ b/crates/primitives/src/transaction/eip1559.rs @@ -52,6 +52,9 @@ pub struct TxEip1559 { /// A gas cost is charged, though at a discount relative to the cost of /// accessing outside the list. pub access_list: AccessList, + /// CHANGE(taiko): Add is_anchor field + #[cfg(feature = "taiko")] + pub is_anchor: bool, /// Input has two uses depending if transaction is Create or Call (if `to` field is None or /// Some). pub init: An unlimited size byte array specifying the /// EVM-code for the account initialisation procedure CREATE, @@ -104,20 +107,27 @@ impl TxEip1559 { value: Decodable::decode(buf)?, input: Decodable::decode(buf)?, access_list: Decodable::decode(buf)?, + #[cfg(feature = "taiko")] + is_anchor: Decodable::decode(buf)?, }) } /// Encodes only the transaction's fields into the desired buffer, without a RLP header. pub(crate) fn fields_len(&self) -> usize { - self.chain_id.length() + - self.nonce.length() + - self.max_priority_fee_per_gas.length() + - self.max_fee_per_gas.length() + - self.gas_limit.length() + - self.to.length() + - self.value.length() + - self.input.0.length() + - self.access_list.length() + let anchor_len = 0; + #[cfg(feature = "taiko")] + let anchor_len = self.is_anchor.length(); + + self.chain_id.length() + + self.nonce.length() + + self.max_priority_fee_per_gas.length() + + self.max_fee_per_gas.length() + + self.gas_limit.length() + + self.to.length() + + self.value.length() + + self.input.0.length() + + self.access_list.length() + + anchor_len } /// Encodes only the transaction's fields into the desired buffer, without a RLP header. @@ -131,6 +141,8 @@ impl TxEip1559 { self.value.encode(out); self.input.0.encode(out); self.access_list.encode(out); + #[cfg(feature = "taiko")] + self.is_anchor.encode(out); } /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating @@ -248,6 +260,8 @@ mod tests { max_fee_per_gas: 0x4a817c800, max_priority_fee_per_gas: 0x3b9aca00, access_list: AccessList::default(), + #[cfg(feature = "taiko")] + is_anchor: false, }); let sig = Signature { diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index c23d454f868d..7cef75a6a6c3 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -75,18 +75,6 @@ pub(crate) static PARALLEL_SENDER_RECOVERY_THRESHOLD: Lazy = _ => 5, }); -/// Minimum length of a rlp-encoded legacy transaction. -pub const MIN_LENGTH_LEGACY_TX_ENCODED: usize = 10; -/// Minimum length of a rlp-encoded eip2930 transaction. -pub const MIN_LENGTH_EIP2930_TX_ENCODED: usize = 14; -/// Minimum length of a rlp-encoded eip1559 transaction. -pub const MIN_LENGTH_EIP1559_TX_ENCODED: usize = 15; -/// Minimum length of a rlp-encoded eip4844 transaction. -pub const MIN_LENGTH_EIP4844_TX_ENCODED: usize = 37; -/// Minimum length of a rlp-encoded deposit transaction. -#[cfg(feature = "optimism")] -pub const MIN_LENGTH_DEPOSIT_TX_ENCODED: usize = 65; - /// A raw transaction. /// /// Transaction types were introduced in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718). @@ -388,7 +376,7 @@ impl Transaction { // Check if max_fee_per_gas is less than base_fee if max_fee_per_gas < base_fee { - return None + return None; } // Calculate the difference between max_fee_per_gas and base_fee @@ -450,6 +438,29 @@ impl Transaction { matches!(self, Self::Deposit(_)) } + /// Returns whether the transaction is an anchor transaction. + #[cfg(feature = "taiko")] + pub fn is_anchor(&self) -> bool { + match self { + Self::Eip1559(tx) => tx.is_anchor, + Self::Legacy(_) | Self::Eip2930(_) | Self::Eip4844(_) => false, + #[cfg(feature = "optimism")] + Self::Deposit(_) => false, + } + } + + /// Marks the transaction as an anchor transaction. + #[cfg(feature = "taiko")] + pub fn mark_as_anchor(&mut self) -> Result<(), InvalidTransactionError> { + match self { + Self::Eip1559(tx) => { + tx.is_anchor = true; + Ok(()) + } + _ => Err(InvalidTransactionError::TxTypeNotSupported), + } + } + /// This encodes the transaction _without_ the signature, and is only suitable for creating a /// hash intended for signing. pub fn encode_without_signature(&self, out: &mut dyn bytes::BufMut) { @@ -773,7 +784,7 @@ impl TransactionSignedNoHash { // `from` address. #[cfg(feature = "optimism")] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { - return Some(from) + return Some(from); } let signature_hash = self.signature_hash(); @@ -802,7 +813,7 @@ impl TransactionSignedNoHash { #[cfg(feature = "optimism")] { if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { - return Some(from) + return Some(from); } // pre bedrock system transactions were sent from the zero address as legacy @@ -810,7 +821,7 @@ impl TransactionSignedNoHash { // // NOTE: this is very hacky and only relevant for op-mainnet pre bedrock if self.is_legacy() && self.signature == Signature::optimism_deposit_tx_signature() { - return Some(Address::ZERO) + return Some(Address::ZERO); } } @@ -1027,7 +1038,7 @@ impl TransactionSigned { // `from` address. #[cfg(feature = "optimism")] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { - return Some(from) + return Some(from); } let signature_hash = self.signature_hash(); self.signature.recover_signer(signature_hash) @@ -1043,7 +1054,7 @@ impl TransactionSigned { // `from` address. #[cfg(feature = "optimism")] if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { - return Some(from) + return Some(from); } let signature_hash = self.signature_hash(); self.signature.recover_signer_unchecked(signature_hash) @@ -1217,7 +1228,7 @@ impl TransactionSigned { let transaction_payload_len = header.payload_length; if transaction_payload_len > remaining_len { - return Err(RlpError::InputTooShort) + return Err(RlpError::InputTooShort); } let mut transaction = TxLegacy { @@ -1235,7 +1246,7 @@ impl TransactionSigned { // check the new length, compared to the original length and the header length let decoded = remaining_len - data.len(); if decoded != transaction_payload_len { - return Err(RlpError::UnexpectedLength) + return Err(RlpError::UnexpectedLength); } let tx_length = header.payload_length + header.length(); @@ -1280,7 +1291,7 @@ impl TransactionSigned { // decode the list header for the rest of the transaction let header = Header::decode(data)?; if !header.list { - return Err(RlpError::Custom("typed tx fields must be encoded as a list")) + return Err(RlpError::Custom("typed tx fields must be encoded as a list")); } let remaining_len = data.len(); @@ -1290,7 +1301,7 @@ impl TransactionSigned { // decode common fields let Ok(tx_type) = TxType::try_from(tx_type) else { - return Err(RlpError::Custom("unsupported typed transaction type")) + return Err(RlpError::Custom("unsupported typed transaction type")); }; let transaction = match tx_type { @@ -1314,7 +1325,7 @@ impl TransactionSigned { let bytes_consumed = remaining_len - data.len(); if bytes_consumed != header.payload_length { - return Err(RlpError::UnexpectedLength) + return Err(RlpError::UnexpectedLength); } let hash = keccak256(&original_encoding_without_header[..tx_length]); @@ -1449,7 +1460,7 @@ impl Decodable for TransactionSigned { // string Header with payload_length of 1, we need to make sure this check is only // performed for transactions with a string header if bytes_consumed != header.payload_length && original_encoding[0] > EMPTY_STRING_CODE { - return Err(RlpError::UnexpectedLength) + return Err(RlpError::UnexpectedLength); } Ok(tx) @@ -1478,6 +1489,16 @@ impl<'a> arbitrary::Arbitrary<'a> for TransactionSigned { if tx_eip_4844.to != Address::default() { Some(()) } else { None }; } + #[cfg(feature = "optimism")] + // Both `Some(0)` and `None` values are encoded as empty string byte. This introduces + // ambiguity in roundtrip tests. Patch the mint value of deposit transaction here, so that + // it's `None` if zero. + if let Transaction::Deposit(ref mut tx_deposit) = transaction { + if tx_deposit.mint == Some(0) { + tx_deposit.mint = None; + } + } + let signature = Signature::arbitrary(u)?; #[cfg(feature = "optimism")] @@ -1617,12 +1638,10 @@ mod tests { hex, sign_message, transaction::{ from_compact_zstd_unaware, signature::Signature, to_compact_ztd_unaware, TxEip1559, - TxKind, TxLegacy, MIN_LENGTH_EIP1559_TX_ENCODED, MIN_LENGTH_EIP2930_TX_ENCODED, - MIN_LENGTH_EIP4844_TX_ENCODED, MIN_LENGTH_LEGACY_TX_ENCODED, - PARALLEL_SENDER_RECOVERY_THRESHOLD, + TxKind, TxLegacy, PARALLEL_SENDER_RECOVERY_THRESHOLD, }, Address, Bytes, Transaction, TransactionSigned, TransactionSignedEcRecovered, - TransactionSignedNoHash, TxEip2930, TxEip4844, B256, U256, + TransactionSignedNoHash, B256, U256, }; use alloy_primitives::{address, b256, bytes}; use alloy_rlp::{Decodable, Encodable, Error as RlpError}; @@ -1787,6 +1806,8 @@ mod tests { value: U256::from(3000000000000000000u64), input: Default::default(), access_list: Default::default(), + #[cfg(feature = "taiko")] + is_anchor: false, }); let signature = Signature { odd_y_parity: true, @@ -1963,106 +1984,6 @@ mod tests { assert_eq!(sender, address!("7e9e359edf0dbacf96a9952fa63092d919b0842b")); } - #[test] - fn min_length_encoded_legacy_transaction() { - let transaction = TxLegacy::default(); - let signature = Signature::default(); - - let signed_tx = TransactionSigned::from_transaction_and_signature( - Transaction::Legacy(transaction), - signature, - ); - - let encoded = &alloy_rlp::encode(signed_tx); - assert_eq!( - if cfg!(feature = "optimism") { - hex!("c9808080808080808080") - } else { - hex!("c98080808080801b8080") - }, - &encoded[..] - ); - assert_eq!(MIN_LENGTH_LEGACY_TX_ENCODED, encoded.len()); - - TransactionSigned::decode(&mut &encoded[..]).unwrap(); - } - - #[test] - fn min_length_encoded_eip2930_transaction() { - let transaction = TxEip2930::default(); - let signature = Signature::default(); - - let signed_tx = TransactionSigned::from_transaction_and_signature( - Transaction::Eip2930(transaction), - signature, - ); - - let encoded = &alloy_rlp::encode(signed_tx); - assert_eq!(hex!("8d01cb80808080808080c0808080"), encoded[..]); - assert_eq!(MIN_LENGTH_EIP2930_TX_ENCODED, encoded.len()); - - TransactionSigned::decode(&mut &encoded[..]).unwrap(); - } - - #[test] - fn min_length_encoded_eip1559_transaction() { - let transaction = TxEip1559::default(); - let signature = Signature::default(); - - let signed_tx = TransactionSigned::from_transaction_and_signature( - Transaction::Eip1559(transaction), - signature, - ); - - let encoded = &alloy_rlp::encode(signed_tx); - assert_eq!(hex!("8e02cc8080808080808080c0808080"), encoded[..]); - assert_eq!(MIN_LENGTH_EIP1559_TX_ENCODED, encoded.len()); - - TransactionSigned::decode(&mut &encoded[..]).unwrap(); - } - - #[test] - fn min_length_encoded_eip4844_transaction() { - let transaction = TxEip4844::default(); - let signature = Signature::default(); - - let signed_tx = TransactionSigned::from_transaction_and_signature( - Transaction::Eip4844(transaction), - signature, - ); - - let encoded = alloy_rlp::encode(signed_tx); - assert_eq!( - hex!("a403e280808080809400000000000000000000000000000000000000008080c080c0808080"), - encoded[..] - ); - assert_eq!(MIN_LENGTH_EIP4844_TX_ENCODED, encoded.len()); - - TransactionSigned::decode(&mut &encoded[..]).unwrap(); - } - - #[cfg(feature = "optimism")] - #[test] - fn min_length_encoded_deposit_transaction() { - use super::MIN_LENGTH_DEPOSIT_TX_ENCODED; - use crate::TxDeposit; - - let transaction = TxDeposit::default(); - let signature = Signature::default(); - - let signed_tx = TransactionSigned::from_transaction_and_signature( - Transaction::Deposit(transaction), - signature, - ); - - let encoded = &alloy_rlp::encode(signed_tx); - - assert_eq!(b"\xb8?~\xf8<\xa0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x94\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x80\x80\x80\x80\x80", &encoded[..]); - assert_eq!(MIN_LENGTH_DEPOSIT_TX_ENCODED, encoded.len()); - - TransactionSigned::decode(&mut &encoded[..]).unwrap(); - } - #[test] fn transaction_signed_no_hash_zstd_codec() { // will use same signature everywhere. diff --git a/crates/prune/types/src/lib.rs b/crates/prune/types/src/lib.rs index 34d74614f2c1..82563010f165 100644 --- a/crates/prune/types/src/lib.rs +++ b/crates/prune/types/src/lib.rs @@ -6,8 +6,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] mod checkpoint; diff --git a/crates/revm/src/database.rs b/crates/revm/src/database.rs index 3b31788dbdaf..a1296ae39c24 100644 --- a/crates/revm/src/database.rs +++ b/crates/revm/src/database.rs @@ -1,6 +1,6 @@ use crate::primitives::alloy_primitives::{BlockNumber, StorageKey, StorageValue}; use core::ops::{Deref, DerefMut}; -use reth_primitives::{Account, Address, B256, KECCAK_EMPTY, U256}; +use reth_primitives::{Account, Address, B256, U256}; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use revm::{ db::DatabaseRef, @@ -134,12 +134,7 @@ impl DatabaseRef for StateProviderDatabase { /// Returns `Ok` with `Some(AccountInfo)` if the account exists, /// `None` if it doesn't, or an error if encountered. fn basic_ref(&self, address: Address) -> Result, Self::Error> { - Ok(self.basic_account(address)?.map(|account| AccountInfo { - balance: account.balance, - nonce: account.nonce, - code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY), - code: None, - })) + Ok(self.basic_account(address)?.map(Into::into)) } /// Retrieves the bytecode associated with a given code hash. @@ -160,13 +155,10 @@ impl DatabaseRef for StateProviderDatabase { /// /// Returns `Ok` with the block hash if found, or the default hash otherwise. fn block_hash_ref(&self, number: U256) -> Result { - // Attempt to convert U256 to u64 - let block_number = match number.try_into() { - Ok(value) => value, - Err(_) => return Err(Self::Error::BlockNumberOverflow(number)), - }; - - // Get the block hash or default hash - Ok(self.0.block_hash(block_number)?.unwrap_or_default()) + // Get the block hash or default hash with an attempt to convert U256 block number to u64 + Ok(self + .0 + .block_hash(number.try_into().map_err(|_| Self::Error::BlockNumberOverflow(number))?)? + .unwrap_or_default()) } } diff --git a/crates/revm/src/state_change.rs b/crates/revm/src/state_change.rs index b9fba6b2578e..5fad6ae42563 100644 --- a/crates/revm/src/state_change.rs +++ b/crates/revm/src/state_change.rs @@ -3,7 +3,7 @@ use alloy_eips::{ eip7002::WithdrawalRequest, }; use alloy_rlp::Buf; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_consensus_common::calc; use reth_execution_errors::{BlockExecutionError, BlockValidationError}; use reth_primitives::{ @@ -11,7 +11,7 @@ use reth_primitives::{ fill_tx_env_with_beacon_root_contract_call, fill_tx_env_with_withdrawal_requests_contract_call, }, - Address, Header, Request, Withdrawal, B256, U256, + Address, Block, Request, Withdrawal, Withdrawals, B256, U256, }; use reth_storage_errors::provider::ProviderError; use revm::{ @@ -36,40 +36,34 @@ use std::collections::HashMap; /// /// Balance changes might include the block reward, uncle rewards, withdrawals, or irregular /// state changes (DAO fork). -#[allow(clippy::too_many_arguments)] #[inline] pub fn post_block_balance_increments( chain_spec: &ChainSpec, - block_number: u64, - block_difficulty: U256, - beneficiary: Address, - block_timestamp: u64, + block: &Block, total_difficulty: U256, - ommers: &[Header], - withdrawals: Option<&[Withdrawal]>, ) -> HashMap { let mut balance_increments = HashMap::new(); // Add block rewards if they are enabled. if let Some(base_block_reward) = - calc::base_block_reward(chain_spec, block_number, block_difficulty, total_difficulty) + calc::base_block_reward(chain_spec, block.number, block.difficulty, total_difficulty) { // Ommer rewards - for ommer in ommers { + for ommer in &block.ommers { *balance_increments.entry(ommer.beneficiary).or_default() += - calc::ommer_reward(base_block_reward, block_number, ommer.number); + calc::ommer_reward(base_block_reward, block.number, ommer.number); } // Full block reward - *balance_increments.entry(beneficiary).or_default() += - calc::block_reward(base_block_reward, ommers.len()); + *balance_increments.entry(block.beneficiary).or_default() += + calc::block_reward(base_block_reward, block.ommers.len()); } // process withdrawals insert_post_block_withdrawals_balance_increments( chain_spec, - block_timestamp, - withdrawals, + block.timestamp, + block.withdrawals.as_ref().map(Withdrawals::as_ref), &mut balance_increments, ); @@ -86,7 +80,7 @@ pub fn post_block_balance_increments( /// /// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 #[inline] -pub fn apply_blockhashes_update + DatabaseCommit>( +pub fn apply_blockhashes_update> + DatabaseCommit>( db: &mut DB, chain_spec: &ChainSpec, block_timestamp: u64, @@ -108,7 +102,7 @@ where // nonce of 1, so it does not get deleted. let mut account: Account = db .basic(HISTORY_STORAGE_ADDRESS) - .map_err(BlockValidationError::BlockHashAccountLoadingFailed)? + .map_err(|err| BlockValidationError::BlockHashAccountLoadingFailed(err.into()))? .unwrap_or_else(|| AccountInfo { nonce: 1, code: Some(Bytecode::new_raw(HISTORY_STORAGE_CODE.clone())), @@ -132,7 +126,7 @@ where /// /// This calculates the correct storage slot in the `BLOCKHASH` history storage address, fetches the /// blockhash and creates a [`EvmStorageSlot`] with appropriate previous and new values. -fn eip2935_block_hash_slot>( +fn eip2935_block_hash_slot>>( db: &mut DB, block_number: u64, block_hash: B256, @@ -140,7 +134,7 @@ fn eip2935_block_hash_slot>( let slot = U256::from(block_number % BLOCKHASH_SERVE_WINDOW as u64); let current_hash = db .storage(HISTORY_STORAGE_ADDRESS, slot) - .map_err(BlockValidationError::BlockHashAccountLoadingFailed)?; + .map_err(|err| BlockValidationError::BlockHashAccountLoadingFailed(err.into()))?; Ok((slot, EvmStorageSlot::new_changed(current_hash, block_hash.into()))) } diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index 5374c46e4898..1532b2ac531c 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -15,6 +15,7 @@ workspace = true # reth reth-primitives.workspace = true reth-rpc-types.workspace = true +reth-rpc-eth-api.workspace = true reth-engine-primitives.workspace = true reth-network-peers.workspace = true @@ -27,4 +28,10 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true [features] -client = ["jsonrpsee/client", "jsonrpsee/async-client"] +client = [ + "jsonrpsee/client", + "jsonrpsee/async-client", + "reth-rpc-eth-api/client" +] +optimism = ["reth-rpc-eth-api/optimism"] +taiko = ["reth-primitives/taiko"] diff --git a/crates/rpc/rpc-api/src/debug.rs b/crates/rpc/rpc-api/src/debug.rs index ccee09cc2b44..580245b1014c 100644 --- a/crates/rpc/rpc-api/src/debug.rs +++ b/crates/rpc/rpc-api/src/debug.rs @@ -26,7 +26,7 @@ pub trait DebugApi { #[method(name = "getRawTransaction")] async fn raw_transaction(&self, hash: B256) -> RpcResult>; - /// Returns an array of EIP-2718 binary-encoded transactions for the given [BlockId]. + /// Returns an array of EIP-2718 binary-encoded transactions for the given [`BlockId`]. #[method(name = "getRawTransactions")] async fn raw_transactions(&self, block_id: BlockId) -> RpcResult>; diff --git a/crates/rpc/rpc-api/src/eth.rs b/crates/rpc/rpc-api/src/eth.rs deleted file mode 100644 index eb11fde824cc..000000000000 --- a/crates/rpc/rpc-api/src/eth.rs +++ /dev/null @@ -1,311 +0,0 @@ -use alloy_dyn_abi::TypedData; -use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64}; -use reth_rpc_types::{ - serde_helpers::JsonStorageKey, state::StateOverride, AccessListWithGasUsed, - AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, - FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, Transaction, - TransactionRequest, Work, -}; - -/// Eth rpc interface: -#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))] -#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))] -pub trait EthApi { - /// Returns the protocol version encoded as a string. - #[method(name = "protocolVersion")] - async fn protocol_version(&self) -> RpcResult; - - /// Returns an object with data about the sync status or false. - #[method(name = "syncing")] - fn syncing(&self) -> RpcResult; - - /// Returns the client coinbase address. - #[method(name = "coinbase")] - async fn author(&self) -> RpcResult
; - - /// Returns a list of addresses owned by client. - #[method(name = "accounts")] - fn accounts(&self) -> RpcResult>; - - /// Returns the number of most recent block. - #[method(name = "blockNumber")] - fn block_number(&self) -> RpcResult; - - /// Returns the chain ID of the current network. - #[method(name = "chainId")] - async fn chain_id(&self) -> RpcResult>; - - /// Returns information about a block by hash. - #[method(name = "getBlockByHash")] - async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult>; - - /// Returns information about a block by number. - #[method(name = "getBlockByNumber")] - async fn block_by_number( - &self, - number: BlockNumberOrTag, - full: bool, - ) -> RpcResult>; - - /// Returns the number of transactions in a block from a block matching the given block hash. - #[method(name = "getBlockTransactionCountByHash")] - async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult>; - - /// Returns the number of transactions in a block matching the given block number. - #[method(name = "getBlockTransactionCountByNumber")] - async fn block_transaction_count_by_number( - &self, - number: BlockNumberOrTag, - ) -> RpcResult>; - - /// Returns the number of uncles in a block from a block matching the given block hash. - #[method(name = "getUncleCountByBlockHash")] - async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult>; - - /// Returns the number of uncles in a block with given block number. - #[method(name = "getUncleCountByBlockNumber")] - async fn block_uncles_count_by_number( - &self, - number: BlockNumberOrTag, - ) -> RpcResult>; - - /// Returns all transaction receipts for a given block. - #[method(name = "getBlockReceipts")] - async fn block_receipts( - &self, - block_id: BlockId, - ) -> RpcResult>>; - - /// Returns an uncle block of the given block and index. - #[method(name = "getUncleByBlockHashAndIndex")] - async fn uncle_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> RpcResult>; - - /// Returns an uncle block of the given block and index. - #[method(name = "getUncleByBlockNumberAndIndex")] - async fn uncle_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> RpcResult>; - - /// Returns the EIP-2718 encoded transaction if it exists. - /// - /// If this is a EIP-4844 transaction that is in the pool it will include the sidecar. - #[method(name = "getRawTransactionByHash")] - async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult>; - - /// Returns the information about a transaction requested by transaction hash. - #[method(name = "getTransactionByHash")] - async fn transaction_by_hash(&self, hash: B256) -> RpcResult>; - - /// Returns information about a raw transaction by block hash and transaction index position. - #[method(name = "getRawTransactionByBlockHashAndIndex")] - async fn raw_transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> RpcResult>; - - /// Returns information about a transaction by block hash and transaction index position. - #[method(name = "getTransactionByBlockHashAndIndex")] - async fn transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> RpcResult>; - - /// Returns information about a raw transaction by block number and transaction index - /// position. - #[method(name = "getRawTransactionByBlockNumberAndIndex")] - async fn raw_transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> RpcResult>; - - /// Returns information about a transaction by block number and transaction index position. - #[method(name = "getTransactionByBlockNumberAndIndex")] - async fn transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> RpcResult>; - - /// Returns the receipt of a transaction by transaction hash. - #[method(name = "getTransactionReceipt")] - async fn transaction_receipt(&self, hash: B256) -> RpcResult>; - - /// Returns the balance of the account of given address. - #[method(name = "getBalance")] - async fn balance(&self, address: Address, block_number: Option) -> RpcResult; - - /// Returns the value from a storage position at a given address - #[method(name = "getStorageAt")] - async fn storage_at( - &self, - address: Address, - index: JsonStorageKey, - block_number: Option, - ) -> RpcResult; - - /// Returns the number of transactions sent from an address at given block number. - #[method(name = "getTransactionCount")] - async fn transaction_count( - &self, - address: Address, - block_number: Option, - ) -> RpcResult; - - /// Returns code at a given address at given block number. - #[method(name = "getCode")] - async fn get_code(&self, address: Address, block_number: Option) -> RpcResult; - - /// Returns the block's header at given number. - #[method(name = "getHeaderByNumber")] - async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; - - /// Returns the block's header at given hash. - #[method(name = "getHeaderByHash")] - async fn header_by_hash(&self, hash: B256) -> RpcResult>; - - /// Executes a new message call immediately without creating a transaction on the block chain. - #[method(name = "call")] - async fn call( - &self, - request: TransactionRequest, - block_number: Option, - state_overrides: Option, - block_overrides: Option>, - ) -> RpcResult; - - /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the - /// optionality of state overrides - #[method(name = "callMany")] - async fn call_many( - &self, - bundle: Bundle, - state_context: Option, - state_override: Option, - ) -> RpcResult>; - - /// Generates an access list for a transaction. - /// - /// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction. - /// - /// An access list contains all storage slots and addresses touched by the transaction, except - /// for the sender account and the chain's precompiles. - /// - /// It returns list of addresses and storage keys used by the transaction, plus the gas - /// consumed when the access list is added. That is, it gives you the list of addresses and - /// storage keys that will be used by that transaction, plus the gas consumed if the access - /// list is included. Like eth_estimateGas, this is an estimation; the list could change - /// when the transaction is actually mined. Adding an accessList to your transaction does - /// not necessary result in lower gas usage compared to a transaction without an access - /// list. - #[method(name = "createAccessList")] - async fn create_access_list( - &self, - request: TransactionRequest, - block_number: Option, - ) -> RpcResult; - - /// Generates and returns an estimate of how much gas is necessary to allow the transaction to - /// complete. - #[method(name = "estimateGas")] - async fn estimate_gas( - &self, - request: TransactionRequest, - block_number: Option, - state_override: Option, - ) -> RpcResult; - - /// Returns the current price per gas in wei. - #[method(name = "gasPrice")] - async fn gas_price(&self) -> RpcResult; - - /// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions. - #[method(name = "maxPriorityFeePerGas")] - async fn max_priority_fee_per_gas(&self) -> RpcResult; - - /// Introduced in EIP-4844, returns the current blob base fee in wei. - #[method(name = "blobBaseFee")] - async fn blob_base_fee(&self) -> RpcResult; - - /// Returns the Transaction fee history - /// - /// Introduced in EIP-1559 for getting information on the appropriate priority fee to use. - /// - /// Returns transaction base fee per gas and effective priority fee per gas for the - /// requested/supported block range. The returned Fee history for the returned block range - /// can be a subsection of the requested range if not all blocks are available. - #[method(name = "feeHistory")] - async fn fee_history( - &self, - block_count: U64, - newest_block: BlockNumberOrTag, - reward_percentiles: Option>, - ) -> RpcResult; - - /// Returns whether the client is actively mining new blocks. - #[method(name = "mining")] - async fn is_mining(&self) -> RpcResult; - - /// Returns the number of hashes per second that the node is mining with. - #[method(name = "hashrate")] - async fn hashrate(&self) -> RpcResult; - - /// Returns the hash of the current block, the seedHash, and the boundary condition to be met - /// (“target”) - #[method(name = "getWork")] - async fn get_work(&self) -> RpcResult; - - /// Used for submitting mining hashrate. - /// - /// Can be used for remote miners to submit their hash rate. - /// It accepts the miner hash rate and an identifier which must be unique between nodes. - /// Returns `true` if the block was successfully submitted, `false` otherwise. - #[method(name = "submitHashrate")] - async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult; - - /// Used for submitting a proof-of-work solution. - #[method(name = "submitWork")] - async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult; - - /// Sends transaction; will block waiting for signer to return the - /// transaction hash. - #[method(name = "sendTransaction")] - async fn send_transaction(&self, request: TransactionRequest) -> RpcResult; - - /// Sends signed transaction, returning its hash. - #[method(name = "sendRawTransaction")] - async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult; - - /// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" - /// + len(message) + message))). - #[method(name = "sign")] - async fn sign(&self, address: Address, message: Bytes) -> RpcResult; - - /// Signs a transaction that can be submitted to the network at a later time using with - /// `sendRawTransaction.` - #[method(name = "signTransaction")] - async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult; - - /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). - #[method(name = "signTypedData")] - async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult; - - /// Returns the account and storage values of the specified account including the Merkle-proof. - /// This call can be used to verify that the data you are pulling from is not tampered with. - #[method(name = "getProof")] - async fn get_proof( - &self, - address: Address, - keys: Vec, - block_number: Option, - ) -> RpcResult; -} diff --git a/crates/rpc/rpc-api/src/lib.rs b/crates/rpc/rpc-api/src/lib.rs index 82af34a86d73..54228930feab 100644 --- a/crates/rpc/rpc-api/src/lib.rs +++ b/crates/rpc/rpc-api/src/lib.rs @@ -16,12 +16,8 @@ mod admin; mod anvil; -mod bundle; mod debug; mod engine; -mod eth; -mod eth_filter; -mod eth_pubsub; mod ganache; mod hardhat; mod mev; @@ -30,6 +26,7 @@ mod optimism; mod otterscan; mod reth; mod rpc; +mod taiko; mod trace; mod txpool; mod validation; @@ -42,22 +39,23 @@ pub use servers::*; pub mod servers { pub use crate::{ admin::AdminApiServer, - bundle::{EthBundleApiServer, EthCallBundleApiServer}, debug::DebugApiServer, engine::{EngineApiServer, EngineEthApiServer}, - eth::EthApiServer, - eth_filter::EthFilterApiServer, - eth_pubsub::EthPubSubApiServer, mev::MevApiServer, net::NetApiServer, otterscan::OtterscanServer, reth::RethApiServer, rpc::RpcApiServer, + taiko::TaikoApiServer, trace::TraceApiServer, txpool::TxPoolApiServer, validation::BlockSubmissionValidationApiServer, web3::Web3ApiServer, }; + pub use reth_rpc_eth_api::{ + self as eth, EthApiServer, EthBundleApiServer, EthCallBundleApiServer, EthFilterApiServer, + EthPubSubApiServer, + }; } /// re-export of all client traits @@ -70,20 +68,21 @@ pub mod clients { pub use crate::{ admin::AdminApiClient, anvil::AnvilApiClient, - bundle::{EthBundleApiClient, EthCallBundleApiClient}, debug::DebugApiClient, engine::{EngineApiClient, EngineEthApiClient}, - eth::EthApiClient, - eth_filter::EthFilterApiClient, ganache::GanacheApiClient, hardhat::HardhatApiClient, mev::MevApiClient, net::NetApiClient, otterscan::OtterscanClient, rpc::RpcApiServer, + taiko::TaikoApiClient, trace::TraceApiClient, txpool::TxPoolApiClient, validation::BlockSubmissionValidationApiClient, web3::Web3ApiClient, }; + pub use reth_rpc_eth_api::{ + EthApiClient, EthBundleApiClient, EthCallBundleApiClient, EthFilterApiClient, + }; } diff --git a/crates/rpc/rpc-api/src/taiko.rs b/crates/rpc/rpc-api/src/taiko.rs new file mode 100644 index 000000000000..77164b78d1a1 --- /dev/null +++ b/crates/rpc/rpc-api/src/taiko.rs @@ -0,0 +1,36 @@ +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use reth_primitives::Address; +use reth_rpc_types::Transaction; + +/// Taiko rpc interface. +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "taiko"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "taiko"))] +pub trait TaikoApi { + /// HeadL1Origin returns the latest L2 block's corresponding L1 origin. + #[method(name = "headL1Origin")] + async fn head_l1_origin(&self) -> RpcResult>; + + /// L1OriginByID returns the L2 block's corresponding L1 origin. + #[method(name = "l1OriginByID")] + async fn l1_origin_by_id(&self, block_id: u64) -> RpcResult>; + + /// GetL2ParentHeaders + #[method(name = "getL2ParentHeaders")] + async fn get_l2_parent_headers(&self, block_id: u64) + -> RpcResult>; + + /// Returns the details of all transactions currently pending for inclusion in the next + /// block(s), as well as the ones that are being scheduled for future execution only. + /// + /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details + #[method(name = "content")] + async fn txpool_content( + &self, + beneficiary: Address, + base_fee: u64, + block_max_gas_limit: u64, + max_bytes_per_tx_list: u64, + locals: Vec, + max_transactions_lists: u64, + ) -> RpcResult>>; +} diff --git a/crates/rpc/rpc-builder/Cargo.toml b/crates/rpc/rpc-builder/Cargo.toml index 46105030cb63..7b7c89c0fcff 100644 --- a/crates/rpc/rpc-builder/Cargo.toml +++ b/crates/rpc/rpc-builder/Cargo.toml @@ -20,6 +20,7 @@ reth-provider.workspace = true reth-rpc.workspace = true reth-rpc-api.workspace = true reth-rpc-layer.workspace = true +reth-rpc-eth-types.workspace = true reth-rpc-server-types.workspace = true reth-tasks = { workspace = true, features = ["rayon"] } reth-transaction-pool.workspace = true @@ -46,6 +47,7 @@ tracing.workspace = true reth-chainspec.workspace = true reth-beacon-consensus.workspace = true reth-network-api.workspace = true +reth-network-peers.workspace = true reth-evm-ethereum.workspace = true reth-ethereum-engine-primitives.workspace = true reth-payload-builder = { workspace = true, features = ["test-utils"] } diff --git a/crates/rpc/rpc-builder/src/auth.rs b/crates/rpc/rpc-builder/src/auth.rs index 1e8ef8f56a18..952362e0cfda 100644 --- a/crates/rpc/rpc-builder/src/auth.rs +++ b/crates/rpc/rpc-builder/src/auth.rs @@ -1,3 +1,5 @@ +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + use crate::error::{RpcError, ServerKind}; use http::header::AUTHORIZATION; use jsonrpsee::{ @@ -7,14 +9,13 @@ use jsonrpsee::{ Methods, }; use reth_engine_primitives::EngineTypes; -use reth_rpc::EthSubscriptionIdProvider; -use reth_rpc_api::servers::*; +use reth_rpc_api::*; +use reth_rpc_eth_types::EthSubscriptionIdProvider; use reth_rpc_layer::{ secret_to_bearer_header, AuthClientLayer, AuthClientService, AuthLayer, JwtAuthValidator, JwtSecret, }; use reth_rpc_server_types::constants; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use tower::layer::util::Identity; pub use jsonrpsee::server::ServerBuilder; diff --git a/crates/rpc/rpc-builder/src/config.rs b/crates/rpc/rpc-builder/src/config.rs index 45cad81cd7f0..fbace8ec7803 100644 --- a/crates/rpc/rpc-builder/src/config.rs +++ b/crates/rpc/rpc-builder/src/config.rs @@ -4,7 +4,7 @@ use crate::{ }; use jsonrpsee::server::ServerBuilder; use reth_node_core::{args::RpcServerArgs, utils::get_or_create_jwt_secret_from_path}; -use reth_rpc::eth::{cache::EthStateCacheConfig, gas_oracle::GasPriceOracleConfig}; +use reth_rpc_eth_types::{EthStateCacheConfig, GasPriceOracleConfig}; use reth_rpc_layer::{JwtError, JwtSecret}; use reth_rpc_server_types::RpcModuleSelection; use std::{net::SocketAddr, path::PathBuf}; @@ -214,11 +214,13 @@ impl RethRpcServerConfig for RpcServerArgs { #[cfg(test)] mod tests { + use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use clap::{Args, Parser}; use reth_node_core::args::RpcServerArgs; - use reth_rpc::eth::RPC_DEFAULT_GAS_CAP; - use reth_rpc_server_types::{constants, RethRpcModule, RpcModuleSelection}; - use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use reth_rpc_server_types::{ + constants, constants::gas_oracle::RPC_DEFAULT_GAS_CAP, RethRpcModule, RpcModuleSelection, + }; use crate::config::RethRpcServerConfig; diff --git a/crates/rpc/rpc-builder/src/eth.rs b/crates/rpc/rpc-builder/src/eth.rs index 224301966b23..7d177ed4302b 100644 --- a/crates/rpc/rpc-builder/src/eth.rs +++ b/crates/rpc/rpc-builder/src/eth.rs @@ -1,27 +1,26 @@ -use crate::RpcModuleConfig; +use std::sync::Arc; + use reth_evm::ConfigureEvm; use reth_network_api::{NetworkInfo, Peers}; use reth_provider::{ AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, StateProviderFactory, }; -use reth_rpc::{ - eth::{ - cache::{cache_new_blocks_task, EthStateCache, EthStateCacheConfig}, - fee_history_cache_new_blocks_task, - gas_oracle::{GasPriceOracle, GasPriceOracleConfig}, - traits::RawTransactionForwarder, - EthFilterConfig, FeeHistoryCache, FeeHistoryCacheConfig, RPC_DEFAULT_GAS_CAP, - }, - EthApi, EthFilter, EthPubSub, +use reth_rpc::eth::{EthApi, EthFilter, EthFilterConfig, EthPubSub, RawTransactionForwarder}; +use reth_rpc_eth_types::{ + cache::cache_new_blocks_task, fee_history::fee_history_cache_new_blocks_task, EthStateCache, + EthStateCacheConfig, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, + GasPriceOracleConfig, }; use reth_rpc_server_types::constants::{ - default_max_tracing_requests, DEFAULT_MAX_BLOCKS_PER_FILTER, DEFAULT_MAX_LOGS_PER_RESPONSE, + default_max_tracing_requests, gas_oracle::RPC_DEFAULT_GAS_CAP, DEFAULT_MAX_BLOCKS_PER_FILTER, + DEFAULT_MAX_LOGS_PER_RESPONSE, }; use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; use reth_transaction_pool::TransactionPool; use serde::{Deserialize, Serialize}; -use std::sync::Arc; + +use crate::RpcModuleConfig; /// All handlers for the `eth` namespace #[derive(Debug, Clone)] @@ -276,7 +275,7 @@ impl Default for EthConfig { max_tracing_requests: default_max_tracing_requests(), max_blocks_per_filter: DEFAULT_MAX_BLOCKS_PER_FILTER, max_logs_per_response: DEFAULT_MAX_LOGS_PER_RESPONSE, - rpc_gas_cap: RPC_DEFAULT_GAS_CAP.into(), + rpc_gas_cap: RPC_DEFAULT_GAS_CAP, stale_filter_ttl: DEFAULT_STALE_FILTER_TTL, fee_history_cache: FeeHistoryCacheConfig::default(), } diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 7257b3be35ab..c9fc14249041 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -47,7 +47,7 @@ //! Pool: TransactionPool + Clone + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, -//! EvmConfig: ConfigureEvm + 'static, +//! EvmConfig: ConfigureEvm, //! { //! // configure the rpc module per transport //! let transports = TransportRpcModuleConfig::default().with_http(vec![ @@ -115,7 +115,7 @@ //! Events: CanonStateSubscriptions + Clone + 'static, //! EngineApi: EngineApiServer, //! EngineT: EngineTypes + 'static, -//! EvmConfig: ConfigureEvm + 'static, +//! EvmConfig: ConfigureEvm, //! { //! // configure the rpc module per transport //! let transports = TransportRpcModuleConfig::default().with_http(vec![ @@ -175,14 +175,15 @@ use reth_ipc::server::IpcServer; use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers}; use reth_provider::{ AccountReader, BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, - ChangeSetReader, EvmEnvProvider, StateProviderFactory, + ChangeSetReader, EvmEnvProvider, L1OriginReader, StateProviderFactory, }; use reth_rpc::{ - eth::{cache::EthStateCache, traits::RawTransactionForwarder, EthBundle}, - AdminApi, DebugApi, EngineEthApi, EthApi, EthSubscriptionIdProvider, NetApi, OtterscanApi, - RPCApi, RethApi, TraceApi, TxPoolApi, Web3Api, + eth::{EthApi, EthBundle, RawTransactionForwarder}, + AdminApi, DebugApi, EngineEthApi, NetApi, OtterscanApi, RPCApi, RethApi, TaikoApi, TraceApi, + TxPoolApi, Web3Api, }; -use reth_rpc_api::servers::*; +use reth_rpc_api::*; +use reth_rpc_eth_types::{EthStateCache, EthSubscriptionIdProvider}; use reth_rpc_layer::{AuthLayer, Claims, JwtAuthValidator, JwtSecret}; use reth_tasks::{pool::BlockingTaskGuard, TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{noop::NoopTransactionPool, TransactionPool}; @@ -243,6 +244,7 @@ where + EvmEnvProvider + ChainSpecProvider + ChangeSetReader + + L1OriginReader + Clone + Unpin + 'static, @@ -250,7 +252,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm + 'static, + EvmConfig: ConfigureEvm, { let module_config = module_config.into(); let server_config = server_config.into(); @@ -434,6 +436,7 @@ where + EvmEnvProvider + ChainSpecProvider + ChangeSetReader + + L1OriginReader + Clone + Unpin + 'static, @@ -441,7 +444,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm + 'static, + EvmConfig: ConfigureEvm, { /// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can /// be used to start the transport server(s). @@ -759,6 +762,7 @@ where + EvmEnvProvider + ChainSpecProvider + ChangeSetReader + + L1OriginReader + Clone + Unpin + 'static, @@ -766,7 +770,7 @@ where Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, Events: CanonStateSubscriptions + Clone + 'static, - EvmConfig: ConfigureEvm + 'static, + EvmConfig: ConfigureEvm, { /// Register Eth Namespace /// @@ -977,6 +981,11 @@ where .into_rpc() .into() } + RethRpcModule::Taiko => { + TaikoApi::new(self.provider.clone(), self.pool.clone()) + .into_rpc() + .into() + } }) .clone() }) @@ -995,7 +1004,7 @@ where /// /// This will spawn the required service tasks for [`EthApi`] for: /// - [`EthStateCache`] - /// - [`reth_rpc::eth::FeeHistoryCache`] + /// - [`FeeHistoryCache`](reth_rpc_eth_types::FeeHistoryCache) fn with_eth(&mut self, f: F) -> R where F: FnOnce(&EthHandlers) -> R, @@ -1250,9 +1259,9 @@ impl RpcServerConfig { /// /// If no server is configured, no server will be launched on [`RpcServerConfig::start`]. pub const fn has_server(&self) -> bool { - self.http_server_config.is_some() || - self.ws_server_config.is_some() || - self.ipc_server_config.is_some() + self.http_server_config.is_some() + || self.ws_server_config.is_some() + || self.ipc_server_config.is_some() } /// Returns the [`SocketAddr`] of the http server @@ -1303,9 +1312,9 @@ impl RpcServerConfig { ))); // If both are configured on the same port, we combine them into one server. - if self.http_addr == self.ws_addr && - self.http_server_config.is_some() && - self.ws_server_config.is_some() + if self.http_addr == self.ws_addr + && self.http_server_config.is_some() + && self.ws_server_config.is_some() { let cors = match (self.ws_cors_domains.as_ref(), self.http_cors_domains.as_ref()) { (Some(ws_cors), Some(http_cors)) => { @@ -1314,7 +1323,7 @@ impl RpcServerConfig { http_cors_domains: Some(http_cors.clone()), ws_cors_domains: Some(ws_cors.clone()), } - .into()) + .into()); } Some(ws_cors) } @@ -1355,7 +1364,7 @@ impl RpcServerConfig { ws_local_addr: Some(addr), server: WsHttpServers::SamePort(server), jwt_secret: self.jwt_secret, - }) + }); } let mut http_local_addr = None; @@ -1603,7 +1612,7 @@ impl TransportRpcModules { /// Returns [Ok(false)] if no http transport is configured. pub fn merge_http(&mut self, other: impl Into) -> Result { if let Some(ref mut http) = self.http { - return http.merge(other.into()).map(|_| true) + return http.merge(other.into()).map(|_| true); } Ok(false) } @@ -1615,7 +1624,7 @@ impl TransportRpcModules { /// Returns [Ok(false)] if no ws transport is configured. pub fn merge_ws(&mut self, other: impl Into) -> Result { if let Some(ref mut ws) = self.ws { - return ws.merge(other.into()).map(|_| true) + return ws.merge(other.into()).map(|_| true); } Ok(false) } @@ -1627,7 +1636,7 @@ impl TransportRpcModules { /// Returns [Ok(false)] if no ipc transport is configured. pub fn merge_ipc(&mut self, other: impl Into) -> Result { if let Some(ref mut ipc) = self.ipc { - return ipc.merge(other.into()).map(|_| true) + return ipc.merge(other.into()).map(|_| true); } Ok(false) } @@ -1835,8 +1844,8 @@ impl RpcServerHandle { "Bearer {}", secret .encode(&Claims { - iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() + - Duration::from_secs(60)) + iat: (SystemTime::now().duration_since(UNIX_EPOCH).unwrap() + + Duration::from_secs(60)) .as_secs(), exp: None, }) diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index caf16ebf6fce..f778dc22a9ab 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -11,7 +11,7 @@ use jsonrpsee::{ rpc_params, types::error::ErrorCode, }; -use reth_chainspec::net::NodeRecord; +use reth_network_peers::NodeRecord; use reth_primitives::{ hex_literal::hex, Address, BlockId, BlockNumberOrTag, Bytes, TxHash, B256, B64, U256, U64, }; diff --git a/crates/rpc/rpc-engine-api/Cargo.toml b/crates/rpc/rpc-engine-api/Cargo.toml index d067515f6c2a..d0fc7fb89ca4 100644 --- a/crates/rpc/rpc-engine-api/Cargo.toml +++ b/crates/rpc/rpc-engine-api/Cargo.toml @@ -54,3 +54,4 @@ assert_matches.workspace = true [features] optimism = ["reth-primitives/optimism"] +taiko = ["reth-primitives/taiko"] diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 8185bbe8cc04..4833aed6f15d 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -10,7 +10,9 @@ use reth_payload_primitives::{ validate_payload_timestamp, EngineApiMessageVersion, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, }; -use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, Hardfork, B256, U64}; +#[cfg(feature = "taiko")] +use reth_payload_builder::TaikoExecutionPayload; +use reth_primitives::{BlockHash, BlockHashOrNumber, BlockNumber, EthereumHardfork, B256, U64}; use reth_rpc_api::EngineApiServer; use reth_rpc_types::engine::{ CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, @@ -118,6 +120,8 @@ where EngineApiMessageVersion::V1, payload_or_attrs, )?; + #[cfg(feature = "taiko")] + let payload = TaikoExecutionPayload::from(payload); Ok(self.inner.beacon_consensus.new_payload(payload, None).await?) } @@ -136,6 +140,8 @@ where EngineApiMessageVersion::V2, payload_or_attrs, )?; + #[cfg(feature = "taiko")] + let payload = TaikoExecutionPayload::from(payload); Ok(self.inner.beacon_consensus.new_payload(payload, None).await?) } @@ -160,6 +166,8 @@ where let cancun_fields = CancunPayloadFields { versioned_hashes, parent_beacon_block_root }; + #[cfg(feature = "taiko")] + let payload = TaikoExecutionPayload::from(payload); Ok(self.inner.beacon_consensus.new_payload(payload, Some(cancun_fields)).await?) } @@ -426,7 +434,7 @@ where ) -> EngineApiResult { let len = hashes.len() as u64; if len > MAX_PAYLOAD_BODIES_LIMIT { - return Err(EngineApiError::PayloadRequestTooLarge { len }) + return Err(EngineApiError::PayloadRequestTooLarge { len }); } let mut result = Vec::with_capacity(hashes.len()); @@ -457,7 +465,7 @@ where let merge_terminal_td = self .inner .chain_spec - .fork(Hardfork::Paris) + .fork(EthereumHardfork::Paris) .ttd() .expect("the engine API should not be running for chains w/o paris"); @@ -466,7 +474,7 @@ where return Err(EngineApiError::TerminalTD { execution: merge_terminal_td, consensus: terminal_total_difficulty, - }) + }); } self.inner.beacon_consensus.transition_configuration_exchanged().await; @@ -476,7 +484,7 @@ where return Ok(TransitionConfiguration { terminal_total_difficulty: merge_terminal_td, ..Default::default() - }) + }); } // Attempt to look up terminal block hash @@ -541,9 +549,9 @@ where // TODO: decide if we want this branch - the FCU INVALID response might be more // useful than the payload attributes INVALID response if fcu_res.is_invalid() { - return Ok(fcu_res) + return Ok(fcu_res); } - return Err(err.into()) + return Err(err.into()); } } @@ -979,8 +987,8 @@ mod tests { blocks .iter() .filter(|b| { - !first_missing_range.contains(&b.number) && - !second_missing_range.contains(&b.number) + !first_missing_range.contains(&b.number) + && !second_missing_range.contains(&b.number) }) .map(|b| (b.hash(), b.clone().unseal())), ); @@ -1009,8 +1017,8 @@ mod tests { // ensure we still return trailing `None`s here because by-hash will not be aware // of the missing block's number, and cannot compare it to the current best block .map(|b| { - if first_missing_range.contains(&b.number) || - second_missing_range.contains(&b.number) + if first_missing_range.contains(&b.number) + || second_missing_range.contains(&b.number) { None } else { @@ -1036,7 +1044,11 @@ mod tests { let (handle, api) = setup_engine_api(); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap() + + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap() + U256::from(1), ..Default::default() }; @@ -1046,7 +1058,7 @@ mod tests { assert_matches!( res, Err(EngineApiError::TerminalTD { execution, consensus }) - if execution == handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap() && consensus == U256::from(transition_config.terminal_total_difficulty) + if execution == handle.chain_spec.fork(EthereumHardfork::Paris).ttd().unwrap() && consensus == U256::from(transition_config.terminal_total_difficulty) ); } @@ -1063,7 +1075,11 @@ mod tests { random_block(&mut rng, terminal_block_number, None, None, None); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap(), + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap(), terminal_block_hash: consensus_terminal_block.hash(), terminal_block_number: U64::from(terminal_block_number), }; @@ -1101,7 +1117,11 @@ mod tests { random_block(&mut generators::rng(), terminal_block_number, None, None, None); let transition_config = TransitionConfiguration { - terminal_total_difficulty: handle.chain_spec.fork(Hardfork::Paris).ttd().unwrap(), + terminal_total_difficulty: handle + .chain_spec + .fork(EthereumHardfork::Paris) + .ttd() + .unwrap(), terminal_block_hash: terminal_block.hash(), terminal_block_number: U64::from(terminal_block_number), }; diff --git a/crates/rpc/rpc-eth-api/Cargo.toml b/crates/rpc/rpc-eth-api/Cargo.toml new file mode 100644 index 000000000000..fb8d84b3f4b7 --- /dev/null +++ b/crates/rpc/rpc-eth-api/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "reth-rpc-eth-api" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +description = "Reth RPC 'eth' namespace API" + +[lints] +workspace = true + +[dependencies] +# reth +revm.workspace = true +revm-inspectors = { workspace = true, features = ["js-tracer"] } +revm-primitives = { workspace = true, features = ["dev"] } +reth-errors.workspace = true +reth-evm.workspace = true +reth-primitives.workspace = true +reth-provider.workspace = true +reth-revm.workspace = true +reth-rpc-types.workspace = true +reth-rpc-types-compat.workspace = true +reth-tasks = { workspace = true, features = ["rayon"] } +reth-transaction-pool.workspace = true +reth-chainspec.workspace = true +reth-execution-types.workspace = true +reth-rpc-eth-types.workspace = true +reth-rpc-server-types.workspace = true + +# ethereum +alloy-dyn-abi = { workspace = true, features = ["eip712"] } + +# rpc +jsonrpsee = { workspace = true, features = ["server", "macros"] } + +# async +async-trait.workspace = true +futures.workspace = true +parking_lot.workspace = true +tokio.workspace = true + +# misc +auto_impl.workspace = true +dyn-clone.workspace = true +tracing.workspace = true + +[features] +client = ["jsonrpsee/client", "jsonrpsee/async-client"] +optimism = [ + "reth-primitives/optimism", + "revm/optimism", + "reth-provider/optimism", + "reth-rpc-eth-types/optimism" +] \ No newline at end of file diff --git a/crates/rpc/rpc-api/src/bundle.rs b/crates/rpc/rpc-eth-api/src/bundle.rs similarity index 98% rename from crates/rpc/rpc-api/src/bundle.rs rename to crates/rpc/rpc-eth-api/src/bundle.rs index 429f6948f8ab..f657e30c430c 100644 --- a/crates/rpc/rpc-api/src/bundle.rs +++ b/crates/rpc/rpc-eth-api/src/bundle.rs @@ -1,4 +1,4 @@ -//! Additional `eth_` functions for bundles +//! Additional `eth_` RPC API for bundles. //! //! See also diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs new file mode 100644 index 000000000000..834682670cae --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -0,0 +1,727 @@ +//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`] trait. Handles RPC requests for +//! the `eth_` namespace. + +use alloy_dyn_abi::TypedData; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64}; +use reth_rpc_eth_types::EthApiError; +use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult}; +use reth_rpc_types::{ + serde_helpers::JsonStorageKey, + state::{EvmOverrides, StateOverride}, + AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle, + EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock, + StateContext, SyncStatus, Transaction, TransactionRequest, Work, +}; +use tracing::trace; + +use crate::helpers::{ + EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, LoadReceipt, Trace, +}; + +/// Eth rpc interface: +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))] +pub trait EthApi { + /// Returns the protocol version encoded as a string. + #[method(name = "protocolVersion")] + async fn protocol_version(&self) -> RpcResult; + + /// Returns an object with data about the sync status or false. + #[method(name = "syncing")] + fn syncing(&self) -> RpcResult; + + /// Returns the client coinbase address. + #[method(name = "coinbase")] + async fn author(&self) -> RpcResult
; + + /// Returns a list of addresses owned by client. + #[method(name = "accounts")] + fn accounts(&self) -> RpcResult>; + + /// Returns the number of most recent block. + #[method(name = "blockNumber")] + fn block_number(&self) -> RpcResult; + + /// Returns the chain ID of the current network. + #[method(name = "chainId")] + async fn chain_id(&self) -> RpcResult>; + + /// Returns information about a block by hash. + #[method(name = "getBlockByHash")] + async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult>; + + /// Returns information about a block by number. + #[method(name = "getBlockByNumber")] + async fn block_by_number( + &self, + number: BlockNumberOrTag, + full: bool, + ) -> RpcResult>; + + /// Returns the number of transactions in a block from a block matching the given block hash. + #[method(name = "getBlockTransactionCountByHash")] + async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult>; + + /// Returns the number of transactions in a block matching the given block number. + #[method(name = "getBlockTransactionCountByNumber")] + async fn block_transaction_count_by_number( + &self, + number: BlockNumberOrTag, + ) -> RpcResult>; + + /// Returns the number of uncles in a block from a block matching the given block hash. + #[method(name = "getUncleCountByBlockHash")] + async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult>; + + /// Returns the number of uncles in a block with given block number. + #[method(name = "getUncleCountByBlockNumber")] + async fn block_uncles_count_by_number( + &self, + number: BlockNumberOrTag, + ) -> RpcResult>; + + /// Returns all transaction receipts for a given block. + #[method(name = "getBlockReceipts")] + async fn block_receipts( + &self, + block_id: BlockId, + ) -> RpcResult>>; + + /// Returns an uncle block of the given block and index. + #[method(name = "getUncleByBlockHashAndIndex")] + async fn uncle_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult>; + + /// Returns an uncle block of the given block and index. + #[method(name = "getUncleByBlockNumberAndIndex")] + async fn uncle_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult>; + + /// Returns the EIP-2718 encoded transaction if it exists. + /// + /// If this is a EIP-4844 transaction that is in the pool it will include the sidecar. + #[method(name = "getRawTransactionByHash")] + async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult>; + + /// Returns the information about a transaction requested by transaction hash. + #[method(name = "getTransactionByHash")] + async fn transaction_by_hash(&self, hash: B256) -> RpcResult>; + + /// Returns information about a raw transaction by block hash and transaction index position. + #[method(name = "getRawTransactionByBlockHashAndIndex")] + async fn raw_transaction_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult>; + + /// Returns information about a transaction by block hash and transaction index position. + #[method(name = "getTransactionByBlockHashAndIndex")] + async fn transaction_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult>; + + /// Returns information about a raw transaction by block number and transaction index + /// position. + #[method(name = "getRawTransactionByBlockNumberAndIndex")] + async fn raw_transaction_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult>; + + /// Returns information about a transaction by block number and transaction index position. + #[method(name = "getTransactionByBlockNumberAndIndex")] + async fn transaction_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult>; + + /// Returns the receipt of a transaction by transaction hash. + #[method(name = "getTransactionReceipt")] + async fn transaction_receipt(&self, hash: B256) -> RpcResult>; + + /// Returns the balance of the account of given address. + #[method(name = "getBalance")] + async fn balance(&self, address: Address, block_number: Option) -> RpcResult; + + /// Returns the value from a storage position at a given address + #[method(name = "getStorageAt")] + async fn storage_at( + &self, + address: Address, + index: JsonStorageKey, + block_number: Option, + ) -> RpcResult; + + /// Returns the number of transactions sent from an address at given block number. + #[method(name = "getTransactionCount")] + async fn transaction_count( + &self, + address: Address, + block_number: Option, + ) -> RpcResult; + + /// Returns code at a given address at given block number. + #[method(name = "getCode")] + async fn get_code(&self, address: Address, block_number: Option) -> RpcResult; + + /// Returns the block's header at given number. + #[method(name = "getHeaderByNumber")] + async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult>; + + /// Returns the block's header at given hash. + #[method(name = "getHeaderByHash")] + async fn header_by_hash(&self, hash: B256) -> RpcResult>; + + /// Executes a new message call immediately without creating a transaction on the block chain. + #[method(name = "call")] + async fn call( + &self, + request: TransactionRequest, + block_number: Option, + state_overrides: Option, + block_overrides: Option>, + ) -> RpcResult; + + /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the + /// optionality of state overrides + #[method(name = "callMany")] + async fn call_many( + &self, + bundle: Bundle, + state_context: Option, + state_override: Option, + ) -> RpcResult>; + + /// Generates an access list for a transaction. + /// + /// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction. + /// + /// An access list contains all storage slots and addresses touched by the transaction, except + /// for the sender account and the chain's precompiles. + /// + /// It returns list of addresses and storage keys used by the transaction, plus the gas + /// consumed when the access list is added. That is, it gives you the list of addresses and + /// storage keys that will be used by that transaction, plus the gas consumed if the access + /// list is included. Like eth_estimateGas, this is an estimation; the list could change + /// when the transaction is actually mined. Adding an accessList to your transaction does + /// not necessary result in lower gas usage compared to a transaction without an access + /// list. + #[method(name = "createAccessList")] + async fn create_access_list( + &self, + request: TransactionRequest, + block_number: Option, + ) -> RpcResult; + + /// Generates and returns an estimate of how much gas is necessary to allow the transaction to + /// complete. + #[method(name = "estimateGas")] + async fn estimate_gas( + &self, + request: TransactionRequest, + block_number: Option, + state_override: Option, + ) -> RpcResult; + + /// Returns the current price per gas in wei. + #[method(name = "gasPrice")] + async fn gas_price(&self) -> RpcResult; + + /// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions. + #[method(name = "maxPriorityFeePerGas")] + async fn max_priority_fee_per_gas(&self) -> RpcResult; + + /// Introduced in EIP-4844, returns the current blob base fee in wei. + #[method(name = "blobBaseFee")] + async fn blob_base_fee(&self) -> RpcResult; + + /// Returns the Transaction fee history + /// + /// Introduced in EIP-1559 for getting information on the appropriate priority fee to use. + /// + /// Returns transaction base fee per gas and effective priority fee per gas for the + /// requested/supported block range. The returned Fee history for the returned block range + /// can be a subsection of the requested range if not all blocks are available. + #[method(name = "feeHistory")] + async fn fee_history( + &self, + block_count: U64, + newest_block: BlockNumberOrTag, + reward_percentiles: Option>, + ) -> RpcResult; + + /// Returns whether the client is actively mining new blocks. + #[method(name = "mining")] + async fn is_mining(&self) -> RpcResult; + + /// Returns the number of hashes per second that the node is mining with. + #[method(name = "hashrate")] + async fn hashrate(&self) -> RpcResult; + + /// Returns the hash of the current block, the seedHash, and the boundary condition to be met + /// (“target”) + #[method(name = "getWork")] + async fn get_work(&self) -> RpcResult; + + /// Used for submitting mining hashrate. + /// + /// Can be used for remote miners to submit their hash rate. + /// It accepts the miner hash rate and an identifier which must be unique between nodes. + /// Returns `true` if the block was successfully submitted, `false` otherwise. + #[method(name = "submitHashrate")] + async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult; + + /// Used for submitting a proof-of-work solution. + #[method(name = "submitWork")] + async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult; + + /// Sends transaction; will block waiting for signer to return the + /// transaction hash. + #[method(name = "sendTransaction")] + async fn send_transaction(&self, request: TransactionRequest) -> RpcResult; + + /// Sends signed transaction, returning its hash. + #[method(name = "sendRawTransaction")] + async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult; + + /// Returns an Ethereum specific signature with: sign(keccak256("\x19Ethereum Signed Message:\n" + /// + len(message) + message))). + #[method(name = "sign")] + async fn sign(&self, address: Address, message: Bytes) -> RpcResult; + + /// Signs a transaction that can be submitted to the network at a later time using with + /// `sendRawTransaction.` + #[method(name = "signTransaction")] + async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult; + + /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). + #[method(name = "signTypedData")] + async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult; + + /// Returns the account and storage values of the specified account including the Merkle-proof. + /// This call can be used to verify that the data you are pulling from is not tampered with. + #[method(name = "getProof")] + async fn get_proof( + &self, + address: Address, + keys: Vec, + block_number: Option, + ) -> RpcResult; +} + +#[async_trait::async_trait] +impl EthApiServer for T +where + Self: EthApiSpec + + EthTransactions + + EthBlocks + + EthState + + EthCall + + EthFees + + Trace + + LoadReceipt, +{ + /// Handler for: `eth_protocolVersion` + async fn protocol_version(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_protocolVersion"); + EthApiSpec::protocol_version(self).await.to_rpc_result() + } + + /// Handler for: `eth_syncing` + fn syncing(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_syncing"); + EthApiSpec::sync_status(self).to_rpc_result() + } + + /// Handler for: `eth_coinbase` + async fn author(&self) -> RpcResult
{ + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_accounts` + fn accounts(&self) -> RpcResult> { + trace!(target: "rpc::eth", "Serving eth_accounts"); + Ok(EthApiSpec::accounts(self)) + } + + /// Handler for: `eth_blockNumber` + fn block_number(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_blockNumber"); + Ok(U256::from( + EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number, + )) + } + + /// Handler for: `eth_chainId` + async fn chain_id(&self) -> RpcResult> { + trace!(target: "rpc::eth", "Serving eth_chainId"); + Ok(Some(EthApiSpec::chain_id(self))) + } + + /// Handler for: `eth_getBlockByHash` + async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash"); + Ok(EthBlocks::rpc_block(self, hash.into(), full).await?) + } + + /// Handler for: `eth_getBlockByNumber` + async fn block_by_number( + &self, + number: BlockNumberOrTag, + full: bool, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber"); + Ok(EthBlocks::rpc_block(self, number.into(), full).await?) + } + + /// Handler for: `eth_getBlockTransactionCountByHash` + async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash"); + Ok(EthBlocks::block_transaction_count(self, hash.into()).await?.map(U256::from)) + } + + /// Handler for: `eth_getBlockTransactionCountByNumber` + async fn block_transaction_count_by_number( + &self, + number: BlockNumberOrTag, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber"); + Ok(EthBlocks::block_transaction_count(self, number.into()).await?.map(U256::from)) + } + + /// Handler for: `eth_getUncleCountByBlockHash` + async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash"); + Ok(EthBlocks::ommers(self, hash.into())?.map(|ommers| U256::from(ommers.len()))) + } + + /// Handler for: `eth_getUncleCountByBlockNumber` + async fn block_uncles_count_by_number( + &self, + number: BlockNumberOrTag, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber"); + Ok(EthBlocks::ommers(self, number.into())?.map(|ommers| U256::from(ommers.len()))) + } + + /// Handler for: `eth_getBlockReceipts` + async fn block_receipts( + &self, + block_id: BlockId, + ) -> RpcResult>> { + trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts"); + Ok(EthBlocks::block_receipts(self, block_id).await?) + } + + /// Handler for: `eth_getUncleByBlockHashAndIndex` + async fn uncle_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex"); + Ok(EthBlocks::ommer_by_block_and_index(self, hash.into(), index).await?) + } + + /// Handler for: `eth_getUncleByBlockNumberAndIndex` + async fn uncle_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex"); + Ok(EthBlocks::ommer_by_block_and_index(self, number.into(), index).await?) + } + + /// Handler for: `eth_getRawTransactionByHash` + async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash"); + Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?) + } + + /// Handler for: `eth_getTransactionByHash` + async fn transaction_by_hash(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash"); + Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into)) + } + + /// Handler for: `eth_getRawTransactionByBlockHashAndIndex` + async fn raw_transaction_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex"); + Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index).await?) + } + + /// Handler for: `eth_getTransactionByBlockHashAndIndex` + async fn transaction_by_block_hash_and_index( + &self, + hash: B256, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex"); + Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index).await?) + } + + /// Handler for: `eth_getRawTransactionByBlockNumberAndIndex` + async fn raw_transaction_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex"); + Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, number.into(), index) + .await?) + } + + /// Handler for: `eth_getTransactionByBlockNumberAndIndex` + async fn transaction_by_block_number_and_index( + &self, + number: BlockNumberOrTag, + index: Index, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex"); + Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index).await?) + } + + /// Handler for: `eth_getTransactionReceipt` + async fn transaction_receipt(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt"); + Ok(EthTransactions::transaction_receipt(self, hash).await?) + } + + /// Handler for: `eth_getBalance` + async fn balance(&self, address: Address, block_number: Option) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); + Ok(EthState::balance(self, address, block_number).await?) + } + + /// Handler for: `eth_getStorageAt` + async fn storage_at( + &self, + address: Address, + index: JsonStorageKey, + block_number: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); + let res: B256 = EthState::storage_at(self, address, index, block_number).await?; + Ok(res) + } + + /// Handler for: `eth_getTransactionCount` + async fn transaction_count( + &self, + address: Address, + block_number: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); + Ok(EthState::transaction_count(self, address, block_number).await?) + } + + /// Handler for: `eth_getCode` + async fn get_code(&self, address: Address, block_number: Option) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); + Ok(EthState::get_code(self, address, block_number).await?) + } + + /// Handler for: `eth_getHeaderByNumber` + async fn header_by_number(&self, block_number: BlockNumberOrTag) -> RpcResult> { + trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); + Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?) + } + + /// Handler for: `eth_getHeaderByHash` + async fn header_by_hash(&self, hash: B256) -> RpcResult> { + trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash"); + Ok(EthBlocks::rpc_block_header(self, hash.into()).await?) + } + + /// Handler for: `eth_call` + async fn call( + &self, + request: TransactionRequest, + block_number: Option, + state_overrides: Option, + block_overrides: Option>, + ) -> RpcResult { + trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call"); + Ok(EthCall::call( + self, + request, + block_number, + EvmOverrides::new(state_overrides, block_overrides), + ) + .await?) + } + + /// Handler for: `eth_callMany` + async fn call_many( + &self, + bundle: Bundle, + state_context: Option, + state_override: Option, + ) -> RpcResult> { + trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany"); + Ok(EthCall::call_many(self, bundle, state_context, state_override).await?) + } + + /// Handler for: `eth_createAccessList` + async fn create_access_list( + &self, + request: TransactionRequest, + block_number: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList"); + let access_list_with_gas_used = + EthCall::create_access_list_at(self, request, block_number).await?; + + Ok(access_list_with_gas_used) + } + + /// Handler for: `eth_estimateGas` + async fn estimate_gas( + &self, + request: TransactionRequest, + block_number: Option, + state_override: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas"); + Ok(EthCall::estimate_gas_at( + self, + request, + block_number.unwrap_or_default(), + state_override, + ) + .await?) + } + + /// Handler for: `eth_gasPrice` + async fn gas_price(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_gasPrice"); + return Ok(EthFees::gas_price(self).await?) + } + + /// Handler for: `eth_maxPriorityFeePerGas` + async fn max_priority_fee_per_gas(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas"); + return Ok(EthFees::suggested_priority_fee(self).await?) + } + + /// Handler for: `eth_blobBaseFee` + async fn blob_base_fee(&self) -> RpcResult { + trace!(target: "rpc::eth", "Serving eth_blobBaseFee"); + return Ok(EthFees::blob_base_fee(self).await?) + } + + // FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further + // caching of it in the LRU cache. + // When new RPC call is executed, the cache gets locked, we check it for the historical fees + // according to the requested block range, and fill any cache misses (in both RPC response + // and cache itself) with the actual data queried from the database. + // To minimize the number of database seeks required to query the missing data, we calculate the + // first non-cached block number and last non-cached block number. After that, we query this + // range of consecutive blocks from the database. + /// Handler for: `eth_feeHistory` + async fn fee_history( + &self, + block_count: U64, + newest_block: BlockNumberOrTag, + reward_percentiles: Option>, + ) -> RpcResult { + trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory"); + return Ok( + EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await? + ) + } + + /// Handler for: `eth_mining` + async fn is_mining(&self) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_hashrate` + async fn hashrate(&self) -> RpcResult { + Ok(U256::ZERO) + } + + /// Handler for: `eth_getWork` + async fn get_work(&self) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_submitHashrate` + async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> RpcResult { + Ok(false) + } + + /// Handler for: `eth_submitWork` + async fn submit_work( + &self, + _nonce: B64, + _pow_hash: B256, + _mix_digest: B256, + ) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_sendTransaction` + async fn send_transaction(&self, request: TransactionRequest) -> RpcResult { + trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction"); + Ok(EthTransactions::send_transaction(self, request).await?) + } + + /// Handler for: `eth_sendRawTransaction` + async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult { + trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction"); + Ok(EthTransactions::send_raw_transaction(self, tx).await?) + } + + /// Handler for: `eth_sign` + async fn sign(&self, address: Address, message: Bytes) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign"); + Ok(EthTransactions::sign(self, address, message).await?) + } + + /// Handler for: `eth_signTransaction` + async fn sign_transaction(&self, _transaction: TransactionRequest) -> RpcResult { + Err(internal_rpc_err("unimplemented")) + } + + /// Handler for: `eth_signTypedData` + async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData"); + Ok(EthTransactions::sign_typed_data(self, &data, address)?) + } + + /// Handler for: `eth_getProof` + async fn get_proof( + &self, + address: Address, + keys: Vec, + block_number: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); + let res = EthState::get_proof(self, address, keys, block_number)?.await; + + Ok(res.map_err(|e| match e { + EthApiError::InvalidBlockRange => { + internal_rpc_err("eth_getProof is unimplemented for historical blocks") + } + _ => e.into(), + })?) + } +} diff --git a/crates/rpc/rpc-api/src/eth_filter.rs b/crates/rpc/rpc-eth-api/src/filter.rs similarity index 97% rename from crates/rpc/rpc-api/src/eth_filter.rs rename to crates/rpc/rpc-eth-api/src/filter.rs index 2e395d5bad76..da53b577eec5 100644 --- a/crates/rpc/rpc-api/src/eth_filter.rs +++ b/crates/rpc/rpc-eth-api/src/filter.rs @@ -1,5 +1,8 @@ +//! `eth_` RPC API for filtering. + use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_rpc_types::{Filter, FilterChanges, FilterId, Log, PendingTransactionFilterKind}; + /// Rpc Interface for poll-based ethereum filter API. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))] diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs new file mode 100644 index 000000000000..78f1ef9da66b --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -0,0 +1,234 @@ +//! Database access for `eth_` block RPC methods. Loads block and receipt data w.r.t. network. + +use std::sync::Arc; + +use futures::Future; +use reth_primitives::{BlockId, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta}; +use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider}; +use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock}; +use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; + +use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking}; + +/// Block related functions for the [`EthApiServer`](crate::EthApiServer) trait in the +/// `eth_` namespace. +pub trait EthBlocks: LoadBlock { + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl HeaderProvider; + + /// Returns the block header for the given block id. + fn rpc_block_header( + &self, + block_id: BlockId, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { Ok(self.rpc_block(block_id, false).await?.map(|block| block.inner.header)) } + } + + /// Returns the populated rpc block object for the given block id. + /// + /// If `full` is true, the block object will contain all transaction objects, otherwise it will + /// only contain the transaction hashes. + fn rpc_block( + &self, + block_id: BlockId, + full: bool, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { + let block = match self.block_with_senders(block_id).await? { + Some(block) => block, + None => return Ok(None), + }; + let block_hash = block.hash(); + let total_difficulty = EthBlocks::provider(self) + .header_td_by_number(block.number)? + .ok_or(EthApiError::UnknownBlockNumber)?; + let block = + from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))?; + Ok(Some(block.into())) + } + } + + /// Returns the number transactions in the given block. + /// + /// Returns `None` if the block does not exist + fn block_transaction_count( + &self, + block_id: BlockId, + ) -> impl Future>> + Send { + async move { + if block_id.is_pending() { + // Pending block can be fetched directly without need for caching + return Ok(LoadBlock::provider(self).pending_block()?.map(|block| block.body.len())) + } + + let block_hash = match LoadBlock::provider(self).block_hash_for_id(block_id)? { + Some(block_hash) => block_hash, + None => return Ok(None), + }; + + Ok(self.cache().get_block_transactions(block_hash).await?.map(|txs| txs.len())) + } + } + + /// Helper function for `eth_getBlockReceipts`. + /// + /// Returns all transaction receipts in block, or `None` if block wasn't found. + fn block_receipts( + &self, + block_id: BlockId, + ) -> impl Future>>> + Send + where + Self: LoadReceipt, + { + async move { + if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? { + let block_number = block.number; + let base_fee = block.base_fee_per_gas; + let block_hash = block.hash(); + let excess_blob_gas = block.excess_blob_gas; + let timestamp = block.timestamp; + let block = block.unseal(); + + let receipts = block + .body + .into_iter() + .zip(receipts.iter()) + .enumerate() + .map(|(idx, (tx, receipt))| { + let meta = TransactionMeta { + tx_hash: tx.hash, + index: idx as u64, + block_hash, + block_number, + base_fee, + excess_blob_gas, + timestamp, + }; + + ReceiptBuilder::new(&tx, meta, receipt, &receipts) + .map(|builder| builder.build()) + }) + .collect::>>(); + return receipts.map(Some) + } + + Ok(None) + } + } + + /// Helper method that loads a bock and all its receipts. + fn load_block_and_receipts( + &self, + block_id: BlockId, + ) -> impl Future>)>>> + Send + where + Self: LoadReceipt, + { + async move { + if block_id.is_pending() { + return Ok(LoadBlock::provider(self) + .pending_block_and_receipts()? + .map(|(sb, receipts)| (sb, Arc::new(receipts)))) + } + + if let Some(block_hash) = LoadBlock::provider(self).block_hash_for_id(block_id)? { + return Ok(LoadReceipt::cache(self).get_block_and_receipts(block_hash).await?) + } + + Ok(None) + } + } + + /// Returns uncle headers of given block. + /// + /// Returns an empty vec if there are none. + fn ommers(&self, block_id: BlockId) -> EthResult>> { + Ok(LoadBlock::provider(self).ommers_by_id(block_id)?) + } + + /// Returns uncle block at given index in given block. + /// + /// Returns `None` if index out of range. + fn ommer_by_block_and_index( + &self, + block_id: BlockId, + index: Index, + ) -> impl Future>> + Send { + async move { + let uncles = if block_id.is_pending() { + // Pending block can be fetched directly without need for caching + LoadBlock::provider(self).pending_block()?.map(|block| block.ommers) + } else { + LoadBlock::provider(self).ommers_by_id(block_id)? + } + .unwrap_or_default(); + + let index = usize::from(index); + let uncle = + uncles.into_iter().nth(index).map(|header| uncle_block_from_header(header).into()); + Ok(uncle) + } + } +} + +/// Loads a block from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. +pub trait LoadBlock: LoadPendingBlock + SpawnBlocking { + // Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl BlockReaderIdExt; + + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Returns the block object for the given block id. + fn block( + &self, + block_id: BlockId, + ) -> impl Future>> + Send { + async move { + self.block_with_senders(block_id) + .await + .map(|maybe_block| maybe_block.map(|block| block.block)) + } + } + + /// Returns the block object for the given block id. + fn block_with_senders( + &self, + block_id: BlockId, + ) -> impl Future>> + Send { + async move { + if block_id.is_pending() { + // Pending block can be fetched directly without need for caching + let maybe_pending = + LoadPendingBlock::provider(self).pending_block_with_senders()?; + return if maybe_pending.is_some() { + Ok(maybe_pending) + } else { + self.local_pending_block().await + } + } + + let block_hash = match LoadPendingBlock::provider(self).block_hash_for_id(block_id)? { + Some(block_hash) => block_hash, + None => return Ok(None), + }; + + Ok(self.cache().get_sealed_block_with_senders(block_hash).await?) + } + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs new file mode 100644 index 000000000000..c199d4de6178 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/blocking_task.rs @@ -0,0 +1,54 @@ +//! Spawns a blocking task. CPU heavy tasks are executed with the `rayon` library. IO heavy tasks +//! are executed on the `tokio` runtime. + +use futures::Future; +use reth_rpc_eth_types::{EthApiError, EthResult}; +use reth_tasks::{pool::BlockingTaskPool, TaskSpawner}; +use tokio::sync::oneshot; + +/// Executes code on a blocking thread. +pub trait SpawnBlocking: Clone + Send + Sync + 'static { + /// Returns a handle for spawning IO heavy blocking tasks. + /// + /// Runtime access in default trait method implementations. + fn io_task_spawner(&self) -> impl TaskSpawner; + + /// Returns a handle for spawning CPU heavy blocking tasks. + /// + /// Thread pool access in default trait method implementations. + fn tracing_task_pool(&self) -> &BlockingTaskPool; + + /// Executes the future on a new blocking task. + /// + /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing + /// or CPU bound operations in general use [`spawn_tracing`](Self::spawn_tracing). + fn spawn_blocking_io(&self, f: F) -> impl Future> + Send + where + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static, + { + let (tx, rx) = oneshot::channel(); + let this = self.clone(); + self.io_task_spawner().spawn_blocking(Box::pin(async move { + let res = async move { f(this) }.await; + let _ = tx.send(res); + })); + + async move { rx.await.map_err(|_| EthApiError::InternalEthError)? } + } + + /// Executes a blocking task on the tracing pool. + /// + /// Note: This is expected for futures that are predominantly CPU bound, as it uses `rayon` + /// under the hood, for blocking IO futures use [`spawn_blocking`](Self::spawn_blocking_io). See + /// . + fn spawn_tracing(&self, f: F) -> impl Future> + Send + where + F: FnOnce(Self) -> EthResult + Send + 'static, + R: Send + 'static, + { + let this = self.clone(); + let fut = self.tracing_task_pool().spawn(move || f(this)); + async move { fut.await.map_err(|_| EthApiError::InternalBlockingTaskError)? } + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs new file mode 100644 index 000000000000..5f6aebaa85b3 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -0,0 +1,779 @@ +//! Loads a pending block from database. Helper trait for `eth_` transaction, call and trace RPC +//! methods. + +use futures::Future; +use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; +use reth_primitives::{ + revm_primitives::{ + BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HaltReason, + ResultAndState, TransactTo, + }, + Bytes, TransactionSignedEcRecovered, TxKind, B256, U256, +}; +use reth_provider::StateProvider; +use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef}; +use reth_rpc_eth_types::{ + cache::db::{StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, + error::ensure_success, + revm_utils::{ + apply_state_overrides, build_call_evm_env, caller_gas_allowance, + cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env, + }, + EthApiError, EthResult, RevertError, RpcInvalidTransactionError, StateCacheDb, +}; +use reth_rpc_server_types::constants::gas_oracle::{ESTIMATE_GAS_ERROR_RATIO, MIN_TRANSACTION_GAS}; +use reth_rpc_types::{ + state::{EvmOverrides, StateOverride}, + AccessListWithGasUsed, BlockId, Bundle, EthCallResponse, StateContext, TransactionInfo, + TransactionRequest, +}; +use revm::{Database, DatabaseCommit}; +use revm_inspectors::access_list::AccessListInspector; +use tracing::trace; + +use super::{LoadBlock, LoadPendingBlock, LoadState, LoadTransaction, SpawnBlocking, Trace}; + +/// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in +/// the `eth_` namespace. +pub trait EthCall: Call + LoadPendingBlock { + /// Estimate gas needed for execution of the `request` at the [`BlockId`]. + fn estimate_gas_at( + &self, + request: TransactionRequest, + at: BlockId, + state_override: Option, + ) -> impl Future> + Send { + Call::estimate_gas_at(self, request, at, state_override) + } + + /// Executes the call request (`eth_call`) and returns the output + fn call( + &self, + request: TransactionRequest, + block_number: Option, + overrides: EvmOverrides, + ) -> impl Future> + Send { + async move { + let (res, _env) = + self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?; + + ensure_success(res.result) + } + } + + /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the + /// optionality of state overrides + fn call_many( + &self, + bundle: Bundle, + state_context: Option, + mut state_override: Option, + ) -> impl Future>> + Send + where + Self: LoadBlock, + { + async move { + let Bundle { transactions, block_override } = bundle; + if transactions.is_empty() { + return Err(EthApiError::InvalidParams(String::from("transactions are empty."))) + } + + let StateContext { transaction_index, block_number } = + state_context.unwrap_or_default(); + let transaction_index = transaction_index.unwrap_or_default(); + + let target_block = block_number.unwrap_or_default(); + let is_block_target_pending = target_block.is_pending(); + + let ((cfg, block_env, _), block) = futures::try_join!( + self.evm_env_at(target_block), + self.block_with_senders(target_block) + )?; + + let Some(block) = block else { return Err(EthApiError::UnknownBlockNumber) }; + let gas_limit = self.call_gas_limit(); + + // we're essentially replaying the transactions in the block here, hence we need the + // state that points to the beginning of the block, which is the state at + // the parent block + let mut at = block.parent_hash; + let mut replay_block_txs = true; + + let num_txs = transaction_index.index().unwrap_or(block.body.len()); + // but if all transactions are to be replayed, we can use the state at the block itself, + // however only if we're not targeting the pending block, because for pending we can't + // rely on the block's state being available + if !is_block_target_pending && num_txs == block.body.len() { + at = block.hash(); + replay_block_txs = false; + } + + let this = self.clone(); + self.spawn_with_state_at_block(at.into(), move |state| { + let mut results = Vec::with_capacity(transactions.len()); + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + if replay_block_txs { + // only need to replay the transactions in the block if not all transactions are + // to be replayed + let transactions = block.into_transactions_ecrecovered().take(num_txs); + for tx in transactions { + let env = EnvWithHandlerCfg::new_with_cfg_env( + cfg.clone(), + block_env.clone(), + Call::evm_config(&this).tx_env(&tx), + ); + let (res, _) = this.transact(&mut db, env)?; + db.commit(res.state); + } + } + + let block_overrides = block_override.map(Box::new); + + let mut transactions = transactions.into_iter().peekable(); + while let Some(tx) = transactions.next() { + // apply state overrides only once, before the first transaction + let state_overrides = state_override.take(); + let overrides = EvmOverrides::new(state_overrides, block_overrides.clone()); + + let env = prepare_call_env( + cfg.clone(), + block_env.clone(), + tx, + gas_limit, + &mut db, + overrides, + )?; + let (res, _) = this.transact(&mut db, env)?; + + match ensure_success(res.result) { + Ok(output) => { + results.push(EthCallResponse { value: Some(output), error: None }); + } + Err(err) => { + results.push(EthCallResponse { + value: None, + error: Some(err.to_string()), + }); + } + } + + if transactions.peek().is_some() { + // need to apply the state changes of this call before executing the next + // call + db.commit(res.state); + } + } + + Ok(results) + }) + .await + } + } + + /// Creates [`AccessListWithGasUsed`] for the [`TransactionRequest`] at the given + /// [`BlockId`], or latest block. + fn create_access_list_at( + &self, + request: TransactionRequest, + block_number: Option, + ) -> impl Future> + Send + where + Self: Trace, + { + async move { + let block_id = block_number.unwrap_or_default(); + let (cfg, block, at) = self.evm_env_at(block_id).await?; + + self.spawn_blocking_io(move |this| { + this.create_access_list_with(cfg, block, at, request) + }) + .await + } + } + + /// Creates [`AccessListWithGasUsed`] for the [`TransactionRequest`] at the given + /// [`BlockId`]. + fn create_access_list_with( + &self, + cfg: CfgEnvWithHandlerCfg, + block: BlockEnv, + at: BlockId, + mut request: TransactionRequest, + ) -> EthResult + where + Self: Trace, + { + let state = self.state_at_block_id(at)?; + + let mut env = build_call_evm_env(cfg, block, request.clone())?; + + // we want to disable this in eth_createAccessList, since this is common practice used by + // other node impls and providers + env.cfg.disable_block_gas_limit = true; + + // The basefee should be ignored for eth_createAccessList + // See: + // + env.cfg.disable_base_fee = true; + + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + if request.gas.is_none() && env.tx.gas_price > U256::ZERO { + // no gas limit was provided in the request, so we need to cap the request's gas limit + cap_tx_gas_limit_with_caller_allowance(&mut db, &mut env.tx)?; + } + + let from = request.from.unwrap_or_default(); + let to = if let Some(TxKind::Call(to)) = request.to { + to + } else { + let nonce = db.basic_ref(from)?.unwrap_or_default().nonce; + from.create(nonce) + }; + + // can consume the list since we're not using the request anymore + let initial = request.access_list.take().unwrap_or_default(); + + let precompiles = get_precompiles(env.handler_cfg.spec_id); + let mut inspector = AccessListInspector::new(initial, from, to, precompiles); + let (result, env) = self.inspect(&mut db, env, &mut inspector)?; + + match result.result { + ExecutionResult::Halt { reason, .. } => Err(match reason { + HaltReason::NonceOverflow => RpcInvalidTransactionError::NonceMaxValue, + halt => RpcInvalidTransactionError::EvmHalt(halt), + }), + ExecutionResult::Revert { output, .. } => { + Err(RpcInvalidTransactionError::Revert(RevertError::new(output))) + } + ExecutionResult::Success { .. } => Ok(()), + }?; + + let access_list = inspector.into_access_list(); + + let cfg_with_spec_id = + CfgEnvWithHandlerCfg { cfg_env: env.cfg.clone(), handler_cfg: env.handler_cfg }; + + // calculate the gas used using the access list + request.access_list = Some(access_list.clone()); + let gas_used = + self.estimate_gas_with(cfg_with_spec_id, env.block.clone(), request, &*db.db, None)?; + + Ok(AccessListWithGasUsed { access_list, gas_used }) + } +} + +/// Executes code on state. +pub trait Call: LoadState + SpawnBlocking { + /// Returns default gas limit to use for `eth_call` and tracing RPC methods. + /// + /// Data access in default trait method implementations. + fn call_gas_limit(&self) -> u64; + + /// Returns a handle for reading evm config. + /// + /// Data access in default (L1) trait method implementations. + fn evm_config(&self) -> &impl ConfigureEvm; + + /// Executes the closure with the state that corresponds to the given [`BlockId`]. + fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult + where + F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult, + { + let state = self.state_at_block_id(at)?; + f(StateProviderTraitObjWrapper(&state)) + } + + /// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state + /// changes. + fn transact( + &self, + db: DB, + env: EnvWithHandlerCfg, + ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + where + DB: Database, + ::Error: Into, + { + let mut evm = self.evm_config().evm_with_env(db, env); + let res = evm.transact()?; + let (_, env) = evm.into_db_and_env_with_handler_cfg(); + Ok((res, env)) + } + + /// Executes the call request at the given [`BlockId`]. + fn transact_call_at( + &self, + request: TransactionRequest, + at: BlockId, + overrides: EvmOverrides, + ) -> impl Future> + Send + where + Self: LoadPendingBlock, + { + let this = self.clone(); + self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env)) + } + + /// Executes the closure with the state that corresponds to the given [`BlockId`] on a new task + fn spawn_with_state_at_block( + &self, + at: BlockId, + f: F, + ) -> impl Future> + Send + where + F: FnOnce(StateProviderTraitObjWrapper<'_>) -> EthResult + Send + 'static, + T: Send + 'static, + { + self.spawn_tracing(move |this| { + let state = this.state_at_block_id(at)?; + f(StateProviderTraitObjWrapper(&state)) + }) + } + + /// Prepares the state and env for the given [`TransactionRequest`] at the given [`BlockId`] and + /// executes the closure on a new task returning the result of the closure. + /// + /// This returns the configured [`EnvWithHandlerCfg`] for the given [`TransactionRequest`] at + /// the given [`BlockId`] and with configured call settings: `prepare_call_env`. + fn spawn_with_call_at( + &self, + request: TransactionRequest, + at: BlockId, + overrides: EvmOverrides, + f: F, + ) -> impl Future> + Send + where + Self: LoadPendingBlock, + F: FnOnce(StateCacheDbRefMutWrapper<'_, '_>, EnvWithHandlerCfg) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + async move { + let (cfg, block_env, at) = self.evm_env_at(at).await?; + let this = self.clone(); + self.spawn_tracing(move |_| { + let state = this.state_at_block_id(at)?; + let mut db = + CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state))); + + let env = prepare_call_env( + cfg, + block_env, + request, + this.call_gas_limit(), + &mut db, + overrides, + )?; + + f(StateCacheDbRefMutWrapper(&mut db), env) + }) + .await + .map_err(|_| EthApiError::InternalBlockingTaskError) + } + } + + /// Retrieves the transaction if it exists and executes it. + /// + /// Before the transaction is executed, all previous transaction in the block are applied to the + /// state by executing them first. + /// The callback `f` is invoked with the [`ResultAndState`] after the transaction was executed + /// and the database that points to the beginning of the transaction. + /// + /// Note: Implementers should use a threadpool where blocking is allowed, such as + /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool). + fn spawn_replay_transaction( + &self, + hash: B256, + f: F, + ) -> impl Future>> + Send + where + Self: LoadBlock + LoadPendingBlock + LoadTransaction, + F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + async move { + let (transaction, block) = match self.transaction_and_block(hash).await? { + None => return Ok(None), + Some(res) => res, + }; + let (tx, tx_info) = transaction.split(); + + let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?; + + // we need to get the state of the parent block because we're essentially replaying the + // block the transaction is included in + let parent_block = block.parent_hash; + let block_txs = block.into_transactions_ecrecovered(); + + let this = self.clone(); + self.spawn_with_state_at_block(parent_block.into(), move |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + // replay all transactions prior to the targeted transaction + this.replay_transactions_until( + &mut db, + cfg.clone(), + block_env.clone(), + block_txs, + tx.hash, + )?; + + let env = EnvWithHandlerCfg::new_with_cfg_env( + cfg, + block_env, + Call::evm_config(&this).tx_env(&tx), + ); + + let (res, _) = this.transact(&mut db, env)?; + f(tx_info, res, db) + }) + .await + .map(Some) + } + } + + /// Replays all the transactions until the target transaction is found. + /// + /// All transactions before the target transaction are executed and their changes are written to + /// the _runtime_ db ([`CacheDB`]). + /// + /// Note: This assumes the target transaction is in the given iterator. + /// Returns the index of the target transaction in the given iterator. + fn replay_transactions_until( + &self, + db: &mut CacheDB, + cfg: CfgEnvWithHandlerCfg, + block_env: BlockEnv, + transactions: impl IntoIterator, + target_tx_hash: B256, + ) -> Result + where + DB: DatabaseRef, + EthApiError: From<::Error>, + { + let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); + + let mut evm = self.evm_config().evm_with_env(db, env); + let mut index = 0; + for tx in transactions { + if tx.hash() == target_tx_hash { + // reached the target transaction + break + } + + let sender = tx.signer(); + self.evm_config().fill_tx_env(evm.tx_mut(), &tx.into_signed(), sender); + evm.transact_commit()?; + index += 1; + } + Ok(index) + } + + /// Estimate gas needed for execution of the `request` at the [`BlockId`]. + fn estimate_gas_at( + &self, + request: TransactionRequest, + at: BlockId, + state_override: Option, + ) -> impl Future> + Send + where + Self: LoadPendingBlock, + { + async move { + let (cfg, block_env, at) = self.evm_env_at(at).await?; + + self.spawn_blocking_io(move |this| { + let state = this.state_at_block_id(at)?; + this.estimate_gas_with(cfg, block_env, request, state, state_override) + }) + .await + } + } + + /// Estimates the gas usage of the `request` with the state. + /// + /// This will execute the [`TransactionRequest`] and find the best gas limit via binary search + fn estimate_gas_with( + &self, + mut cfg: CfgEnvWithHandlerCfg, + block: BlockEnv, + request: TransactionRequest, + state: S, + state_override: Option, + ) -> EthResult + where + S: StateProvider, + { + // Disabled because eth_estimateGas is sometimes used with eoa senders + // See + cfg.disable_eip3607 = true; + + // The basefee should be ignored for eth_createAccessList + // See: + // + cfg.disable_base_fee = true; + + // Keep a copy of gas related request values + let tx_request_gas_limit = request.gas; + let tx_request_gas_price = request.gas_price; + let block_env_gas_limit = block.gas_limit; + + // Determine the highest possible gas limit, considering both the request's specified limit + // and the block's limit. + let mut highest_gas_limit = tx_request_gas_limit + .map(|tx_gas_limit| U256::from(tx_gas_limit).max(block_env_gas_limit)) + .unwrap_or(block_env_gas_limit); + + // Configure the evm env + let mut env = build_call_evm_env(cfg, block, request)?; + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + // Apply any state overrides if specified. + if let Some(state_override) = state_override { + apply_state_overrides(state_override, &mut db)?; + } + + // Optimize for simple transfer transactions, potentially reducing the gas estimate. + if env.tx.data.is_empty() { + if let TransactTo::Call(to) = env.tx.transact_to { + if let Ok(code) = db.db.account_code(to) { + let no_code_callee = code.map(|code| code.is_empty()).unwrap_or(true); + if no_code_callee { + // If the tx is a simple transfer (call to an account with no code) we can + // shortcircuit. But simply returning + // `MIN_TRANSACTION_GAS` is dangerous because there might be additional + // field combos that bump the price up, so we try executing the function + // with the minimum gas limit to make sure. + let mut env = env.clone(); + env.tx.gas_limit = MIN_TRANSACTION_GAS; + if let Ok((res, _)) = self.transact(&mut db, env) { + if res.result.is_success() { + return Ok(U256::from(MIN_TRANSACTION_GAS)) + } + } + } + } + } + } + + // Check funds of the sender (only useful to check if transaction gas price is more than 0). + // + // The caller allowance is check by doing `(account.balance - tx.value) / tx.gas_price` + if env.tx.gas_price > U256::ZERO { + // cap the highest gas limit by max gas caller can afford with given gas price + highest_gas_limit = highest_gas_limit.min(caller_gas_allowance(&mut db, &env.tx)?); + } + + // We can now normalize the highest gas limit to a u64 + let mut highest_gas_limit: u64 = highest_gas_limit.try_into().unwrap_or(u64::MAX); + + // If the provided gas limit is less than computed cap, use that + env.tx.gas_limit = env.tx.gas_limit.min(highest_gas_limit); + + trace!(target: "rpc::eth::estimate", ?env, "Starting gas estimation"); + + // Execute the transaction with the highest possible gas limit. + let (mut res, mut env) = match self.transact(&mut db, env.clone()) { + // Handle the exceptional case where the transaction initialization uses too much gas. + // If the gas price or gas limit was specified in the request, retry the transaction + // with the block's gas limit to determine if the failure was due to + // insufficient gas. + Err(EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) + if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() => + { + return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) + } + // Propagate other results (successful or other errors). + ethres => ethres?, + }; + + let gas_refund = match res.result { + ExecutionResult::Success { gas_refunded, .. } => gas_refunded, + ExecutionResult::Halt { reason, gas_used } => { + // here we don't check for invalid opcode because already executed with highest gas + // limit + return Err(RpcInvalidTransactionError::halt(reason, gas_used).into()) + } + ExecutionResult::Revert { output, .. } => { + // if price or limit was included in the request then we can execute the request + // again with the block's gas limit to check if revert is gas related or not + return if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() { + Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) + } else { + // the transaction did revert + Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into()) + } + } + }; + + // At this point we know the call succeeded but want to find the _best_ (lowest) gas the + // transaction succeeds with. We find this by doing a binary search over the possible range. + // + // NOTE: this is the gas the transaction used, which is less than the + // transaction requires to succeed. + let mut gas_used = res.result.gas_used(); + // the lowest value is capped by the gas used by the unconstrained transaction + let mut lowest_gas_limit = gas_used.saturating_sub(1); + + // As stated in Geth, there is a good chance that the transaction will pass if we set the + // gas limit to the execution gas used plus the gas refund, so we check this first + // 1 { + // An estimation error is allowed once the current gas limit range used in the binary + // search is small enough (less than 1.5% of the highest gas limit) + // { + // Increase the lowest gas limit if gas is too high + lowest_gas_limit = mid_gas_limit; + } + // Handle other cases, including successful transactions. + ethres => { + // Unpack the result and environment if the transaction was successful. + (res, env) = ethres?; + // Update the estimated gas range based on the transaction result. + self.update_estimated_gas_range( + res.result, + mid_gas_limit, + &mut highest_gas_limit, + &mut lowest_gas_limit, + )?; + } + } + + // New midpoint + mid_gas_limit = ((highest_gas_limit as u128 + lowest_gas_limit as u128) / 2) as u64; + } + + Ok(U256::from(highest_gas_limit)) + } + + /// Updates the highest and lowest gas limits for binary search based on the execution result. + /// + /// This function refines the gas limit estimates used in a binary search to find the optimal + /// gas limit for a transaction. It adjusts the highest or lowest gas limits depending on + /// whether the execution succeeded, reverted, or halted due to specific reasons. + #[inline] + fn update_estimated_gas_range( + &self, + result: ExecutionResult, + tx_gas_limit: u64, + highest_gas_limit: &mut u64, + lowest_gas_limit: &mut u64, + ) -> EthResult<()> { + match result { + ExecutionResult::Success { .. } => { + // Cap the highest gas limit with the succeeding gas limit. + *highest_gas_limit = tx_gas_limit; + } + ExecutionResult::Revert { .. } => { + // Increase the lowest gas limit. + *lowest_gas_limit = tx_gas_limit; + } + ExecutionResult::Halt { reason, .. } => { + match reason { + HaltReason::OutOfGas(_) | HaltReason::InvalidEFOpcode => { + // Both `OutOfGas` and `InvalidEFOpcode` can occur dynamically if the gas + // left is too low. Treat this as an out of gas + // condition, knowing that the call succeeds with a + // higher gas limit. + // + // Common usage of invalid opcode in OpenZeppelin: + // + + // Increase the lowest gas limit. + *lowest_gas_limit = tx_gas_limit; + } + err => { + // These cases should be unreachable because we know the transaction + // succeeds, but if they occur, treat them as an + // error. + return Err(RpcInvalidTransactionError::EvmHalt(err).into()) + } + } + } + }; + + Ok(()) + } + + /// Executes the requests again after an out of gas error to check if the error is gas related + /// or not + #[inline] + fn map_out_of_gas_err( + &self, + env_gas_limit: U256, + mut env: EnvWithHandlerCfg, + db: &mut CacheDB>, + ) -> EthApiError + where + S: StateProvider, + { + let req_gas_limit = env.tx.gas_limit; + env.tx.gas_limit = env_gas_limit.try_into().unwrap_or(u64::MAX); + let (res, _) = match self.transact(db, env) { + Ok(res) => res, + Err(err) => return err, + }; + match res.result { + ExecutionResult::Success { .. } => { + // transaction succeeded by manually increasing the gas limit to + // highest, which means the caller lacks funds to pay for the tx + RpcInvalidTransactionError::BasicOutOfGas(req_gas_limit).into() + } + ExecutionResult::Revert { output, .. } => { + // reverted again after bumping the limit + RpcInvalidTransactionError::Revert(RevertError::new(output)).into() + } + ExecutionResult::Halt { reason, .. } => { + RpcInvalidTransactionError::EvmHalt(reason).into() + } + } + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs new file mode 100644 index 000000000000..54c577ea2504 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -0,0 +1,346 @@ +//! Loads fee history from database. Helper trait for `eth_` fee and transaction RPC methods. + +use futures::Future; +use reth_primitives::U256; +use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider}; +use reth_rpc_eth_types::{ + fee_history::calculate_reward_percentiles_for_block, EthApiError, EthResult, EthStateCache, + FeeHistoryCache, FeeHistoryEntry, GasPriceOracle, RpcInvalidTransactionError, +}; +use reth_rpc_types::{BlockNumberOrTag, FeeHistory}; +use tracing::debug; + +use super::LoadBlock; + +/// Fee related functions for the [`EthApiServer`](crate::EthApiServer) trait in the +/// `eth_` namespace. +pub trait EthFees: LoadFee { + /// Returns a suggestion for a gas price for legacy transactions. + /// + /// See also: + fn gas_price(&self) -> impl Future> + Send + where + Self: LoadBlock, + { + LoadFee::gas_price(self) + } + + /// Returns a suggestion for a base fee for blob transactions. + fn blob_base_fee(&self) -> impl Future> + Send + where + Self: LoadBlock, + { + LoadFee::blob_base_fee(self) + } + + /// Returns a suggestion for the priority fee (the tip) + fn suggested_priority_fee(&self) -> impl Future> + Send + where + Self: 'static, + { + LoadFee::suggested_priority_fee(self) + } + + /// Reports the fee history, for the given amount of blocks, up until the given newest block. + /// + /// If `reward_percentiles` are provided the [`FeeHistory`] will include the _approximated_ + /// rewards for the requested range. + fn fee_history( + &self, + mut block_count: u64, + newest_block: BlockNumberOrTag, + reward_percentiles: Option>, + ) -> impl Future> + Send { + async move { + if block_count == 0 { + return Ok(FeeHistory::default()) + } + + // See https://github.com/ethereum/go-ethereum/blob/2754b197c935ee63101cbbca2752338246384fec/eth/gasprice/feehistory.go#L218C8-L225 + let max_fee_history = if reward_percentiles.is_none() { + self.gas_oracle().config().max_header_history + } else { + self.gas_oracle().config().max_block_history + }; + + if block_count > max_fee_history { + debug!( + requested = block_count, + truncated = max_fee_history, + "Sanitizing fee history block count" + ); + block_count = max_fee_history + } + + let Some(end_block) = + LoadFee::provider(self).block_number_for_id(newest_block.into())? + else { + return Err(EthApiError::UnknownBlockNumber) + }; + + // need to add 1 to the end block to get the correct (inclusive) range + let end_block_plus = end_block + 1; + // Ensure that we would not be querying outside of genesis + if end_block_plus < block_count { + block_count = end_block_plus; + } + + // If reward percentiles were specified, we + // need to validate that they are monotonically + // increasing and 0 <= p <= 100 + // Note: The types used ensure that the percentiles are never < 0 + if let Some(percentiles) = &reward_percentiles { + if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) { + return Err(EthApiError::InvalidRewardPercentiles) + } + } + + // Fetch the headers and ensure we got all of them + // + // Treat a request for 1 block as a request for `newest_block..=newest_block`, + // otherwise `newest_block - 2 + // NOTE: We ensured that block count is capped + let start_block = end_block_plus - block_count; + + // Collect base fees, gas usage ratios and (optionally) reward percentile data + let mut base_fee_per_gas: Vec = Vec::new(); + let mut gas_used_ratio: Vec = Vec::new(); + + let mut base_fee_per_blob_gas: Vec = Vec::new(); + let mut blob_gas_used_ratio: Vec = Vec::new(); + + let mut rewards: Vec> = Vec::new(); + + // Check if the requested range is within the cache bounds + let fee_entries = self.fee_history_cache().get_history(start_block, end_block).await; + + if let Some(fee_entries) = fee_entries { + if fee_entries.len() != block_count as usize { + return Err(EthApiError::InvalidBlockRange) + } + + for entry in &fee_entries { + base_fee_per_gas.push(entry.base_fee_per_gas as u128); + gas_used_ratio.push(entry.gas_used_ratio); + base_fee_per_blob_gas.push(entry.base_fee_per_blob_gas.unwrap_or_default()); + blob_gas_used_ratio.push(entry.blob_gas_used_ratio); + + if let Some(percentiles) = &reward_percentiles { + let mut block_rewards = Vec::with_capacity(percentiles.len()); + for &percentile in percentiles { + block_rewards.push(self.approximate_percentile(entry, percentile)); + } + rewards.push(block_rewards); + } + } + let last_entry = fee_entries.last().expect("is not empty"); + + // Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the + // next block + base_fee_per_gas + .push(last_entry.next_block_base_fee(&LoadFee::provider(self).chain_spec()) + as u128); + + base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default()); + } else { + // read the requested header range + let headers = LoadFee::provider(self).sealed_headers_range(start_block..=end_block)?; + if headers.len() != block_count as usize { + return Err(EthApiError::InvalidBlockRange) + } + + for header in &headers { + base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128); + gas_used_ratio.push(header.gas_used as f64 / header.gas_limit as f64); + base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default()); + blob_gas_used_ratio.push( + header.blob_gas_used.unwrap_or_default() as f64 / + reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, + ); + + // Percentiles were specified, so we need to collect reward percentile ino + if let Some(percentiles) = &reward_percentiles { + let (transactions, receipts) = LoadFee::cache(self) + .get_transactions_and_receipts(header.hash()) + .await? + .ok_or(EthApiError::InvalidBlockRange)?; + rewards.push( + calculate_reward_percentiles_for_block( + percentiles, + header.gas_used, + header.base_fee_per_gas.unwrap_or_default(), + &transactions, + &receipts, + ) + .unwrap_or_default(), + ); + } + } + + // The spec states that `base_fee_per_gas` "[..] includes the next block after the + // newest of the returned range, because this value can be derived from the + // newest block" + // + // The unwrap is safe since we checked earlier that we got at least 1 header. + let last_header = headers.last().expect("is present"); + base_fee_per_gas.push( + LoadFee::provider(self).chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee( + last_header.gas_used as u128, + last_header.gas_limit as u128, + last_header.base_fee_per_gas.unwrap_or_default() as u128, + )); + + // Same goes for the `base_fee_per_blob_gas`: + // > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block. + base_fee_per_blob_gas + .push(last_header.next_block_blob_fee().unwrap_or_default()); + }; + + Ok(FeeHistory { + base_fee_per_gas, + gas_used_ratio, + base_fee_per_blob_gas, + blob_gas_used_ratio, + oldest_block: start_block, + reward: reward_percentiles.map(|_| rewards), + }) + } + } + + /// Approximates reward at a given percentile for a specific block + /// Based on the configured resolution + fn approximate_percentile(&self, entry: &FeeHistoryEntry, requested_percentile: f64) -> u128 { + let resolution = self.fee_history_cache().resolution(); + let rounded_percentile = + (requested_percentile * resolution as f64).round() / resolution as f64; + let clamped_percentile = rounded_percentile.clamp(0.0, 100.0); + + // Calculate the index in the precomputed rewards array + let index = (clamped_percentile / (1.0 / resolution as f64)).round() as usize; + // Fetch the reward from the FeeHistoryEntry + entry.rewards.get(index).cloned().unwrap_or_default() + } +} + +/// Loads fee from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` fees RPC methods. +pub trait LoadFee: LoadBlock { + // Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl BlockIdReader + HeaderProvider + ChainSpecProvider; + + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Returns a handle for reading gas price. + /// + /// Data access in default (L1) trait method implementations. + fn gas_oracle(&self) -> &GasPriceOracle; + + /// Returns a handle for reading fee history data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn fee_history_cache(&self) -> &FeeHistoryCache; + + /// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy + /// transactions. + fn legacy_gas_price( + &self, + gas_price: Option, + ) -> impl Future> + Send { + async move { + match gas_price { + Some(gas_price) => Ok(gas_price), + None => { + // fetch a suggested gas price + self.gas_price().await + } + } + } + } + + /// Returns the EIP-1559 fees if they are set, otherwise fetches a suggested gas price for + /// EIP-1559 transactions. + /// + /// Returns (`max_fee`, `priority_fee`) + fn eip1559_fees( + &self, + max_fee_per_gas: Option, + max_priority_fee_per_gas: Option, + ) -> impl Future> + Send { + async move { + let max_fee_per_gas = match max_fee_per_gas { + Some(max_fee_per_gas) => max_fee_per_gas, + None => { + // fetch pending base fee + let base_fee = self + .block(BlockNumberOrTag::Pending.into()) + .await? + .ok_or(EthApiError::UnknownBlockNumber)? + .base_fee_per_gas + .ok_or_else(|| { + EthApiError::InvalidTransaction( + RpcInvalidTransactionError::TxTypeNotSupported, + ) + })?; + U256::from(base_fee) + } + }; + + let max_priority_fee_per_gas = match max_priority_fee_per_gas { + Some(max_priority_fee_per_gas) => max_priority_fee_per_gas, + None => self.suggested_priority_fee().await?, + }; + Ok((max_fee_per_gas, max_priority_fee_per_gas)) + } + } + + /// Returns the EIP-4844 blob fee if it is set, otherwise fetches a blob fee. + fn eip4844_blob_fee( + &self, + blob_fee: Option, + ) -> impl Future> + Send { + async move { + match blob_fee { + Some(blob_fee) => Ok(blob_fee), + None => self.blob_base_fee().await, + } + } + } + + /// Returns a suggestion for a gas price for legacy transactions. + /// + /// See also: + fn gas_price(&self) -> impl Future> + Send { + let header = self.block(BlockNumberOrTag::Latest.into()); + let suggested_tip = self.suggested_priority_fee(); + async move { + let (header, suggested_tip) = futures::try_join!(header, suggested_tip)?; + let base_fee = header.and_then(|h| h.base_fee_per_gas).unwrap_or_default(); + Ok(suggested_tip + U256::from(base_fee)) + } + } + + /// Returns a suggestion for a base fee for blob transactions. + fn blob_base_fee(&self) -> impl Future> + Send { + async move { + self.block(BlockNumberOrTag::Latest.into()) + .await? + .and_then(|h: reth_primitives::SealedBlock| h.next_block_blob_fee()) + .ok_or(EthApiError::ExcessBlobGasNotSet) + .map(U256::from) + } + } + + /// Returns a suggestion for the priority fee (the tip) + fn suggested_priority_fee(&self) -> impl Future> + Send + where + Self: 'static, + { + self.gas_oracle().suggest_tip_cap() + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/mod.rs b/crates/rpc/rpc-eth-api/src/helpers/mod.rs new file mode 100644 index 000000000000..321e9b03ec5d --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/mod.rs @@ -0,0 +1,47 @@ +//! Behaviour needed to serve `eth_` RPC requests, divided into general database reads and +//! specific database access. +//! +//! Traits with `Load` prefix, read atomic data from database, e.g. a block or transaction. Any +//! database read done in more than one default `Eth` trait implementation, is defined in a `Load` +//! trait. +//! +//! Traits with `Eth` prefix, compose specific data needed to serve RPC requests in the `eth` +//! namespace. They use `Load` traits as building blocks. [`EthTransactions`] also writes data +//! (submits transactions). Based on the `eth_` request method semantics, request methods are +//! divided into: [`EthTransactions`], [`EthBlocks`], [`EthFees`], [`EthState`] and [`EthCall`]. +//! Default implementation of the `Eth` traits, is done w.r.t. L1. +//! +//! [`EthApiServer`](crate::EthApiServer), is implemented for any type that implements +//! all the `Eth` traits, e.g. `reth_rpc::EthApi`. + +pub mod block; +pub mod blocking_task; +pub mod call; +pub mod fee; +pub mod pending_block; +pub mod receipt; +pub mod signer; +pub mod spec; +pub mod state; +pub mod trace; +pub mod transaction; + +pub use block::{EthBlocks, LoadBlock}; +pub use blocking_task::SpawnBlocking; +pub use call::{Call, EthCall}; +pub use fee::{EthFees, LoadFee}; +pub use pending_block::LoadPendingBlock; +pub use receipt::LoadReceipt; +pub use signer::EthSigner; +pub use spec::EthApiSpec; +pub use state::{EthState, LoadState}; +pub use trace::Trace; +pub use transaction::{EthTransactions, LoadTransaction}; + +/// Extension trait that bundles traits needed for tracing transactions. +pub trait TraceExt: + LoadTransaction + LoadBlock + LoadPendingBlock + SpawnBlocking + Trace + Call +{ +} + +impl TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock + Trace + Call {} diff --git a/crates/rpc/rpc/src/eth/api/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs similarity index 52% rename from crates/rpc/rpc/src/eth/api/pending_block.rs rename to crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index 4f9a616dece8..8f3e38817695 100644 --- a/crates/rpc/rpc/src/eth/api/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -1,63 +1,209 @@ -//! Support for building a pending block via local txpool. +//! Loads a pending block from database. Helper trait for `eth_` block, transaction, call and trace +//! RPC methods. -use crate::eth::error::{EthApiError, EthResult}; -use reth_chainspec::ChainSpec; -use reth_errors::ProviderError; +use std::time::{Duration, Instant}; + +use futures::Future; +use reth_chainspec::EthereumHardforks; +use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ constants::{eip4844::MAX_DATA_GAS_PER_BLOCK, BEACON_NONCE, EMPTY_ROOT_HASH}, - proofs, - revm::env::tx_env_with_recovered, + proofs::calculate_transaction_root, revm_primitives::{ - BlockEnv, CfgEnvWithHandlerCfg, EVMError, Env, InvalidTransaction, ResultAndState, SpecId, + BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, EVMError, Env, ExecutionResult, InvalidTransaction, + ResultAndState, SpecId, }, - Block, BlockId, BlockNumberOrTag, Header, IntoRecoveredTransaction, Receipt, Requests, - SealedBlockWithSenders, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256, + Block, BlockNumber, Header, IntoRecoveredTransaction, Receipt, Requests, + SealedBlockWithSenders, SealedHeader, TransactionSignedEcRecovered, B256, + EMPTY_OMMER_ROOT_HASH, U256, +}; +use reth_provider::{ + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, }; -use reth_provider::{ChainSpecProvider, StateProviderFactory}; use reth_revm::{ - database::StateProviderDatabase, - state_change::{ - apply_beacon_root_contract_call, apply_blockhashes_update, - post_block_withdrawals_balance_increments, - }, + database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments, +}; +use reth_rpc_eth_types::{ + pending_block::{pre_block_beacon_root_contract_call, pre_block_blockhashes_update}, + EthApiError, EthResult, PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin, }; use reth_transaction_pool::{BestTransactionsAttributes, TransactionPool}; -use revm::{db::states::bundle_state::BundleRetention, Database, DatabaseCommit, State}; -use revm_primitives::EnvWithHandlerCfg; -use std::time::Instant; - -/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block -#[derive(Debug, Clone)] -pub(crate) struct PendingBlockEnv { - /// Configured [`CfgEnvWithHandlerCfg`] for the pending block. - pub(crate) cfg: CfgEnvWithHandlerCfg, - /// Configured [`BlockEnv`] for the pending block. - pub(crate) block_env: BlockEnv, - /// Origin block for the config - pub(crate) origin: PendingBlockEnvOrigin, -} +use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State}; +use tokio::sync::Mutex; +use tracing::debug; + +use super::SpawnBlocking; + +/// Loads a pending block from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods. +#[auto_impl::auto_impl(&, Arc)] +pub trait LoadPendingBlock { + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider( + &self, + ) -> impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory; + + /// Returns a handle for reading data from transaction pool. + /// + /// Data access in default (L1) trait method implementations. + fn pool(&self) -> impl TransactionPool; + + /// Returns a handle to the pending block. + /// + /// Data access in default (L1) trait method implementations. + fn pending_block(&self) -> &Mutex>; + + /// Returns a handle for reading evm config. + /// + /// Data access in default (L1) trait method implementations. + fn evm_config(&self) -> &impl ConfigureEvm; + + /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block + /// + /// If no pending block is available, this will derive it from the `latest` block + fn pending_block_env_and_cfg(&self) -> EthResult { + let origin: PendingBlockEnvOrigin = if let Some(pending) = + self.provider().pending_block_with_senders()? + { + PendingBlockEnvOrigin::ActualPending(pending) + } else { + // no pending block from the CL yet, so we use the latest block and modify the env + // values that we can + let latest = + self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?; + + let (mut latest_header, block_hash) = latest.split(); + // child block + latest_header.number += 1; + // assumed child block is in the next slot: 12s + latest_header.timestamp += 12; + // base fee of the child block + let chain_spec = self.provider().chain_spec(); + + latest_header.base_fee_per_gas = latest_header.next_block_base_fee( + chain_spec.base_fee_params_at_timestamp(latest_header.timestamp), + ); + + // update excess blob gas consumed above target + latest_header.excess_blob_gas = latest_header.next_block_excess_blob_gas(); + + // we're reusing the same block hash because we need this to lookup the block's state + let latest = SealedHeader::new(latest_header, block_hash); + + PendingBlockEnvOrigin::DerivedFromLatest(latest) + }; + + let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); + + let mut block_env = BlockEnv::default(); + // Note: for the PENDING block we assume it is past the known merge block and thus this will + // not fail when looking up the total difficulty value for the blockenv. + self.provider().fill_env_with_header( + &mut cfg, + &mut block_env, + origin.header(), + self.evm_config().clone(), + )?; + + Ok(PendingBlockEnv::new(cfg, block_env, origin)) + } + + /// Returns the locally built pending block + fn local_pending_block( + &self, + ) -> impl Future>> + Send + where + Self: SpawnBlocking, + { + async move { + let pending = self.pending_block_env_and_cfg()?; + if pending.origin.is_actual_pending() { + return Ok(pending.origin.into_actual_pending()) + } + + let mut lock = self.pending_block().lock().await; + + let now = Instant::now(); + + // check if the block is still good + if let Some(pending_block) = lock.as_ref() { + // this is guaranteed to be the `latest` header + if pending.block_env.number.to::() == pending_block.block.number && + pending.origin.header().hash() == pending_block.block.parent_hash && + now <= pending_block.expires_at + { + return Ok(Some(pending_block.block.clone())) + } + } + + // no pending block from the CL yet, so we need to build it ourselves via txpool + let pending_block = match self + .spawn_blocking_io(move |this| { + // we rebuild the block + this.build_block(pending) + }) + .await + { + Ok(block) => block, + Err(err) => { + debug!(target: "rpc", "Failed to build pending block: {:?}", err); + return Ok(None) + } + }; + + let now = Instant::now(); + *lock = Some(PendingBlock::new(pending_block.clone(), now + Duration::from_secs(1))); + + Ok(Some(pending_block)) + } + } -impl PendingBlockEnv { - /// Builds a pending block using the given client and pool. + /// Assembles a [`Receipt`] for a transaction, based on its [`ExecutionResult`]. + fn assemble_receipt( + &self, + tx: &TransactionSignedEcRecovered, + result: ExecutionResult, + cumulative_gas_used: u64, + ) -> Receipt { + Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + #[cfg(feature = "optimism")] + deposit_nonce: None, + #[cfg(feature = "optimism")] + deposit_receipt_version: None, + } + } + + /// Calculates receipts root in block building. + /// + /// Panics if block is not in the [`ExecutionOutcome`]'s block range. + fn receipts_root( + &self, + _block_env: &BlockEnv, + execution_outcome: &ExecutionOutcome, + block_number: BlockNumber, + ) -> B256 { + execution_outcome.receipts_root_slow(block_number).expect("Block is present") + } + + /// Builds a pending block using the configured provider and pool. /// /// If the origin is the actual pending block, the block is built with withdrawals. /// /// After Cancun, if the origin is the actual pending block, the block includes the EIP-4788 pre /// block contract call using the parent beacon block root received from the CL. - pub(crate) fn build_block( - self, - client: &Client, - pool: &Pool, - ) -> EthResult - where - Client: StateProviderFactory + ChainSpecProvider, - Pool: TransactionPool, - { - let Self { cfg, block_env, origin } = self; + fn build_block(&self, env: PendingBlockEnv) -> EthResult { + let PendingBlockEnv { cfg, block_env, origin } = env; let parent_hash = origin.build_target_hash(); - let state_provider = client.history_by_block_hash(parent_hash)?; + let state_provider = self.provider().history_by_block_hash(parent_hash)?; let state = StateProviderDatabase::new(state_provider); let mut db = State::builder().with_database(state).with_bundle_update().build(); @@ -69,10 +215,11 @@ impl PendingBlockEnv { let mut executed_txs = Vec::new(); let mut senders = Vec::new(); - let mut best_txs = pool.best_transactions_with_attributes(BestTransactionsAttributes::new( - base_fee, - block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), - )); + let mut best_txs = + self.pool().best_transactions_with_attributes(BestTransactionsAttributes::new( + base_fee, + block_env.get_blob_gasprice().map(|gasprice| gasprice as u64), + )); let (withdrawals, withdrawals_root) = match origin { PendingBlockEnvOrigin::ActualPending(ref block) => { @@ -81,7 +228,7 @@ impl PendingBlockEnv { PendingBlockEnvOrigin::DerivedFromLatest(_) => (None, None), }; - let chain_spec = client.chain_spec(); + let chain_spec = self.provider().chain_spec(); let parent_beacon_block_root = if origin.is_actual_pending() { // apply eip-4788 pre block contract call if we got the block from the CL with the real @@ -144,8 +291,11 @@ impl PendingBlockEnv { } // Configure the environment for the block. - let env = - Env::boxed(cfg.cfg_env.clone(), block_env.clone(), tx_env_with_recovered(&tx)); + let env = Env::boxed( + cfg.cfg_env.clone(), + block_env.clone(), + Self::evm_config(self).tx_env(&tx), + ); let mut evm = revm::Evm::builder().with_env(env).with_db(&mut db).build(); @@ -192,16 +342,7 @@ impl PendingBlockEnv { cumulative_gas_used += gas_used; // Push transaction changeset and calculate header bloom filter for receipt. - receipts.push(Some(Receipt { - tx_type: tx.tx_type(), - success: result.is_success(), - cumulative_gas_used, - logs: result.into_logs().into_iter().map(Into::into).collect(), - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - })); + receipts.push(Some(self.assemble_receipt(&tx, result, cumulative_gas_used))); // append transaction to the list of executed transactions let (tx, sender) = tx.to_components(); @@ -229,18 +370,7 @@ impl PendingBlockEnv { Vec::new(), ); - #[cfg(feature = "optimism")] - let receipts_root = execution_outcome - .optimism_receipts_root_slow( - block_number, - chain_spec.as_ref(), - block_env.timestamp.to::(), - ) - .expect("Block is present"); - - #[cfg(not(feature = "optimism"))] - let receipts_root = - execution_outcome.receipts_root_slow(block_number).expect("Block is present"); + let receipts_root = self.receipts_root(&block_env, &execution_outcome, block_number); let logs_bloom = execution_outcome.block_logs_bloom(block_number).expect("Block is present"); @@ -250,7 +380,7 @@ impl PendingBlockEnv { let state_root = state_provider.state_root(execution_outcome.state())?; // create the block header - let transactions_root = proofs::calculate_transaction_root(&executed_txs); + let transactions_root = calculate_transaction_root(&executed_txs); // check if cancun is activated to set eip4844 header fields correctly let blob_gas_used = @@ -294,137 +424,3 @@ impl PendingBlockEnv { Ok(SealedBlockWithSenders { block: block.seal_slow(), senders }) } } - -/// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call. -/// -/// This constructs a new [Evm](revm::Evm) with the given DB, and environment -/// [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] to execute the pre block contract call. -/// -/// This uses [`apply_beacon_root_contract_call`] to ultimately apply the beacon root contract state -/// change. -fn pre_block_beacon_root_contract_call( - db: &mut DB, - chain_spec: &ChainSpec, - block_number: u64, - initialized_cfg: &CfgEnvWithHandlerCfg, - initialized_block_env: &BlockEnv, - parent_beacon_block_root: Option, -) -> EthResult<()> -where - DB::Error: std::fmt::Display, -{ - // apply pre-block EIP-4788 contract call - let mut evm_pre_block = revm::Evm::builder() - .with_db(db) - .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( - initialized_cfg.clone(), - initialized_block_env.clone(), - Default::default(), - )) - .build(); - - // initialize a block from the env, because the pre block call needs the block itself - apply_beacon_root_contract_call( - chain_spec, - initialized_block_env.timestamp.to::(), - block_number, - parent_beacon_block_root, - &mut evm_pre_block, - ) - .map_err(|err| EthApiError::Internal(err.into())) -} - -/// Apply the [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) pre block state transitions. -/// -/// This constructs a new [Evm](revm::Evm) with the given DB, and environment -/// [`CfgEnvWithHandlerCfg`] and [`BlockEnv`]. -/// -/// This uses [`apply_blockhashes_update`]. -fn pre_block_blockhashes_update + DatabaseCommit>( - db: &mut DB, - chain_spec: &ChainSpec, - initialized_block_env: &BlockEnv, - block_number: u64, - parent_block_hash: B256, -) -> EthResult<()> -where - DB::Error: std::fmt::Display, -{ - apply_blockhashes_update( - db, - chain_spec, - initialized_block_env.timestamp.to::(), - block_number, - parent_block_hash, - ) - .map_err(|err| EthApiError::Internal(err.into())) -} - -/// The origin for a configured [`PendingBlockEnv`] -#[derive(Clone, Debug)] -pub(crate) enum PendingBlockEnvOrigin { - /// The pending block as received from the CL. - ActualPending(SealedBlockWithSenders), - /// The _modified_ header of the latest block. - /// - /// This derives the pending state based on the latest header by modifying: - /// - the timestamp - /// - the block number - /// - fees - DerivedFromLatest(SealedHeader), -} - -impl PendingBlockEnvOrigin { - /// Returns true if the origin is the actual pending block as received from the CL. - pub(crate) const fn is_actual_pending(&self) -> bool { - matches!(self, Self::ActualPending(_)) - } - - /// Consumes the type and returns the actual pending block. - pub(crate) fn into_actual_pending(self) -> Option { - match self { - Self::ActualPending(block) => Some(block), - _ => None, - } - } - - /// Returns the [`BlockId`] that represents the state of the block. - /// - /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely - /// identify the block by its hash (latest block). - pub(crate) fn state_block_id(&self) -> BlockId { - match self { - Self::ActualPending(_) => BlockNumberOrTag::Pending.into(), - Self::DerivedFromLatest(header) => BlockId::Hash(header.hash().into()), - } - } - - /// Returns the hash of the block the pending block should be built on. - /// - /// For the [`PendingBlockEnvOrigin::ActualPending`] this is the parent hash of the block. - /// For the [`PendingBlockEnvOrigin::DerivedFromLatest`] this is the hash of the _latest_ - /// header. - fn build_target_hash(&self) -> B256 { - match self { - Self::ActualPending(block) => block.parent_hash, - Self::DerivedFromLatest(header) => header.hash(), - } - } - - /// Returns the header this pending block is based on. - pub(crate) fn header(&self) -> &SealedHeader { - match self { - Self::ActualPending(block) => &block.header, - Self::DerivedFromLatest(header) => header, - } - } -} - -/// In memory pending block for `pending` tag -#[derive(Debug)] -pub(crate) struct PendingBlock { - /// The cached pending block - pub(crate) block: SealedBlockWithSenders, - /// Timestamp when the pending block is considered outdated - pub(crate) expires_at: Instant, -} diff --git a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs new file mode 100644 index 000000000000..5cd6c03c4d9f --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs @@ -0,0 +1,36 @@ +//! Loads a receipt from database. Helper trait for `eth_` block and transaction RPC methods, that +//! loads receipt data w.r.t. network. + +use futures::Future; +use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; +use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder}; +use reth_rpc_types::AnyTransactionReceipt; + +/// Assembles transaction receipt data w.r.t to network. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` receipts RPC methods. +#[auto_impl::auto_impl(&, Arc)] +pub trait LoadReceipt: Send + Sync { + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Helper method for `eth_getBlockReceipts` and `eth_getTransactionReceipt`. + fn build_transaction_receipt( + &self, + tx: TransactionSigned, + meta: TransactionMeta, + receipt: Receipt, + ) -> impl Future> + Send { + async move { + // get all receipts for the block + let all_receipts = match self.cache().get_receipts(meta.block_hash).await? { + Some(recpts) => recpts, + None => return Err(EthApiError::UnknownBlockNumber), + }; + + Ok(ReceiptBuilder::new(&tx, meta, &receipt, &all_receipts)?.build()) + } + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/signer.rs b/crates/rpc/rpc-eth-api/src/helpers/signer.rs new file mode 100644 index 000000000000..2a75d9abb02e --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/signer.rs @@ -0,0 +1,39 @@ +//! An abstraction over ethereum signers. + +use std::result; + +use alloy_dyn_abi::TypedData; +use dyn_clone::DynClone; +use reth_primitives::{Address, Signature, TransactionSigned}; +use reth_rpc_eth_types::SignError; +use reth_rpc_types::TypedTransactionRequest; + +/// Result returned by [`EthSigner`] methods. +pub type Result = result::Result; + +/// An Ethereum Signer used via RPC. +#[async_trait::async_trait] +pub trait EthSigner: Send + Sync + DynClone { + /// Returns the available accounts for this signer. + fn accounts(&self) -> Vec
; + + /// Returns `true` whether this signer can sign for this address + fn is_signer_for(&self, addr: &Address) -> bool { + self.accounts().contains(addr) + } + + /// Returns the signature + async fn sign(&self, address: Address, message: &[u8]) -> Result; + + /// signs a transaction request using the given account in request + fn sign_transaction( + &self, + request: TypedTransactionRequest, + address: &Address, + ) -> Result; + + /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. + fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result; +} + +dyn_clone::clone_trait_object!(EthSigner); diff --git a/crates/rpc/rpc-eth-api/src/helpers/spec.rs b/crates/rpc/rpc-eth-api/src/helpers/spec.rs new file mode 100644 index 000000000000..63722e376e64 --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/spec.rs @@ -0,0 +1,31 @@ +//! Loads chain metadata. + +use futures::Future; +use reth_chainspec::ChainInfo; +use reth_errors::RethResult; +use reth_primitives::{Address, U64}; +use reth_rpc_types::SyncStatus; + +/// `Eth` API trait. +/// +/// Defines core functionality of the `eth` API implementation. +#[auto_impl::auto_impl(&, Arc)] +pub trait EthApiSpec: Send + Sync { + /// Returns the current ethereum protocol version. + fn protocol_version(&self) -> impl Future> + Send; + + /// Returns the chain id + fn chain_id(&self) -> U64; + + /// Returns provider chain info + fn chain_info(&self) -> RethResult; + + /// Returns a list of addresses owned by provider. + fn accounts(&self) -> Vec
; + + /// Returns `true` if the network is undergoing sync. + fn is_syncing(&self) -> bool; + + /// Returns the [`SyncStatus`] of the network + fn sync_status(&self) -> RethResult; +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs new file mode 100644 index 000000000000..80859b929b7b --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -0,0 +1,247 @@ +//! Loads a pending block from database. Helper trait for `eth_` block, transaction, call and trace +//! RPC methods. + +use futures::Future; +use reth_primitives::{ + revm::env::fill_block_env_with_coinbase, Address, BlockId, BlockNumberOrTag, Bytes, Header, + B256, U256, +}; +use reth_provider::{BlockIdReader, StateProvider, StateProviderBox, StateProviderFactory}; +use reth_rpc_eth_types::{ + EthApiError, EthResult, EthStateCache, PendingBlockEnv, RpcInvalidTransactionError, +}; +use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; +use reth_rpc_types_compat::proof::from_primitive_account_proof; +use reth_transaction_pool::{PoolTransaction, TransactionPool}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId}; + +use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking}; + +/// Helper methods for `eth_` methods relating to state (accounts). +pub trait EthState: LoadState + SpawnBlocking { + /// Returns the number of transactions sent from an address at the given block identifier. + /// + /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will + /// look up the highest transaction in pool and return the next nonce (highest + 1). + fn transaction_count( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + LoadState::transaction_count(self, address, block_id) + } + + /// Returns code of given account, at given blocknumber. + fn get_code( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(this + .state_at_block_id_or_latest(block_id)? + .account_code(address)? + .unwrap_or_default() + .original_bytes()) + }) + } + + /// Returns balance of given account, at given blocknumber. + fn balance( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(this + .state_at_block_id_or_latest(block_id)? + .account_balance(address)? + .unwrap_or_default()) + }) + } + + /// Returns values stored of given account, at given blocknumber. + fn storage_at( + &self, + address: Address, + index: JsonStorageKey, + block_id: Option, + ) -> impl Future> + Send { + self.spawn_blocking_io(move |this| { + Ok(B256::new( + this.state_at_block_id_or_latest(block_id)? + .storage(address, index.0)? + .unwrap_or_default() + .to_be_bytes(), + )) + }) + } + + /// Returns values stored of given account, with Merkle-proof, at given blocknumber. + fn get_proof( + &self, + address: Address, + keys: Vec, + block_id: Option, + ) -> EthResult> + Send> + where + Self: EthApiSpec, + { + let chain_info = self.chain_info()?; + let block_id = block_id.unwrap_or_default(); + + // if we are trying to create a proof for the latest block, but have a BlockId as input + // that is not BlockNumberOrTag::Latest, then we need to figure out whether or not the + // BlockId corresponds to the latest block + let is_latest_block = match block_id { + BlockId::Number(BlockNumberOrTag::Number(num)) => num == chain_info.best_number, + BlockId::Hash(hash) => hash == chain_info.best_hash.into(), + BlockId::Number(BlockNumberOrTag::Latest) => true, + _ => false, + }; + + // TODO: remove when HistoricalStateProviderRef::proof is implemented + if !is_latest_block { + return Err(EthApiError::InvalidBlockRange) + } + + Ok(self.spawn_tracing(move |this| { + let state = this.state_at_block_id(block_id)?; + let storage_keys = keys.iter().map(|key| key.0).collect::>(); + let proof = state.proof(address, &storage_keys)?; + Ok(from_primitive_account_proof(proof)) + })) + } +} + +/// Loads state from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` state RPC methods. +pub trait LoadState { + /// Returns a handle for reading state from database. + /// + /// Data access in default trait method implementations. + fn provider(&self) -> impl StateProviderFactory; + + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Returns a handle for reading data from transaction pool. + /// + /// Data access in default trait method implementations. + fn pool(&self) -> impl TransactionPool; + + /// Returns the state at the given block number + fn state_at_hash(&self, block_hash: B256) -> EthResult { + Ok(self.provider().history_by_block_hash(block_hash)?) + } + + /// Returns the state at the given [`BlockId`] enum. + /// + /// Note: if not [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this + /// will only return canonical state. See also + fn state_at_block_id(&self, at: BlockId) -> EthResult { + Ok(self.provider().state_by_block_id(at)?) + } + + /// Returns the _latest_ state + fn latest_state(&self) -> EthResult { + Ok(self.provider().latest()?) + } + + /// Returns the state at the given [`BlockId`] enum or the latest. + /// + /// Convenience function to interprets `None` as `BlockId::Number(BlockNumberOrTag::Latest)` + fn state_at_block_id_or_latest( + &self, + block_id: Option, + ) -> EthResult { + if let Some(block_id) = block_id { + self.state_at_block_id(block_id) + } else { + Ok(self.latest_state()?) + } + } + + /// Returns the revm evm env for the requested [`BlockId`] + /// + /// If the [`BlockId`] this will return the [`BlockId`] of the block the env was configured + /// for. + /// If the [`BlockId`] is pending, this will return the "Pending" tag, otherwise this returns + /// the hash of the exact block. + fn evm_env_at( + &self, + at: BlockId, + ) -> impl Future> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { + if at.is_pending() { + let PendingBlockEnv { cfg, block_env, origin } = + self.pending_block_env_and_cfg()?; + Ok((cfg, block_env, origin.state_block_id())) + } else { + // Use cached values if there is no pending block + let block_hash = LoadPendingBlock::provider(self) + .block_hash_for_id(at)? + .ok_or_else(|| EthApiError::UnknownBlockNumber)?; + let (cfg, env) = self.cache().get_evm_env(block_hash).await?; + Ok((cfg, env, block_hash.into())) + } + } + } + + /// Returns the revm evm env for the raw block header + /// + /// This is used for tracing raw blocks + fn evm_env_for_raw_block( + &self, + header: &Header, + ) -> impl Future> + Send + where + Self: LoadPendingBlock + SpawnBlocking, + { + async move { + // get the parent config first + let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; + + let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; + fill_block_env_with_coinbase(&mut block_env, header, after_merge, header.beneficiary); + + Ok((cfg, block_env)) + } + } + + /// Returns the number of transactions sent from an address at the given block identifier. + /// + /// If this is [`BlockNumberOrTag::Pending`](reth_primitives::BlockNumberOrTag) then this will + /// look up the highest transaction in pool and return the next nonce (highest + 1). + fn transaction_count( + &self, + address: Address, + block_id: Option, + ) -> impl Future> + Send + where + Self: SpawnBlocking, + { + self.spawn_blocking_io(move |this| { + if block_id == Some(BlockId::pending()) { + let address_txs = this.pool().get_transactions_by_sender(address); + if let Some(highest_nonce) = + address_txs.iter().map(|item| item.transaction.nonce()).max() + { + let tx_count = highest_nonce + .checked_add(1) + .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; + return Ok(U256::from(tx_count)) + } + } + + let state = this.state_at_block_id_or_latest(block_id)?; + Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) + }) + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs new file mode 100644 index 000000000000..d48e566ed51d --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -0,0 +1,415 @@ +//! Loads a pending block from database. Helper trait for `eth_` call and trace RPC methods. + +use futures::Future; +use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; +use reth_primitives::B256; +use reth_revm::database::StateProviderDatabase; +use reth_rpc_eth_types::{ + cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper}, + EthApiError, EthResult, +}; +use reth_rpc_types::{BlockId, TransactionInfo}; +use revm::{db::CacheDB, Database, DatabaseCommit, GetInspector, Inspector}; +use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; +use revm_primitives::{EnvWithHandlerCfg, EvmState, ExecutionResult, ResultAndState}; + +use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction}; + +/// Executes CPU heavy tasks. +pub trait Trace: LoadState { + /// Returns a handle for reading evm config. + /// + /// Data access in default (L1) trait method implementations. + fn evm_config(&self) -> &impl ConfigureEvm; + + /// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state + /// changes. + fn inspect( + &self, + db: DB, + env: EnvWithHandlerCfg, + inspector: I, + ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> + where + DB: Database, + ::Error: Into, + I: GetInspector, + { + self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env)) + } + + /// Same as [`inspect`](Self::inspect) but also returns the database again. + /// + /// Even though [Database] is also implemented on `&mut` + /// this is still useful if there are certain trait bounds on the Inspector's database generic + /// type + fn inspect_and_return_db( + &self, + db: DB, + env: EnvWithHandlerCfg, + inspector: I, + ) -> EthResult<(ResultAndState, EnvWithHandlerCfg, DB)> + where + DB: Database, + ::Error: Into, + I: GetInspector, + { + let mut evm = self.evm_config().evm_with_env_and_inspector(db, env, inspector); + let res = evm.transact()?; + let (db, env) = evm.into_db_and_env_with_handler_cfg(); + Ok((res, env, db)) + } + + /// Executes the transaction on top of the given [`BlockId`] with a tracer configured by the + /// config. + /// + /// The callback is then called with the [`TracingInspector`] and the [`ResultAndState`] after + /// the configured [`EnvWithHandlerCfg`] was inspected. + /// + /// Caution: this is blocking + fn trace_at( + &self, + env: EnvWithHandlerCfg, + config: TracingInspectorConfig, + at: BlockId, + f: F, + ) -> EthResult + where + Self: Call, + F: FnOnce(TracingInspector, ResultAndState) -> EthResult, + { + self.with_state_at_block(at, |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut inspector = TracingInspector::new(config); + let (res, _) = self.inspect(&mut db, env, &mut inspector)?; + f(inspector, res) + }) + } + + /// Same as [`trace_at`](Self::trace_at) but also provides the used database to the callback. + /// + /// Executes the transaction on top of the given [`BlockId`] with a tracer configured by the + /// config. + /// + /// The callback is then called with the [`TracingInspector`] and the [`ResultAndState`] after + /// the configured [`EnvWithHandlerCfg`] was inspected. + fn spawn_trace_at_with_state( + &self, + env: EnvWithHandlerCfg, + config: TracingInspectorConfig, + at: BlockId, + f: F, + ) -> impl Future> + Send + where + Self: LoadPendingBlock + Call, + F: FnOnce(TracingInspector, ResultAndState, StateCacheDb<'_>) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + let this = self.clone(); + self.spawn_with_state_at_block(at, move |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + let mut inspector = TracingInspector::new(config); + let (res, _) = this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?; + f(inspector, res, db) + }) + } + + /// Retrieves the transaction if it exists and returns its trace. + /// + /// Before the transaction is traced, all previous transaction in the block are applied to the + /// state by executing them first. + /// The callback `f` is invoked with the [`ResultAndState`] after the transaction was executed + /// and the database that points to the beginning of the transaction. + /// + /// Note: Implementers should use a threadpool where blocking is allowed, such as + /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool). + fn spawn_trace_transaction_in_block( + &self, + hash: B256, + config: TracingInspectorConfig, + f: F, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + LoadTransaction + Call, + F: FnOnce( + TransactionInfo, + TracingInspector, + ResultAndState, + StateCacheDb<'_>, + ) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + self.spawn_trace_transaction_in_block_with_inspector(hash, TracingInspector::new(config), f) + } + + /// Retrieves the transaction if it exists and returns its trace. + /// + /// Before the transaction is traced, all previous transaction in the block are applied to the + /// state by executing them first. + /// The callback `f` is invoked with the [`ResultAndState`] after the transaction was executed + /// and the database that points to the beginning of the transaction. + /// + /// Note: Implementers should use a threadpool where blocking is allowed, such as + /// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool). + fn spawn_trace_transaction_in_block_with_inspector( + &self, + hash: B256, + mut inspector: Insp, + f: F, + ) -> impl Future>> + Send + where + Self: LoadPendingBlock + LoadTransaction + Call, + F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDb<'_>) -> EthResult + + Send + + 'static, + Insp: for<'a, 'b> Inspector> + Send + 'static, + R: Send + 'static, + { + async move { + let (transaction, block) = match self.transaction_and_block(hash).await? { + None => return Ok(None), + Some(res) => res, + }; + let (tx, tx_info) = transaction.split(); + + let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?; + + // we need to get the state of the parent block because we're essentially replaying the + // block the transaction is included in + let parent_block = block.parent_hash; + let block_txs = block.into_transactions_ecrecovered(); + + let this = self.clone(); + self.spawn_with_state_at_block(parent_block.into(), move |state| { + let mut db = CacheDB::new(StateProviderDatabase::new(state)); + + // replay all transactions prior to the targeted transaction + this.replay_transactions_until( + &mut db, + cfg.clone(), + block_env.clone(), + block_txs, + tx.hash, + )?; + + let env = EnvWithHandlerCfg::new_with_cfg_env( + cfg, + block_env, + Call::evm_config(&this).tx_env(&tx), + ); + let (res, _) = + this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?; + f(tx_info, inspector, res, db) + }) + .await + .map(Some) + } + } + + /// Executes all transactions of a block up to a given index. + /// + /// If a `highest_index` is given, this will only execute the first `highest_index` + /// transactions, in other words, it will stop executing transactions after the + /// `highest_index`th transaction. If `highest_index` is `None`, all transactions + /// are executed. + fn trace_block_until( + &self, + block_id: BlockId, + highest_index: Option, + config: TracingInspectorConfig, + f: F, + ) -> impl Future>>> + Send + where + Self: LoadBlock, + F: Fn( + TransactionInfo, + TracingInspector, + ExecutionResult, + &EvmState, + &StateCacheDb<'_>, + ) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + self.trace_block_until_with_inspector( + block_id, + highest_index, + move || TracingInspector::new(config), + f, + ) + } + + /// Executes all transactions of a block. + /// + /// If a `highest_index` is given, this will only execute the first `highest_index` + /// transactions, in other words, it will stop executing transactions after the + /// `highest_index`th transaction. + /// + /// Note: This expect tx index to be 0-indexed, so the first transaction is at index 0. + /// + /// This accepts a `inspector_setup` closure that returns the inspector to be used for tracing + /// the transactions. + fn trace_block_until_with_inspector( + &self, + block_id: BlockId, + highest_index: Option, + mut inspector_setup: Setup, + f: F, + ) -> impl Future>>> + Send + where + Self: LoadBlock, + F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDb<'_>) -> EthResult + + Send + + 'static, + Setup: FnMut() -> Insp + Send + 'static, + Insp: for<'a, 'b> Inspector> + Send + 'static, + R: Send + 'static, + { + async move { + let ((cfg, block_env, _), block) = + futures::try_join!(self.evm_env_at(block_id), self.block_with_senders(block_id))?; + + let Some(block) = block else { return Ok(None) }; + + if block.body.is_empty() { + // nothing to trace + return Ok(Some(Vec::new())) + } + + // replay all transactions of the block + self.spawn_tracing(move |this| { + // we need to get the state of the parent block because we're replaying this block + // on top of its parent block's state + let state_at = block.parent_hash; + let block_hash = block.hash(); + + let block_number = block_env.number.saturating_to::(); + let base_fee = block_env.basefee.saturating_to::(); + + // prepare transactions, we do everything upfront to reduce time spent with open + // state + let max_transactions = highest_index.map_or(block.body.len(), |highest| { + // we need + 1 because the index is 0-based + highest as usize + 1 + }); + let mut results = Vec::with_capacity(max_transactions); + + let mut transactions = block + .into_transactions_ecrecovered() + .take(max_transactions) + .enumerate() + .map(|(idx, tx)| { + let tx_info = TransactionInfo { + hash: Some(tx.hash()), + index: Some(idx as u64), + block_hash: Some(block_hash), + block_number: Some(block_number), + base_fee: Some(base_fee), + }; + let tx_env = Trace::evm_config(&this).tx_env(&tx); + (tx_info, tx_env) + }) + .peekable(); + + // now get the state + let state = this.state_at_block_id(state_at.into())?; + let mut db = + CacheDB::new(StateProviderDatabase::new(StateProviderTraitObjWrapper(&state))); + + while let Some((tx_info, tx)) = transactions.next() { + let env = + EnvWithHandlerCfg::new_with_cfg_env(cfg.clone(), block_env.clone(), tx); + + let mut inspector = inspector_setup(); + let (res, _) = + this.inspect(StateCacheDbRefMutWrapper(&mut db), env, &mut inspector)?; + let ResultAndState { result, state } = res; + results.push(f(tx_info, inspector, result, &state, &db)?); + + // need to apply the state changes of this transaction before executing the + // next transaction, but only if there's a next transaction + if transactions.peek().is_some() { + // commit the state changes to the DB + db.commit(state) + } + } + + Ok(Some(results)) + }) + .await + } + } + + /// Executes all transactions of a block and returns a list of callback results invoked for each + /// transaction in the block. + /// + /// This + /// 1. fetches all transactions of the block + /// 2. configures the EVM evn + /// 3. loops over all transactions and executes them + /// 4. calls the callback with the transaction info, the execution result, the changed state + /// _after_ the transaction [`StateProviderDatabase`] and the database that points to the + /// state right _before_ the transaction. + fn trace_block_with( + &self, + block_id: BlockId, + config: TracingInspectorConfig, + f: F, + ) -> impl Future>>> + Send + where + Self: LoadBlock, + // This is the callback that's invoked for each transaction with the inspector, the result, + // state and db + F: Fn( + TransactionInfo, + TracingInspector, + ExecutionResult, + &EvmState, + &StateCacheDb<'_>, + ) -> EthResult + + Send + + 'static, + R: Send + 'static, + { + self.trace_block_until(block_id, None, config, f) + } + + /// Executes all transactions of a block and returns a list of callback results invoked for each + /// transaction in the block. + /// + /// This + /// 1. fetches all transactions of the block + /// 2. configures the EVM evn + /// 3. loops over all transactions and executes them + /// 4. calls the callback with the transaction info, the execution result, the changed state + /// _after_ the transaction [`EvmState`] and the database that points to the state right + /// _before_ the transaction, in other words the state the transaction was executed on: + /// `changed_state = tx(cached_state)` + /// + /// This accepts a `inspector_setup` closure that returns the inspector to be used for tracing + /// a transaction. This is invoked for each transaction. + fn trace_block_inspector( + &self, + block_id: BlockId, + insp_setup: Setup, + f: F, + ) -> impl Future>>> + Send + where + Self: LoadBlock, + // This is the callback that's invoked for each transaction with the inspector, the result, + // state and db + F: Fn(TransactionInfo, Insp, ExecutionResult, &EvmState, &StateCacheDb<'_>) -> EthResult + + Send + + 'static, + Setup: FnMut() -> Insp + Send + 'static, + Insp: for<'a, 'b> Inspector> + Send + 'static, + R: Send + 'static, + { + self.trace_block_until_with_inspector(block_id, None, insp_setup, f) + } +} diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs new file mode 100644 index 000000000000..acf0156c6d9f --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -0,0 +1,650 @@ +//! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. +//! network. + +use std::{fmt, sync::Arc}; + +use alloy_dyn_abi::TypedData; +use futures::Future; +use reth_primitives::{ + Address, BlockId, Bytes, FromRecoveredPooledTransaction, IntoRecoveredTransaction, Receipt, + SealedBlockWithSenders, TransactionMeta, TransactionSigned, TxHash, TxKind, B256, U256, +}; +use reth_provider::{BlockReaderIdExt, ReceiptProvider, TransactionsProvider}; +use reth_rpc_eth_types::{ + utils::recover_raw_transaction, EthApiError, EthResult, EthStateCache, SignError, + TransactionSource, +}; +use reth_rpc_types::{ + transaction::{ + EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest, + LegacyTransactionRequest, + }, + AnyTransactionReceipt, Index, Transaction, TransactionRequest, TypedTransactionRequest, +}; +use reth_rpc_types_compat::transaction::from_recovered_with_block_context; +use reth_transaction_pool::{TransactionOrigin, TransactionPool}; + +use super::EthSigner; + +use super::{Call, EthApiSpec, LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, SpawnBlocking}; + +/// Transaction related functions for the [`EthApiServer`](crate::EthApiServer) trait in +/// the `eth_` namespace. +/// +/// This includes utilities for transaction tracing, transacting and inspection. +/// +/// Async functions that are spawned onto the +/// [`BlockingTaskPool`](reth_tasks::pool::BlockingTaskPool) begin with `spawn_` +/// +/// ## Calls +/// +/// There are subtle differences between when transacting [`TransactionRequest`]: +/// +/// The endpoints `eth_call` and `eth_estimateGas` and `eth_createAccessList` should always +/// __disable__ the base fee check in the +/// [`EnvWithHandlerCfg`](revm_primitives::CfgEnvWithHandlerCfg). +/// +/// The behaviour for tracing endpoints is not consistent across clients. +/// Geth also disables the basefee check for tracing: +/// Erigon does not: +/// +/// See also +/// +/// This implementation follows the behaviour of Geth and disables the basefee check for tracing. +pub trait EthTransactions: LoadTransaction { + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl BlockReaderIdExt; + + /// Returns a handle for forwarding received raw transactions. + /// + /// Access to transaction forwarder in default (L1) trait method implementations. + fn raw_tx_forwarder(&self) -> Option>; + + /// Returns a handle for signing data. + /// + /// Singer access in default (L1) trait method implementations. + fn signers(&self) -> &parking_lot::RwLock>>; + + /// Returns the transaction by hash. + /// + /// Checks the pool and state. + /// + /// Returns `Ok(None)` if no matching transaction was found. + fn transaction_by_hash( + &self, + hash: B256, + ) -> impl Future>> + Send { + LoadTransaction::transaction_by_hash(self, hash) + } + + /// Get all transactions in the block with the given hash. + /// + /// Returns `None` if block does not exist. + fn transactions_by_block( + &self, + block: B256, + ) -> impl Future>>> + Send { + async move { Ok(self.cache().get_block_transactions(block).await?) } + } + + /// Returns the EIP-2718 encoded transaction by hash. + /// + /// If this is a pooled EIP-4844 transaction, the blob sidecar is included. + /// + /// Checks the pool and state. + /// + /// Returns `Ok(None)` if no matching transaction was found. + fn raw_transaction_by_hash( + &self, + hash: B256, + ) -> impl Future>> + Send { + async move { + // Note: this is mostly used to fetch pooled transactions so we check the pool first + if let Some(tx) = + self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded()) + { + return Ok(Some(tx)) + } + + self.spawn_blocking_io(move |ref this| { + Ok(LoadTransaction::provider(this) + .transaction_by_hash(hash)? + .map(|tx| tx.envelope_encoded())) + }) + .await + } + } + + /// Returns the _historical_ transaction and the block it was mined in + fn historical_transaction_by_hash_at( + &self, + hash: B256, + ) -> impl Future>> + Send { + async move { + match self.transaction_by_hash_at(hash).await? { + None => Ok(None), + Some((tx, at)) => Ok(at.as_block_hash().map(|hash| (tx, hash))), + } + } + } + + /// Returns the transaction receipt for the given hash. + /// + /// Returns None if the transaction does not exist or is pending + /// Note: The tx receipt is not available for pending transactions. + fn transaction_receipt( + &self, + hash: B256, + ) -> impl Future>> + Send + where + Self: LoadReceipt + 'static, + { + async move { + let result = self.load_transaction_and_receipt(hash).await?; + + let (tx, meta, receipt) = match result { + Some((tx, meta, receipt)) => (tx, meta, receipt), + None => return Ok(None), + }; + + self.build_transaction_receipt(tx, meta, receipt).await.map(Some) + } + } + + /// Helper method that loads a transaction and its receipt. + fn load_transaction_and_receipt( + &self, + hash: TxHash, + ) -> impl Future>> + Send + where + Self: 'static, + { + let this = self.clone(); + self.spawn_blocking_io(move |_| { + let (tx, meta) = + match LoadTransaction::provider(&this).transaction_by_hash_with_meta(hash)? { + Some((tx, meta)) => (tx, meta), + None => return Ok(None), + }; + + let receipt = match EthTransactions::provider(&this).receipt_by_hash(hash)? { + Some(recpt) => recpt, + None => return Ok(None), + }; + + Ok(Some((tx, meta, receipt))) + }) + } + + /// Get [`Transaction`] by [`BlockId`] and index of transaction within that block. + /// + /// Returns `Ok(None)` if the block does not exist, or index is out of range. + fn transaction_by_block_and_tx_index( + &self, + block_id: BlockId, + index: Index, + ) -> impl Future>> + Send + where + Self: LoadBlock, + { + async move { + if let Some(block) = self.block_with_senders(block_id).await? { + let block_hash = block.hash(); + let block_number = block.number; + let base_fee_per_gas = block.base_fee_per_gas; + if let Some(tx) = block.into_transactions_ecrecovered().nth(index.into()) { + return Ok(Some(from_recovered_with_block_context( + tx, + block_hash, + block_number, + base_fee_per_gas, + index.into(), + ))) + } + } + + Ok(None) + } + } + + /// Get transaction, as raw bytes, by [`BlockId`] and index of transaction within that block. + /// + /// Returns `Ok(None)` if the block does not exist, or index is out of range. + fn raw_transaction_by_block_and_tx_index( + &self, + block_id: BlockId, + index: Index, + ) -> impl Future>> + Send + where + Self: LoadBlock, + { + async move { + if let Some(block) = self.block_with_senders(block_id).await? { + if let Some(tx) = block.transactions().nth(index.into()) { + return Ok(Some(tx.envelope_encoded())) + } + } + + Ok(None) + } + } + + /// Decodes and recovers the transaction and submits it to the pool. + /// + /// Returns the hash of the transaction. + fn send_raw_transaction(&self, tx: Bytes) -> impl Future> + Send { + async move { + // On optimism, transactions are forwarded directly to the sequencer to be included in + // blocks that it builds. + if let Some(client) = self.raw_tx_forwarder().as_ref() { + tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); + client.forward_raw_transaction(&tx).await?; + } + + let recovered = recover_raw_transaction(tx)?; + let pool_transaction = + ::Transaction::from_recovered_pooled_transaction( + recovered, + ); + + // submit the transaction to the pool with a `Local` origin + let hash = + self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; + + Ok(hash) + } + } + + /// Signs transaction with a matching signer, if any and submits the transaction to the pool. + /// Returns the hash of the signed transaction. + fn send_transaction( + &self, + mut request: TransactionRequest, + ) -> impl Future> + Send + where + Self: EthApiSpec + LoadBlock + LoadPendingBlock + LoadFee + Call, + { + async move { + let from = match request.from { + Some(from) => from, + None => return Err(SignError::NoAccount.into()), + }; + + // set nonce if not already set before + if request.nonce.is_none() { + let nonce = self.transaction_count(from, Some(BlockId::pending())).await?; + // note: `.to()` can't panic because the nonce is constructed from a `u64` + request.nonce = Some(nonce.to::()); + } + + let chain_id = self.chain_id(); + + let estimated_gas = + self.estimate_gas_at(request.clone(), BlockId::pending(), None).await?; + let gas_limit = estimated_gas; + + let TransactionRequest { + to, + gas_price, + max_fee_per_gas, + max_priority_fee_per_gas, + gas, + value, + input: data, + nonce, + mut access_list, + max_fee_per_blob_gas, + blob_versioned_hashes, + sidecar, + .. + } = request; + + // todo: remove this inlining after https://github.com/alloy-rs/alloy/pull/183#issuecomment-1928161285 + let transaction = match ( + gas_price, + max_fee_per_gas, + access_list.take(), + max_fee_per_blob_gas, + blob_versioned_hashes, + sidecar, + ) { + // legacy transaction + // gas price required + (Some(_), None, None, None, None, None) => { + Some(TypedTransactionRequest::Legacy(LegacyTransactionRequest { + nonce: nonce.unwrap_or_default(), + gas_price: U256::from(gas_price.unwrap_or_default()), + gas_limit: U256::from(gas.unwrap_or_default()), + value: value.unwrap_or_default(), + input: data.into_input().unwrap_or_default(), + kind: to.unwrap_or(TxKind::Create), + chain_id: None, + })) + } + // EIP2930 + // if only accesslist is set, and no eip1599 fees + (_, None, Some(access_list), None, None, None) => { + Some(TypedTransactionRequest::EIP2930(EIP2930TransactionRequest { + nonce: nonce.unwrap_or_default(), + gas_price: U256::from(gas_price.unwrap_or_default()), + gas_limit: U256::from(gas.unwrap_or_default()), + value: value.unwrap_or_default(), + input: data.into_input().unwrap_or_default(), + kind: to.unwrap_or(TxKind::Create), + chain_id: 0, + access_list, + })) + } + // EIP1559 + // if 4844 fields missing + // gas_price, max_fee_per_gas, access_list, max_fee_per_blob_gas, + // blob_versioned_hashes, sidecar, + (None, _, _, None, None, None) => { + // Empty fields fall back to the canonical transaction schema. + Some(TypedTransactionRequest::EIP1559(EIP1559TransactionRequest { + nonce: nonce.unwrap_or_default(), + max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()), + max_priority_fee_per_gas: U256::from( + max_priority_fee_per_gas.unwrap_or_default(), + ), + gas_limit: U256::from(gas.unwrap_or_default()), + value: value.unwrap_or_default(), + input: data.into_input().unwrap_or_default(), + kind: to.unwrap_or(TxKind::Create), + chain_id: 0, + access_list: access_list.unwrap_or_default(), + })) + } + // EIP4884 + // all blob fields required + ( + None, + _, + _, + Some(max_fee_per_blob_gas), + Some(blob_versioned_hashes), + Some(sidecar), + ) => { + // As per the EIP, we follow the same semantics as EIP-1559. + Some(TypedTransactionRequest::EIP4844(EIP4844TransactionRequest { + chain_id: 0, + nonce: nonce.unwrap_or_default(), + max_priority_fee_per_gas: U256::from( + max_priority_fee_per_gas.unwrap_or_default(), + ), + max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()), + gas_limit: U256::from(gas.unwrap_or_default()), + value: value.unwrap_or_default(), + input: data.into_input().unwrap_or_default(), + #[allow(clippy::manual_unwrap_or_default)] // clippy is suggesting here unwrap_or_default + to: match to { + Some(TxKind::Call(to)) => to, + _ => Address::default(), + }, + access_list: access_list.unwrap_or_default(), + + // eip-4844 specific. + max_fee_per_blob_gas: U256::from(max_fee_per_blob_gas), + blob_versioned_hashes, + sidecar, + })) + } + + _ => None, + }; + + let transaction = match transaction { + Some(TypedTransactionRequest::Legacy(mut req)) => { + req.chain_id = Some(chain_id.to()); + req.gas_limit = gas_limit.saturating_to(); + req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?; + + TypedTransactionRequest::Legacy(req) + } + Some(TypedTransactionRequest::EIP2930(mut req)) => { + req.chain_id = chain_id.to(); + req.gas_limit = gas_limit.saturating_to(); + req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?; + + TypedTransactionRequest::EIP2930(req) + } + Some(TypedTransactionRequest::EIP1559(mut req)) => { + let (max_fee_per_gas, max_priority_fee_per_gas) = self + .eip1559_fees( + max_fee_per_gas.map(U256::from), + max_priority_fee_per_gas.map(U256::from), + ) + .await?; + + req.chain_id = chain_id.to(); + req.gas_limit = gas_limit.saturating_to(); + req.max_fee_per_gas = max_fee_per_gas.saturating_to(); + req.max_priority_fee_per_gas = max_priority_fee_per_gas.saturating_to(); + + TypedTransactionRequest::EIP1559(req) + } + Some(TypedTransactionRequest::EIP4844(mut req)) => { + let (max_fee_per_gas, max_priority_fee_per_gas) = self + .eip1559_fees( + max_fee_per_gas.map(U256::from), + max_priority_fee_per_gas.map(U256::from), + ) + .await?; + + req.max_fee_per_gas = max_fee_per_gas; + req.max_priority_fee_per_gas = max_priority_fee_per_gas; + req.max_fee_per_blob_gas = + self.eip4844_blob_fee(max_fee_per_blob_gas.map(U256::from)).await?; + + req.chain_id = chain_id.to(); + req.gas_limit = gas_limit; + + TypedTransactionRequest::EIP4844(req) + } + None => return Err(EthApiError::ConflictingFeeFieldsInRequest), + }; + + let signed_tx = self.sign_request(&from, transaction)?; + + let recovered = + signed_tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?; + + let pool_transaction = match recovered.try_into() { + Ok(converted) => <::Pool as TransactionPool>::Transaction::from_recovered_pooled_transaction(converted), + Err(_) => return Err(EthApiError::TransactionConversionError), + }; + + // submit the transaction to the pool with a `Local` origin + let hash = LoadTransaction::pool(self) + .add_transaction(TransactionOrigin::Local, pool_transaction) + .await?; + + Ok(hash) + } + } + + /// Signs a transaction, with configured signers. + fn sign_request( + &self, + from: &Address, + request: TypedTransactionRequest, + ) -> EthResult { + for signer in self.signers().read().iter() { + if signer.is_signer_for(from) { + return match signer.sign_transaction(request, from) { + Ok(tx) => Ok(tx), + Err(e) => Err(e.into()), + } + } + } + Err(EthApiError::InvalidTransactionSignature) + } + + /// Signs given message. Returns the signature. + fn sign( + &self, + account: Address, + message: Bytes, + ) -> impl Future> + Send { + async move { Ok(self.find_signer(&account)?.sign(account, &message).await?.to_hex_bytes()) } + } + + /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. + fn sign_typed_data(&self, data: &TypedData, account: Address) -> EthResult { + Ok(self.find_signer(&account)?.sign_typed_data(account, data)?.to_hex_bytes()) + } + + /// Returns the signer for the given account, if found in configured signers. + fn find_signer(&self, account: &Address) -> Result, SignError> { + self.signers() + .read() + .iter() + .find(|signer| signer.is_signer_for(account)) + .map(|signer| dyn_clone::clone_box(&**signer)) + .ok_or(SignError::NoAccount) + } +} + +/// Loads a transaction from database. +/// +/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` transactions RPC +/// methods. +pub trait LoadTransaction: SpawnBlocking { + /// Transaction pool with pending transactions. [`TransactionPool::Transaction`] is the + /// supported transaction type. + type Pool: TransactionPool; + + /// Returns a handle for reading data from disk. + /// + /// Data access in default (L1) trait method implementations. + fn provider(&self) -> impl TransactionsProvider; + + /// Returns a handle for reading data from memory. + /// + /// Data access in default (L1) trait method implementations. + fn cache(&self) -> &EthStateCache; + + /// Returns a handle for reading data from pool. + /// + /// Data access in default (L1) trait method implementations. + fn pool(&self) -> &Self::Pool; + + /// Returns the transaction by hash. + /// + /// Checks the pool and state. + /// + /// Returns `Ok(None)` if no matching transaction was found. + fn transaction_by_hash( + &self, + hash: B256, + ) -> impl Future>> + Send { + async move { + // Try to find the transaction on disk + let mut resp = self + .spawn_blocking_io(move |this| { + match this.provider().transaction_by_hash_with_meta(hash)? { + None => Ok(None), + Some((tx, meta)) => { + // Note: we assume this transaction is valid, because it's mined (or + // part of pending block) and already. We don't need to + // check for pre EIP-2 because this transaction could be pre-EIP-2. + let transaction = tx + .into_ecrecovered_unchecked() + .ok_or(EthApiError::InvalidTransactionSignature)?; + + let tx = TransactionSource::Block { + transaction, + index: meta.index, + block_hash: meta.block_hash, + block_number: meta.block_number, + base_fee: meta.base_fee, + }; + Ok(Some(tx)) + } + } + }) + .await?; + + if resp.is_none() { + // tx not found on disk, check pool + if let Some(tx) = + self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction()) + { + resp = Some(TransactionSource::Pool(tx)); + } + } + + Ok(resp) + } + } + + /// Returns the transaction by including its corresponding [`BlockId`]. + /// + /// Note: this supports pending transactions + fn transaction_by_hash_at( + &self, + transaction_hash: B256, + ) -> impl Future>> + Send { + async move { + match self.transaction_by_hash(transaction_hash).await? { + None => Ok(None), + Some(tx) => { + let res = match tx { + tx @ TransactionSource::Pool(_) => (tx, BlockId::pending()), + TransactionSource::Block { + transaction, + index, + block_hash, + block_number, + base_fee, + } => { + let at = BlockId::Hash(block_hash.into()); + let tx = TransactionSource::Block { + transaction, + index, + block_hash, + block_number, + base_fee, + }; + (tx, at) + } + }; + Ok(Some(res)) + } + } + } + } + + /// Fetches the transaction and the transaction's block + fn transaction_and_block( + &self, + hash: B256, + ) -> impl Future>> + Send + { + async move { + let (transaction, at) = match self.transaction_by_hash_at(hash).await? { + None => return Ok(None), + Some(res) => res, + }; + + // Note: this is always either hash or pending + let block_hash = match at { + BlockId::Hash(hash) => hash.block_hash, + _ => return Ok(None), + }; + let block = self.cache().get_block_with_senders(block_hash).await?; + Ok(block.map(|block| (transaction, block.seal(block_hash)))) + } + } +} + +/// A trait that allows for forwarding raw transactions. +/// +/// For example to a sequencer. +#[async_trait::async_trait] +pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static { + /// Forwards raw transaction bytes for `eth_sendRawTransaction` + async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>; +} diff --git a/crates/rpc/rpc-eth-api/src/lib.rs b/crates/rpc/rpc-eth-api/src/lib.rs new file mode 100644 index 000000000000..922c6ed77fad --- /dev/null +++ b/crates/rpc/rpc-eth-api/src/lib.rs @@ -0,0 +1,33 @@ +//! Reth RPC `eth_` API implementation +//! +//! ## Feature Flags +//! +//! - `client`: Enables JSON-RPC client support. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +pub mod bundle; +pub mod core; +pub mod filter; +pub mod helpers; +pub mod pubsub; + +pub use bundle::{EthBundleApiServer, EthCallBundleApiServer}; +pub use core::EthApiServer; +pub use filter::EthFilterApiServer; +pub use pubsub::EthPubSubApiServer; + +pub use helpers::transaction::RawTransactionForwarder; + +#[cfg(feature = "client")] +pub use bundle::{EthBundleApiClient, EthCallBundleApiClient}; +#[cfg(feature = "client")] +pub use core::EthApiClient; +#[cfg(feature = "client")] +pub use filter::EthFilterApiClient; diff --git a/crates/rpc/rpc-api/src/eth_pubsub.rs b/crates/rpc/rpc-eth-api/src/pubsub.rs similarity index 92% rename from crates/rpc/rpc-api/src/eth_pubsub.rs rename to crates/rpc/rpc-eth-api/src/pubsub.rs index eaa1ef2d817e..8de125152823 100644 --- a/crates/rpc/rpc-api/src/eth_pubsub.rs +++ b/crates/rpc/rpc-eth-api/src/pubsub.rs @@ -1,3 +1,5 @@ +//! `eth_` RPC API for pubsub subscription. + use jsonrpsee::proc_macros::rpc; use reth_rpc_types::pubsub::{Params, SubscriptionKind}; diff --git a/crates/rpc/rpc-eth-types/Cargo.toml b/crates/rpc/rpc-eth-types/Cargo.toml new file mode 100644 index 000000000000..b1c307191025 --- /dev/null +++ b/crates/rpc/rpc-eth-types/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "reth-rpc-eth-types" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +description = "Types supporting implementation of 'eth' namespace RPC server API" + +[lints] +workspace = true + +[dependencies] +reth-chainspec.workspace = true +reth-errors.workspace = true +reth-evm.workspace = true +reth-execution-types.workspace = true +reth-metrics.workspace = true +reth-primitives.workspace = true +reth-provider.workspace = true +reth-revm.workspace = true +reth-rpc-server-types.workspace = true +reth-rpc-types.workspace = true +reth-rpc-types-compat.workspace = true +reth-tasks.workspace = true +reth-transaction-pool.workspace = true +reth-trie.workspace = true + +# ethereum +alloy-sol-types.workspace = true +revm.workspace = true +revm-inspectors = { workspace = true, features = ["js-tracer"] } +revm-primitives = { workspace = true, features = ["dev"] } + +# rpc +jsonrpsee-core.workspace = true +jsonrpsee-types.workspace = true + +# async +futures.workspace = true +tokio.workspace = true +tokio-stream.workspace = true + +# metrics +metrics.workspace = true + +# misc +serde = { workspace = true, features = ["derive"] } +thiserror.workspace = true +derive_more.workspace = true +schnellru.workspace = true +rand.workspace = true +tracing.workspace = true + +[dev-dependencies] +serde_json.workspace = true + +[features] +optimism = [ + "reth-primitives/optimism", + "reth-provider/optimism", + "reth-revm/optimism", + "reth-chainspec/optimism", + "reth-execution-types/optimism", + "reth-revm/optimism", + "revm/optimism" +] \ No newline at end of file diff --git a/crates/rpc/rpc/src/eth/cache/config.rs b/crates/rpc/rpc-eth-types/src/cache/config.rs similarity index 77% rename from crates/rpc/rpc/src/eth/cache/config.rs rename to crates/rpc/rpc-eth-types/src/cache/config.rs index 5dc989e8e637..c2d379652a47 100644 --- a/crates/rpc/rpc/src/eth/cache/config.rs +++ b/crates/rpc/rpc-eth-types/src/cache/config.rs @@ -1,7 +1,13 @@ -use reth_rpc_server_types::constants::cache::*; +//! Configuration for RPC cache. + use serde::{Deserialize, Serialize}; -/// Settings for the [`EthStateCache`](crate::eth::cache::EthStateCache). +use reth_rpc_server_types::constants::cache::{ + DEFAULT_BLOCK_CACHE_MAX_LEN, DEFAULT_CONCURRENT_DB_REQUESTS, DEFAULT_ENV_CACHE_MAX_LEN, + DEFAULT_RECEIPT_CACHE_MAX_LEN, +}; + +/// Settings for the [`EthStateCache`](super::EthStateCache). #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EthStateCacheConfig { diff --git a/crates/rpc/rpc-eth-types/src/cache/db.rs b/crates/rpc/rpc-eth-types/src/cache/db.rs new file mode 100644 index 000000000000..47af8e85df31 --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/cache/db.rs @@ -0,0 +1,169 @@ +//! Helper types to workaround 'higher-ranked lifetime error' +//! in default implementation of +//! `reth_rpc_eth_api::helpers::Call`. + +use reth_primitives::{B256, U256}; +use reth_provider::StateProvider; +use reth_revm::{database::StateProviderDatabase, db::CacheDB, DatabaseRef}; +use revm::Database; + +/// Helper alias type for the state's [`CacheDB`] +pub type StateCacheDb<'a> = CacheDB>>; + +/// Hack to get around 'higher-ranked lifetime error', see +/// +#[allow(missing_debug_implementations)] +pub struct StateProviderTraitObjWrapper<'a>(pub &'a dyn StateProvider); + +impl<'a> reth_provider::StateRootProvider for StateProviderTraitObjWrapper<'a> { + fn state_root( + &self, + bundle_state: &revm::db::BundleState, + ) -> reth_errors::ProviderResult { + self.0.state_root(bundle_state) + } + + fn state_root_with_updates( + &self, + bundle_state: &revm::db::BundleState, + ) -> reth_errors::ProviderResult<(B256, reth_trie::updates::TrieUpdates)> { + self.0.state_root_with_updates(bundle_state) + } +} + +impl<'a> reth_provider::AccountReader for StateProviderTraitObjWrapper<'a> { + fn basic_account( + &self, + address: revm_primitives::Address, + ) -> reth_errors::ProviderResult> { + self.0.basic_account(address) + } +} + +impl<'a> reth_provider::BlockHashReader for StateProviderTraitObjWrapper<'a> { + fn block_hash( + &self, + block_number: reth_primitives::BlockNumber, + ) -> reth_errors::ProviderResult> { + self.0.block_hash(block_number) + } + + fn canonical_hashes_range( + &self, + start: reth_primitives::BlockNumber, + end: reth_primitives::BlockNumber, + ) -> reth_errors::ProviderResult> { + self.0.canonical_hashes_range(start, end) + } + + fn convert_block_hash( + &self, + hash_or_number: reth_rpc_types::BlockHashOrNumber, + ) -> reth_errors::ProviderResult> { + self.0.convert_block_hash(hash_or_number) + } +} + +impl<'a> StateProvider for StateProviderTraitObjWrapper<'a> { + fn account_balance( + &self, + addr: revm_primitives::Address, + ) -> reth_errors::ProviderResult> { + self.0.account_balance(addr) + } + + fn account_code( + &self, + addr: revm_primitives::Address, + ) -> reth_errors::ProviderResult> { + self.0.account_code(addr) + } + + fn account_nonce( + &self, + addr: revm_primitives::Address, + ) -> reth_errors::ProviderResult> { + self.0.account_nonce(addr) + } + + fn bytecode_by_hash( + &self, + code_hash: B256, + ) -> reth_errors::ProviderResult> { + self.0.bytecode_by_hash(code_hash) + } + + fn proof( + &self, + address: revm_primitives::Address, + keys: &[B256], + ) -> reth_errors::ProviderResult { + self.0.proof(address, keys) + } + + fn storage( + &self, + account: revm_primitives::Address, + storage_key: reth_primitives::StorageKey, + ) -> reth_errors::ProviderResult> { + self.0.storage(account, storage_key) + } +} + +/// Hack to get around 'higher-ranked lifetime error', see +/// +#[allow(missing_debug_implementations)] +pub struct StateCacheDbRefMutWrapper<'a, 'b>(pub &'b mut StateCacheDb<'a>); + +impl<'a, 'b> Database for StateCacheDbRefMutWrapper<'a, 'b> { + type Error = as Database>::Error; + fn basic( + &mut self, + address: revm_primitives::Address, + ) -> Result, Self::Error> { + self.0.basic(address) + } + + fn block_hash(&mut self, number: U256) -> Result { + self.0.block_hash(number) + } + + fn code_by_hash(&mut self, code_hash: B256) -> Result { + self.0.code_by_hash(code_hash) + } + + fn storage( + &mut self, + address: revm_primitives::Address, + index: U256, + ) -> Result { + self.0.storage(address, index) + } +} + +impl<'a, 'b> DatabaseRef for StateCacheDbRefMutWrapper<'a, 'b> { + type Error = as Database>::Error; + + fn basic_ref( + &self, + address: revm_primitives::Address, + ) -> Result, Self::Error> { + self.0.basic_ref(address) + } + + fn block_hash_ref(&self, number: U256) -> Result { + self.0.block_hash_ref(number) + } + + fn code_by_hash_ref(&self, code_hash: B256) -> Result { + self.0.code_by_hash_ref(code_hash) + } + + fn storage_ref( + &self, + address: revm_primitives::Address, + index: U256, + ) -> Result { + self.0.storage_ref(address, index) + } +} diff --git a/crates/rpc/rpc/src/eth/cache/metrics.rs b/crates/rpc/rpc-eth-types/src/cache/metrics.rs similarity index 93% rename from crates/rpc/rpc/src/eth/cache/metrics.rs rename to crates/rpc/rpc-eth-types/src/cache/metrics.rs index c9b18a299da3..d87a35e03170 100644 --- a/crates/rpc/rpc/src/eth/cache/metrics.rs +++ b/crates/rpc/rpc-eth-types/src/cache/metrics.rs @@ -1,3 +1,5 @@ +//! Tracks state of RPC cache. + use metrics::Counter; use reth_metrics::{metrics::Gauge, Metrics}; diff --git a/crates/rpc/rpc/src/eth/cache/mod.rs b/crates/rpc/rpc-eth-types/src/cache/mod.rs similarity index 98% rename from crates/rpc/rpc/src/eth/cache/mod.rs rename to crates/rpc/rpc-eth-types/src/cache/mod.rs index cfbe68311ee3..cda3d72584c3 100644 --- a/crates/rpc/rpc/src/eth/cache/mod.rs +++ b/crates/rpc/rpc-eth-types/src/cache/mod.rs @@ -26,13 +26,12 @@ use tokio::sync::{ }; use tokio_stream::wrappers::UnboundedReceiverStream; -mod config; -pub use config::*; +use super::{EthStateCacheConfig, MultiConsumerLruCache}; -mod metrics; - -mod multi_consumer; -pub use multi_consumer::MultiConsumerLruCache; +pub mod config; +pub mod db; +pub mod metrics; +pub mod multi_consumer; /// The type that can send the response to a requested [Block] type BlockTransactionsResponseSender = @@ -107,7 +106,7 @@ impl EthStateCache { ) -> Self where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, - EvmConfig: ConfigureEvm + 'static, + EvmConfig: ConfigureEvm, { Self::spawn_with(provider, config, TokioTaskExecutor::default(), evm_config) } @@ -125,7 +124,7 @@ impl EthStateCache { where Provider: StateProviderFactory + BlockReader + EvmEnvProvider + Clone + Unpin + 'static, Tasks: TaskSpawner + Clone + 'static, - EvmConfig: ConfigureEvm + 'static, + EvmConfig: ConfigureEvm, { let EthStateCacheConfig { max_blocks, max_receipts, max_envs, max_concurrent_db_requests } = config; @@ -277,7 +276,7 @@ impl EthStateCache { /// handles messages and does LRU lookups and never blocking IO. /// /// Caution: The channel for the data is _unbounded_ it is assumed that this is mainly used by the -/// [`EthApi`](crate::EthApi) which is typically invoked by the RPC server, which already uses +/// `reth_rpc::EthApi` which is typically invoked by the RPC server, which already uses /// permits to limit concurrent requests. #[must_use = "Type does nothing unless spawned"] pub(crate) struct EthStateCacheService< @@ -316,7 +315,7 @@ impl EthStateCacheService>) { if let Some(queued) = self.full_block_cache.remove(&block_hash) { @@ -403,7 +402,7 @@ impl Future for EthStateCacheService where K: Hash + Eq, L: Limiter, { - /// The LRU cache for the + /// The LRU cache. cache: LruMap, - /// All queued consumers + /// All queued consumers. queued: HashMap>, /// Cache metrics metrics: CacheMetrics, diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc-eth-types/src/error.rs similarity index 97% rename from crates/rpc/rpc/src/eth/error.rs rename to crates/rpc/rpc-eth-types/src/error.rs index 84c1504015a3..4ddbf9a38dfe 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc-eth-types/src/error.rs @@ -1,10 +1,13 @@ //! Implementation specific Errors for the `eth_` namespace. -use crate::result::{internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code}; +use std::time::Duration; + use alloy_sol_types::decode_revert_reason; -use jsonrpsee::types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObject}; use reth_errors::RethError; use reth_primitives::{revm_primitives::InvalidHeader, Address, Bytes}; +use reth_rpc_server_types::result::{ + internal_rpc_err, invalid_params_rpc_err, rpc_err, rpc_error_with_code, +}; use reth_rpc_types::{ error::EthRpcErrorCode, request::TransactionInputError, BlockError, ToRpcError, }; @@ -14,7 +17,6 @@ use reth_transaction_pool::error::{ }; use revm::primitives::{EVMError, ExecutionResult, HaltReason, OutOfGasError}; use revm_inspectors::tracing::{js::JsInspectorError, MuxError}; -use std::time::Duration; /// Result alias pub type EthResult = Result; @@ -134,7 +136,7 @@ impl EthApiError { } } -impl From for ErrorObject<'static> { +impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(error: EthApiError) -> Self { match error { EthApiError::FailedToDecodeSignedTransaction | @@ -165,9 +167,10 @@ impl From for ErrorObject<'static> { EthApiError::Unsupported(msg) => internal_rpc_err(msg), EthApiError::InternalJsTracerError(msg) => internal_rpc_err(msg), EthApiError::InvalidParams(msg) => invalid_params_rpc_err(msg), - err @ EthApiError::ExecutionTimedOut(_) => { - rpc_error_with_code(CALL_EXECUTION_FAILED_CODE, err.to_string()) - } + err @ EthApiError::ExecutionTimedOut(_) => rpc_error_with_code( + jsonrpsee_types::error::CALL_EXECUTION_FAILED_CODE, + err.to_string(), + ), err @ EthApiError::InternalBlockingTaskError | err @ EthApiError::InternalEthError => { internal_rpc_err(err.to_string()) } @@ -386,7 +389,7 @@ impl RpcInvalidTransactionError { /// Converts the halt error /// /// Takes the configured gas limit of the transaction which is attached to the error - pub(crate) const fn halt(reason: HaltReason, gas_limit: u64) -> Self { + pub const fn halt(reason: HaltReason, gas_limit: u64) -> Self { match reason { HaltReason::OutOfGas(err) => Self::out_of_gas(err, gas_limit), HaltReason::NonceOverflow => Self::NonceMaxValue, @@ -395,7 +398,7 @@ impl RpcInvalidTransactionError { } /// Converts the out of gas error - pub(crate) const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self { + pub const fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self { match reason { OutOfGasError::Basic => Self::BasicOutOfGas(gas_limit), OutOfGasError::Memory | OutOfGasError::MemoryLimit => Self::MemoryOutOfGas(gas_limit), @@ -405,7 +408,7 @@ impl RpcInvalidTransactionError { } } -impl From for ErrorObject<'static> { +impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(err: RpcInvalidTransactionError) -> Self { match err { RpcInvalidTransactionError::Revert(revert) => { @@ -580,7 +583,7 @@ pub enum RpcPoolError { Other(Box), } -impl From for ErrorObject<'static> { +impl From for jsonrpsee_types::error::ErrorObject<'static> { fn from(error: RpcPoolError) -> Self { match error { RpcPoolError::Invalid(err) => err.into(), @@ -655,7 +658,7 @@ pub enum SignError { /// Converts the evm [`ExecutionResult`] into a result where `Ok` variant is the output bytes if it /// is [`ExecutionResult::Success`]. -pub(crate) fn ensure_success(result: ExecutionResult) -> EthResult { +pub fn ensure_success(result: ExecutionResult) -> EthResult { match result { ExecutionResult::Success { output, .. } => Ok(output.into_data()), ExecutionResult::Revert { output, .. } => { diff --git a/crates/rpc/rpc/src/eth/api/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs similarity index 99% rename from crates/rpc/rpc/src/eth/api/fee_history.rs rename to crates/rpc/rpc-eth-types/src/fee_history.rs index 626c670376c8..6f84511aa6eb 100644 --- a/crates/rpc/rpc/src/eth/api/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -1,6 +1,11 @@ //! Consist of types adjacent to the fee history cache and its configs -use crate::eth::{cache::EthStateCache, error::EthApiError}; +use std::{ + collections::{BTreeMap, VecDeque}, + fmt::Debug, + sync::{atomic::Ordering::SeqCst, Arc}, +}; + use futures::{ future::{Fuse, FusedFuture}, FutureExt, Stream, StreamExt, @@ -13,16 +18,14 @@ use reth_primitives::{ Receipt, SealedBlock, TransactionSigned, B256, }; use reth_provider::{BlockReaderIdExt, CanonStateNotification, ChainSpecProvider}; -use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY; use reth_rpc_types::TxGasAndReward; use serde::{Deserialize, Serialize}; -use std::{ - collections::{BTreeMap, VecDeque}, - fmt::Debug, - sync::{atomic::Ordering::SeqCst, Arc}, -}; use tracing::trace; +use reth_rpc_server_types::constants::gas_oracle::MAX_HEADER_HISTORY; + +use super::{EthApiError, EthStateCache}; + /// Contains cached fee history entries for blocks. /// /// Purpose for this is to provide cached data for `eth_feeHistory`. @@ -263,7 +266,7 @@ pub async fn fee_history_cache_new_blocks_task( /// the corresponding rewards for the transactions at each percentile. /// /// The results are returned as a vector of U256 values. -pub(crate) fn calculate_reward_percentiles_for_block( +pub fn calculate_reward_percentiles_for_block( percentiles: &[f64], gas_used: u64, base_fee_per_gas: u64, diff --git a/crates/rpc/rpc/src/eth/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs similarity index 92% rename from crates/rpc/rpc/src/eth/gas_oracle.rs rename to crates/rpc/rpc-eth-types/src/gas_oracle.rs index bb44af67b5f7..4993c5d78a6e 100644 --- a/crates/rpc/rpc/src/eth/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -1,20 +1,28 @@ //! An implementation of the eth gas price oracle, used for providing gas price estimates based on //! previous blocks. -use crate::eth::{ - cache::EthStateCache, - error::{EthApiError, EthResult, RpcInvalidTransactionError}, -}; -use derive_more::{Deref, DerefMut}; +use std::fmt::{self, Debug, Formatter}; + +use derive_more::{Deref, DerefMut, From, Into}; use reth_primitives::{constants::GWEI_TO_WEI, BlockNumberOrTag, B256, U256}; use reth_provider::BlockReaderIdExt; -use reth_rpc_server_types::constants::gas_oracle::*; +use reth_rpc_server_types::constants; use schnellru::{ByLength, LruMap}; use serde::{Deserialize, Serialize}; -use std::fmt::{self, Debug, Formatter}; use tokio::sync::Mutex; use tracing::warn; +use reth_rpc_server_types::constants::gas_oracle::{ + DEFAULT_GAS_PRICE_BLOCKS, DEFAULT_GAS_PRICE_PERCENTILE, DEFAULT_IGNORE_GAS_PRICE, + DEFAULT_MAX_GAS_PRICE, MAX_HEADER_HISTORY, SAMPLE_NUMBER, +}; + +use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError}; + +/// The default gas limit for `eth_call` and adjacent calls. See +/// [`RPC_DEFAULT_GAS_CAP`](constants::gas_oracle::RPC_DEFAULT_GAS_CAP). +pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(constants::gas_oracle::RPC_DEFAULT_GAS_CAP); + /// Settings for the [`GasPriceOracle`] #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -73,7 +81,7 @@ pub struct GasPriceOracle { impl GasPriceOracle where - Provider: BlockReaderIdExt + 'static, + Provider: BlockReaderIdExt, { /// Creates and returns the [`GasPriceOracle`]. pub fn new( @@ -286,6 +294,16 @@ impl Default for GasPriceOracleResult { } } +/// The wrapper type for gas limit +#[derive(Debug, Clone, Copy, From, Into)] +pub struct GasCap(pub u64); + +impl Default for GasCap { + fn default() -> Self { + RPC_DEFAULT_GAS_CAP + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc/rpc/src/eth/id_provider.rs b/crates/rpc/rpc-eth-types/src/id_provider.rs similarity index 84% rename from crates/rpc/rpc/src/eth/id_provider.rs rename to crates/rpc/rpc-eth-types/src/id_provider.rs index 6691e13a9f4b..642d87578f81 100644 --- a/crates/rpc/rpc/src/eth/id_provider.rs +++ b/crates/rpc/rpc-eth-types/src/id_provider.rs @@ -1,14 +1,19 @@ -use jsonrpsee::types::SubscriptionId; +//! Helper type for `reth_rpc_eth_api::EthPubSubApiServer` implementation. +//! +//! Generates IDs for tracking subscriptions. + use std::fmt::Write; -/// An [`IdProvider`](jsonrpsee::core::traits::IdProvider) for ethereum subscription ids. +use jsonrpsee_types::SubscriptionId; + +/// An [`IdProvider`](jsonrpsee_core::traits::IdProvider) for ethereum subscription ids. /// /// Returns new hex-string [QUANTITY](https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding) ids #[derive(Debug, Clone, Copy, Default)] #[non_exhaustive] pub struct EthSubscriptionIdProvider; -impl jsonrpsee::core::traits::IdProvider for EthSubscriptionIdProvider { +impl jsonrpsee_core::traits::IdProvider for EthSubscriptionIdProvider { fn next_id(&self) -> SubscriptionId<'static> { to_quantity(rand::random::()) } diff --git a/crates/rpc/rpc-eth-types/src/lib.rs b/crates/rpc/rpc-eth-types/src/lib.rs new file mode 100644 index 000000000000..be4e1619ce42 --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/lib.rs @@ -0,0 +1,34 @@ +//! Reth RPC server types, used in server implementation of `eth` namespace API. + +#![doc( + html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", + html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", + issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" +)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +pub mod cache; +pub mod error; +pub mod fee_history; +pub mod gas_oracle; +pub mod id_provider; +pub mod logs_utils; +pub mod pending_block; +pub mod receipt; +pub mod revm_utils; +pub mod transaction; +pub mod utils; + +pub use cache::{ + config::EthStateCacheConfig, db::StateCacheDb, multi_consumer::MultiConsumerLruCache, + EthStateCache, +}; +pub use error::{EthApiError, EthResult, RevertError, RpcInvalidTransactionError, SignError}; +pub use fee_history::{FeeHistoryCache, FeeHistoryCacheConfig, FeeHistoryEntry}; +pub use gas_oracle::{GasCap, GasPriceOracle, GasPriceOracleConfig, GasPriceOracleResult}; +pub use id_provider::EthSubscriptionIdProvider; +pub use logs_utils::EthFilterError; +pub use pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}; +pub use receipt::ReceiptBuilder; +pub use transaction::TransactionSource; diff --git a/crates/rpc/rpc/src/eth/logs_utils.rs b/crates/rpc/rpc-eth-types/src/logs_utils.rs similarity index 78% rename from crates/rpc/rpc/src/eth/logs_utils.rs rename to crates/rpc/rpc-eth-types/src/logs_utils.rs index c57ce5fcb986..5cd5fa789d04 100644 --- a/crates/rpc/rpc/src/eth/logs_utils.rs +++ b/crates/rpc/rpc-eth-types/src/logs_utils.rs @@ -1,12 +1,66 @@ -use super::filter::FilterError; -use alloy_primitives::TxHash; +//! Helper functions for `reth_rpc_eth_api::EthFilterApiServer` implementation. +//! +//! Log parsing for building filter. + use reth_chainspec::ChainInfo; -use reth_primitives::{BlockNumHash, Receipt}; +use reth_primitives::{BlockNumHash, Receipt, TxHash}; use reth_provider::{BlockReader, ProviderError}; -use reth_rpc_types::{FilteredParams, Log}; +use reth_rpc_server_types::result::rpc_error_with_code; +use reth_rpc_types::{FilterId, FilteredParams, Log}; + +use crate::EthApiError; + +/// Errors that can occur in the handler implementation +#[derive(Debug, thiserror::Error)] +pub enum EthFilterError { + /// Filter not found. + #[error("filter not found")] + FilterNotFound(FilterId), + /// Invalid block range. + #[error("invalid block range params")] + InvalidBlockRangeParams, + /// Query scope is too broad. + #[error("query exceeds max block range {0}")] + QueryExceedsMaxBlocks(u64), + /// Query result is too large. + #[error("query exceeds max results {0}")] + QueryExceedsMaxResults(usize), + /// Error serving request in `eth_` namespace. + #[error(transparent)] + EthAPIError(#[from] EthApiError), + /// Error thrown when a spawned task failed to deliver a response. + #[error("internal filter error")] + InternalError, +} + +// convert the error +impl From for jsonrpsee_types::error::ErrorObject<'static> { + fn from(err: EthFilterError) -> Self { + match err { + EthFilterError::FilterNotFound(_) => { + rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, "filter not found") + } + err @ EthFilterError::InternalError => { + rpc_error_with_code(jsonrpsee_types::error::INTERNAL_ERROR_CODE, err.to_string()) + } + EthFilterError::EthAPIError(err) => err.into(), + err @ EthFilterError::InvalidBlockRangeParams | + err @ EthFilterError::QueryExceedsMaxBlocks(_) | + err @ EthFilterError::QueryExceedsMaxResults(_) => { + rpc_error_with_code(jsonrpsee_types::error::INVALID_PARAMS_CODE, err.to_string()) + } + } + } +} + +impl From for EthFilterError { + fn from(err: ProviderError) -> Self { + Self::EthAPIError(err.into()) + } +} /// Returns all matching of a block's receipts when the transaction hashes are known. -pub(crate) fn matching_block_logs_with_tx_hashes<'a, I>( +pub fn matching_block_logs_with_tx_hashes<'a, I>( filter: &FilteredParams, block_num_hash: BlockNumHash, tx_hashes_and_receipts: I, @@ -43,7 +97,7 @@ where /// Appends all matching logs of a block's receipts. /// If the log matches, look up the corresponding transaction hash. -pub(crate) fn append_matching_block_logs( +pub fn append_matching_block_logs( all_logs: &mut Vec, provider: impl BlockReader, filter: &FilteredParams, @@ -51,7 +105,7 @@ pub(crate) fn append_matching_block_logs( receipts: &[Receipt], removed: bool, block_timestamp: u64, -) -> Result<(), FilterError> { +) -> Result<(), EthFilterError> { // Tracks the index of a log in the entire block. let mut log_index: u64 = 0; @@ -110,7 +164,7 @@ pub(crate) fn append_matching_block_logs( } /// Returns true if the log matches the filter and should be included -pub(crate) fn log_matches_filter( +pub fn log_matches_filter( block: BlockNumHash, log: &reth_primitives::Log, params: &FilteredParams, @@ -127,7 +181,7 @@ pub(crate) fn log_matches_filter( } /// Computes the block range based on the filter range and current block numbers -pub(crate) fn get_filter_block_range( +pub fn get_filter_block_range( from_block: Option, to_block: Option, start_block: u64, diff --git a/crates/rpc/rpc-eth-types/src/pending_block.rs b/crates/rpc/rpc-eth-types/src/pending_block.rs new file mode 100644 index 000000000000..7e27a9d6b692 --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/pending_block.rs @@ -0,0 +1,162 @@ +//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation. +//! +//! Types used in block building. + +use std::{fmt, time::Instant}; + +use derive_more::Constructor; +use reth_chainspec::ChainSpec; +use reth_primitives::{BlockId, BlockNumberOrTag, SealedBlockWithSenders, SealedHeader, B256}; +use reth_provider::ProviderError; +use reth_revm::state_change::{apply_beacon_root_contract_call, apply_blockhashes_update}; +use revm_primitives::{ + db::{Database, DatabaseCommit}, + BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, +}; + +use super::{EthApiError, EthResult}; + +/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block +#[derive(Debug, Clone, Constructor)] +pub struct PendingBlockEnv { + /// Configured [`CfgEnvWithHandlerCfg`] for the pending block. + pub cfg: CfgEnvWithHandlerCfg, + /// Configured [`BlockEnv`] for the pending block. + pub block_env: BlockEnv, + /// Origin block for the config + pub origin: PendingBlockEnvOrigin, +} + +/// Apply the [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) pre block contract call. +/// +/// This constructs a new [Evm](revm::Evm) with the given DB, and environment +/// [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] to execute the pre block contract call. +/// +/// This uses [`apply_beacon_root_contract_call`] to ultimately apply the beacon root contract state +/// change. +pub fn pre_block_beacon_root_contract_call( + db: &mut DB, + chain_spec: &ChainSpec, + block_number: u64, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + parent_beacon_block_root: Option, +) -> EthResult<()> +where + DB::Error: fmt::Display, +{ + // apply pre-block EIP-4788 contract call + let mut evm_pre_block = revm::Evm::builder() + .with_db(db) + .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + Default::default(), + )) + .build(); + + // initialize a block from the env, because the pre block call needs the block itself + apply_beacon_root_contract_call( + chain_spec, + initialized_block_env.timestamp.to::(), + block_number, + parent_beacon_block_root, + &mut evm_pre_block, + ) + .map_err(|err| EthApiError::Internal(err.into())) +} + +/// Apply the [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) pre block state transitions. +/// +/// This constructs a new [Evm](revm::Evm) with the given DB, and environment +/// [`CfgEnvWithHandlerCfg`] and [`BlockEnv`]. +/// +/// This uses [`apply_blockhashes_update`]. +pub fn pre_block_blockhashes_update + DatabaseCommit>( + db: &mut DB, + chain_spec: &ChainSpec, + initialized_block_env: &BlockEnv, + block_number: u64, + parent_block_hash: B256, +) -> EthResult<()> +where + DB::Error: fmt::Display, +{ + apply_blockhashes_update( + db, + chain_spec, + initialized_block_env.timestamp.to::(), + block_number, + parent_block_hash, + ) + .map_err(|err| EthApiError::Internal(err.into())) +} + +/// The origin for a configured [`PendingBlockEnv`] +#[derive(Clone, Debug)] +pub enum PendingBlockEnvOrigin { + /// The pending block as received from the CL. + ActualPending(SealedBlockWithSenders), + /// The _modified_ header of the latest block. + /// + /// This derives the pending state based on the latest header by modifying: + /// - the timestamp + /// - the block number + /// - fees + DerivedFromLatest(SealedHeader), +} + +impl PendingBlockEnvOrigin { + /// Returns true if the origin is the actual pending block as received from the CL. + pub const fn is_actual_pending(&self) -> bool { + matches!(self, Self::ActualPending(_)) + } + + /// Consumes the type and returns the actual pending block. + pub fn into_actual_pending(self) -> Option { + match self { + Self::ActualPending(block) => Some(block), + _ => None, + } + } + + /// Returns the [`BlockId`] that represents the state of the block. + /// + /// If this is the actual pending block, the state is the "Pending" tag, otherwise we can safely + /// identify the block by its hash (latest block). + pub fn state_block_id(&self) -> BlockId { + match self { + Self::ActualPending(_) => BlockNumberOrTag::Pending.into(), + Self::DerivedFromLatest(header) => BlockId::Hash(header.hash().into()), + } + } + + /// Returns the hash of the block the pending block should be built on. + /// + /// For the [`PendingBlockEnvOrigin::ActualPending`] this is the parent hash of the block. + /// For the [`PendingBlockEnvOrigin::DerivedFromLatest`] this is the hash of the _latest_ + /// header. + pub fn build_target_hash(&self) -> B256 { + match self { + Self::ActualPending(block) => block.parent_hash, + Self::DerivedFromLatest(header) => header.hash(), + } + } + + /// Returns the header this pending block is based on. + pub fn header(&self) -> &SealedHeader { + match self { + Self::ActualPending(block) => &block.header, + Self::DerivedFromLatest(header) => header, + } + } +} + +/// In memory pending block for `pending` tag +#[derive(Debug, Constructor)] +pub struct PendingBlock { + /// The cached pending block + pub block: SealedBlockWithSenders, + /// Timestamp when the pending block is considered outdated + pub expires_at: Instant, +} diff --git a/crates/rpc/rpc-eth-types/src/receipt.rs b/crates/rpc/rpc-eth-types/src/receipt.rs new file mode 100644 index 000000000000..cd3fd1ed514b --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/receipt.rs @@ -0,0 +1,126 @@ +//! RPC receipt response builder, extends a layer one receipt with layer two data. + +use reth_primitives::{Address, Receipt, TransactionMeta, TransactionSigned, TxKind}; +use reth_rpc_types::{ + AnyReceiptEnvelope, AnyTransactionReceipt, Log, OtherFields, ReceiptWithBloom, + TransactionReceipt, WithOtherFields, +}; +use revm_primitives::calc_blob_gasprice; + +use super::{EthApiError, EthResult}; + +/// Receipt response builder. +#[derive(Debug)] +pub struct ReceiptBuilder { + /// The base response body, contains L1 fields. + base: TransactionReceipt>, + /// Additional L2 fields. + other: OtherFields, +} + +impl ReceiptBuilder { + /// Returns a new builder with the base response body (L1 fields) set. + /// + /// Note: This requires _all_ block receipts because we need to calculate the gas used by the + /// transaction. + pub fn new( + transaction: &TransactionSigned, + meta: TransactionMeta, + receipt: &Receipt, + all_receipts: &[Receipt], + ) -> EthResult { + // Note: we assume this transaction is valid, because it's mined (or part of pending block) + // and we don't need to check for pre EIP-2 + let from = transaction + .recover_signer_unchecked() + .ok_or(EthApiError::InvalidTransactionSignature)?; + + // get the previous transaction cumulative gas used + let gas_used = if meta.index == 0 { + receipt.cumulative_gas_used + } else { + let prev_tx_idx = (meta.index - 1) as usize; + all_receipts + .get(prev_tx_idx) + .map(|prev_receipt| receipt.cumulative_gas_used - prev_receipt.cumulative_gas_used) + .unwrap_or_default() + }; + + let blob_gas_used = transaction.transaction.blob_gas_used(); + // Blob gas price should only be present if the transaction is a blob transaction + let blob_gas_price = + blob_gas_used.and_then(|_| meta.excess_blob_gas.map(calc_blob_gasprice)); + let logs_bloom = receipt.bloom_slow(); + + // get number of logs in the block + let mut num_logs = 0; + for prev_receipt in all_receipts.iter().take(meta.index as usize) { + num_logs += prev_receipt.logs.len(); + } + + let mut logs = Vec::with_capacity(receipt.logs.len()); + for (tx_log_idx, log) in receipt.logs.iter().enumerate() { + let rpclog = Log { + inner: log.clone(), + block_hash: Some(meta.block_hash), + block_number: Some(meta.block_number), + block_timestamp: Some(meta.timestamp), + transaction_hash: Some(meta.tx_hash), + transaction_index: Some(meta.index), + log_index: Some((num_logs + tx_log_idx) as u64), + removed: false, + }; + logs.push(rpclog); + } + + let rpc_receipt = reth_rpc_types::Receipt { + status: receipt.success.into(), + cumulative_gas_used: receipt.cumulative_gas_used as u128, + logs, + }; + + let (contract_address, to) = match transaction.transaction.kind() { + TxKind::Create => (Some(from.create(transaction.transaction.nonce())), None), + TxKind::Call(addr) => (None, Some(Address(*addr))), + }; + + #[allow(clippy::needless_update)] + let base = TransactionReceipt { + inner: AnyReceiptEnvelope { + inner: ReceiptWithBloom { receipt: rpc_receipt, logs_bloom }, + r#type: transaction.transaction.tx_type().into(), + }, + transaction_hash: meta.tx_hash, + transaction_index: Some(meta.index), + block_hash: Some(meta.block_hash), + block_number: Some(meta.block_number), + from, + to, + gas_used: gas_used as u128, + contract_address, + effective_gas_price: transaction.effective_gas_price(meta.base_fee), + // TODO pre-byzantium receipts have a post-transaction state root + state_root: None, + // EIP-4844 fields + blob_gas_price, + blob_gas_used: blob_gas_used.map(u128::from), + }; + + Ok(Self { base, other: Default::default() }) + } + + /// Adds fields to response body. + pub fn add_other_fields(mut self, mut fields: OtherFields) -> Self { + self.other.append(&mut fields); + self + } + + /// Builds a receipt response from the base response body, and any set additional fields. + pub fn build(self) -> AnyTransactionReceipt { + let Self { base, other } = self; + let mut res = WithOtherFields::new(base); + res.other = other; + + res + } +} diff --git a/crates/rpc/rpc/src/eth/revm_utils.rs b/crates/rpc/rpc-eth-types/src/revm_utils.rs similarity index 90% rename from crates/rpc/rpc/src/eth/revm_utils.rs rename to crates/rpc/rpc-eth-types/src/revm_utils.rs index 4f4b9d7f02e4..6b30de26c4da 100644 --- a/crates/rpc/rpc/src/eth/revm_utils.rs +++ b/crates/rpc/rpc-eth-types/src/revm_utils.rs @@ -1,14 +1,8 @@ //! utilities for working with revm -use crate::eth::error::{EthApiError, EthResult, RpcInvalidTransactionError}; -#[cfg(feature = "optimism")] -use reth_primitives::revm::env::fill_op_tx_env; -#[cfg(not(feature = "optimism"))] -use reth_primitives::revm::env::fill_tx_env; -use reth_primitives::{ - revm::env::fill_tx_env_with_recovered, Address, TransactionSigned, - TransactionSignedEcRecovered, TxHash, TxKind, B256, U256, -}; +use std::cmp::min; + +use reth_primitives::{Address, TxKind, B256, U256}; use reth_rpc_types::{ state::{AccountOverride, EvmOverrides, StateOverride}, BlockOverrides, TransactionRequest, @@ -23,58 +17,9 @@ use revm::{ }, Database, }; -use std::cmp::min; use tracing::trace; -/// Helper type to work with different transaction types when configuring the EVM env. -/// -/// This makes it easier to handle errors. -pub trait FillableTransaction { - /// Returns the hash of the transaction. - fn hash(&self) -> TxHash; - - /// Fill the transaction environment with the given transaction. - fn try_fill_tx_env(&self, tx_env: &mut TxEnv) -> EthResult<()>; -} - -impl FillableTransaction for TransactionSignedEcRecovered { - fn hash(&self) -> TxHash { - self.hash - } - - fn try_fill_tx_env(&self, tx_env: &mut TxEnv) -> EthResult<()> { - #[cfg(not(feature = "optimism"))] - fill_tx_env_with_recovered(tx_env, self); - - #[cfg(feature = "optimism")] - { - let mut envelope_buf = Vec::with_capacity(self.length_without_header()); - self.encode_enveloped(&mut envelope_buf); - fill_tx_env_with_recovered(tx_env, self, envelope_buf.into()); - } - Ok(()) - } -} -impl FillableTransaction for TransactionSigned { - fn hash(&self) -> TxHash { - self.hash - } - - fn try_fill_tx_env(&self, tx_env: &mut TxEnv) -> EthResult<()> { - let signer = - self.recover_signer().ok_or_else(|| EthApiError::InvalidTransactionSignature)?; - #[cfg(not(feature = "optimism"))] - fill_tx_env(tx_env, self, signer); - - #[cfg(feature = "optimism")] - { - let mut envelope_buf = Vec::with_capacity(self.length_without_header()); - self.encode_enveloped(&mut envelope_buf); - fill_op_tx_env(tx_env, self, signer, envelope_buf.into()); - } - Ok(()) - } -} +use super::{EthApiError, EthResult, RpcInvalidTransactionError}; /// Returns the addresses of the precompiles corresponding to the `SpecId`. #[inline] diff --git a/crates/rpc/rpc-eth-types/src/transaction.rs b/crates/rpc/rpc-eth-types/src/transaction.rs new file mode 100644 index 000000000000..32c81d3966f8 --- /dev/null +++ b/crates/rpc/rpc-eth-types/src/transaction.rs @@ -0,0 +1,96 @@ +//! Helper types for `reth_rpc_eth_api::EthApiServer` implementation. +//! +//! Transaction wrapper that labels transaction with its origin. + +use reth_primitives::{TransactionSignedEcRecovered, B256}; +use reth_rpc_types::{Transaction, TransactionInfo}; +use reth_rpc_types_compat::transaction::from_recovered_with_block_context; + +/// Represents from where a transaction was fetched. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum TransactionSource { + /// Transaction exists in the pool (Pending) + Pool(TransactionSignedEcRecovered), + /// Transaction already included in a block + /// + /// This can be a historical block or a pending block (received from the CL) + Block { + /// Transaction fetched via provider + transaction: TransactionSignedEcRecovered, + /// Index of the transaction in the block + index: u64, + /// Hash of the block. + block_hash: B256, + /// Number of the block. + block_number: u64, + /// base fee of the block. + base_fee: Option, + }, +} + +// === impl TransactionSource === + +impl TransactionSource { + /// Consumes the type and returns the wrapped transaction. + pub fn into_recovered(self) -> TransactionSignedEcRecovered { + self.into() + } + + /// Returns the transaction and block related info, if not pending + pub fn split(self) -> (TransactionSignedEcRecovered, TransactionInfo) { + match self { + Self::Pool(tx) => { + let hash = tx.hash(); + ( + tx, + TransactionInfo { + hash: Some(hash), + index: None, + block_hash: None, + block_number: None, + base_fee: None, + }, + ) + } + Self::Block { transaction, index, block_hash, block_number, base_fee } => { + let hash = transaction.hash(); + ( + transaction, + TransactionInfo { + hash: Some(hash), + index: Some(index), + block_hash: Some(block_hash), + block_number: Some(block_number), + base_fee: base_fee.map(u128::from), + }, + ) + } + } + } +} + +impl From for TransactionSignedEcRecovered { + fn from(value: TransactionSource) -> Self { + match value { + TransactionSource::Pool(tx) => tx, + TransactionSource::Block { transaction, .. } => transaction, + } + } +} + +impl From for Transaction { + fn from(value: TransactionSource) -> Self { + match value { + TransactionSource::Pool(tx) => reth_rpc_types_compat::transaction::from_recovered(tx), + TransactionSource::Block { transaction, index, block_hash, block_number, base_fee } => { + from_recovered_with_block_context( + transaction, + block_hash, + block_number, + base_fee, + index as usize, + ) + } + } + } +} diff --git a/crates/rpc/rpc/src/eth/utils.rs b/crates/rpc/rpc-eth-types/src/utils.rs similarity index 79% rename from crates/rpc/rpc/src/eth/utils.rs rename to crates/rpc/rpc-eth-types/src/utils.rs index a4291c4b933d..a35708396813 100644 --- a/crates/rpc/rpc/src/eth/utils.rs +++ b/crates/rpc/rpc-eth-types/src/utils.rs @@ -1,14 +1,13 @@ //! Commonly used code snippets -use crate::eth::error::{EthApiError, EthResult}; use reth_primitives::{Bytes, PooledTransactionsElement, PooledTransactionsElementEcRecovered}; +use super::{EthApiError, EthResult}; + /// Recovers a [`PooledTransactionsElementEcRecovered`] from an enveloped encoded byte stream. /// /// See [`PooledTransactionsElement::decode_enveloped`] -pub(crate) fn recover_raw_transaction( - data: Bytes, -) -> EthResult { +pub fn recover_raw_transaction(data: Bytes) -> EthResult { if data.is_empty() { return Err(EthApiError::EmptyRawTransactionData) } diff --git a/crates/rpc/rpc-server-types/Cargo.toml b/crates/rpc/rpc-server-types/Cargo.toml index ddecc0a490ca..628654ebaf98 100644 --- a/crates/rpc/rpc-server-types/Cargo.toml +++ b/crates/rpc/rpc-server-types/Cargo.toml @@ -12,9 +12,20 @@ description = "RPC server types and constants" workspace = true [dependencies] +reth-errors.workspace = true +reth-network-api.workspace = true +reth-primitives.workspace = true +reth-rpc-types.workspace = true + + # ethereum alloy-primitives.workspace = true +# rpc +jsonrpsee-core.workspace = true +jsonrpsee-types.workspace = true + # misc strum = { workspace = true, features = ["derive"] } serde = { workspace = true, features = ["derive"] } + diff --git a/crates/rpc/rpc-server-types/src/constants.rs b/crates/rpc/rpc-server-types/src/constants.rs index 3784d7508ff2..807d96a91256 100644 --- a/crates/rpc/rpc-server-types/src/constants.rs +++ b/crates/rpc/rpc-server-types/src/constants.rs @@ -64,6 +64,20 @@ pub mod gas_oracle { /// The default minimum gas price, under which the sample will be ignored pub const DEFAULT_IGNORE_GAS_PRICE: U256 = U256::from_limbs([2u64, 0, 0, 0]); + + /// The default gas limit for `eth_call` and adjacent calls. + /// + /// This is different from the default to regular 30M block gas limit + /// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow + /// for more complex calls. + pub const RPC_DEFAULT_GAS_CAP: u64 = 50_000_000; + + /// Gas per transaction not creating a contract. + pub const MIN_TRANSACTION_GAS: u64 = 21_000u64; + /// Allowed error ratio for gas estimation + /// Taken from Geth's implementation in order to pass the hive tests + /// + pub const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015; } /// Cache specific constants diff --git a/crates/rpc/rpc-server-types/src/lib.rs b/crates/rpc/rpc-server-types/src/lib.rs index 4bdee53f83cb..c20b578816b8 100644 --- a/crates/rpc/rpc-server-types/src/lib.rs +++ b/crates/rpc/rpc-server-types/src/lib.rs @@ -10,6 +10,9 @@ /// Common RPC constants. pub mod constants; +pub mod result; mod module; pub use module::{RethRpcModule, RpcModuleSelection}; + +pub use result::ToRpcResult; diff --git a/crates/rpc/rpc-server-types/src/module.rs b/crates/rpc/rpc-server-types/src/module.rs index a94c53d89a0b..c4df75aa21ee 100644 --- a/crates/rpc/rpc-server-types/src/module.rs +++ b/crates/rpc/rpc-server-types/src/module.rs @@ -195,7 +195,7 @@ impl FromStr for RpcModuleSelection { fn from_str(s: &str) -> Result { if s.is_empty() { - return Ok(Self::Selection(Default::default())) + return Ok(Self::Selection(Default::default())); } let mut modules = s.split(',').map(str::trim).peekable(); let first = modules.peek().copied().ok_or(ParseError::VariantNotFound)?; @@ -255,6 +255,8 @@ pub enum RethRpcModule { Reth, /// `ots_` module Ots, + /// `taiko_` module + Taiko, /// For single non-standard `eth_` namespace call `eth_callBundle` /// /// This is separate from [`RethRpcModule::Eth`] because it is a non standardized call that diff --git a/crates/rpc/rpc/src/result.rs b/crates/rpc/rpc-server-types/src/result.rs similarity index 77% rename from crates/rpc/rpc/src/result.rs rename to crates/rpc/rpc-server-types/src/result.rs index f00c9e279939..252c78f241b2 100644 --- a/crates/rpc/rpc/src/result.rs +++ b/crates/rpc/rpc-server-types/src/result.rs @@ -1,9 +1,10 @@ //! Additional helpers for converting errors. -use jsonrpsee::core::RpcResult; -use reth_rpc_types::engine::PayloadError; use std::fmt::Display; +use jsonrpsee_core::RpcResult; +use reth_rpc_types::engine::PayloadError; + /// Helper trait to easily convert various `Result` types into [`RpcResult`] pub trait ToRpcResult: Sized { /// Converts the error of the [Result] to an [`RpcResult`] via the `Err` [Display] impl. @@ -21,14 +22,14 @@ pub trait ToRpcResult: Sized { M: Into; /// Converts this type into an [`RpcResult`] with the - /// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE` and the given message. + /// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and the given message. fn map_internal_err(self, op: F) -> RpcResult where F: FnOnce(Err) -> M, M: Into; /// Converts this type into an [`RpcResult`] with the - /// [`jsonrpsee::types::error::INTERNAL_ERROR_CODE`] and given message and data. + /// [`jsonrpsee_types::error::INTERNAL_ERROR_CODE`] and given message and data. fn map_internal_err_with_data<'a, F, M>(self, op: F) -> RpcResult where F: FnOnce(Err) -> (M, &'a [u8]), @@ -46,7 +47,7 @@ macro_rules! impl_to_rpc_result { ($err:ty) => { impl ToRpcResult for Result { #[inline] - fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult + fn map_rpc_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> (i32, M, Option<&'a [u8]>), M: Into, @@ -61,7 +62,7 @@ macro_rules! impl_to_rpc_result { } #[inline] - fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult + fn map_internal_err<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> M, M: Into, @@ -70,7 +71,7 @@ macro_rules! impl_to_rpc_result { } #[inline] - fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee::core::RpcResult + fn map_internal_err_with_data<'a, F, M>(self, op: F) -> jsonrpsee_core::RpcResult where F: FnOnce($err) -> (M, &'a [u8]), M: Into, @@ -85,7 +86,7 @@ macro_rules! impl_to_rpc_result { } #[inline] - fn with_message(self, msg: &str) -> jsonrpsee::core::RpcResult { + fn with_message(self, msg: &str) -> jsonrpsee_core::RpcResult { match self { Ok(t) => Ok(t), Err(err) => { @@ -104,46 +105,44 @@ impl_to_rpc_result!(reth_errors::ProviderError); impl_to_rpc_result!(reth_network_api::NetworkError); /// Constructs an invalid params JSON-RPC error. -pub(crate) fn invalid_params_rpc_err( +pub fn invalid_params_rpc_err( msg: impl Into, -) -> jsonrpsee::types::error::ErrorObject<'static> { - rpc_err(jsonrpsee::types::error::INVALID_PARAMS_CODE, msg, None) +) -> jsonrpsee_types::error::ErrorObject<'static> { + rpc_err(jsonrpsee_types::error::INVALID_PARAMS_CODE, msg, None) } /// Constructs an internal JSON-RPC error. -pub(crate) fn internal_rpc_err( - msg: impl Into, -) -> jsonrpsee::types::error::ErrorObject<'static> { - rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, None) +pub fn internal_rpc_err(msg: impl Into) -> jsonrpsee_types::error::ErrorObject<'static> { + rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, None) } /// Constructs an internal JSON-RPC error with data -pub(crate) fn internal_rpc_err_with_data( +pub fn internal_rpc_err_with_data( msg: impl Into, data: &[u8], -) -> jsonrpsee::types::error::ErrorObject<'static> { - rpc_err(jsonrpsee::types::error::INTERNAL_ERROR_CODE, msg, Some(data)) +) -> jsonrpsee_types::error::ErrorObject<'static> { + rpc_err(jsonrpsee_types::error::INTERNAL_ERROR_CODE, msg, Some(data)) } /// Constructs an internal JSON-RPC error with code and message -pub(crate) fn rpc_error_with_code( +pub fn rpc_error_with_code( code: i32, msg: impl Into, -) -> jsonrpsee::types::error::ErrorObject<'static> { +) -> jsonrpsee_types::error::ErrorObject<'static> { rpc_err(code, msg, None) } /// Constructs a JSON-RPC error, consisting of `code`, `message` and optional `data`. -pub(crate) fn rpc_err( +pub fn rpc_err( code: i32, msg: impl Into, data: Option<&[u8]>, -) -> jsonrpsee::types::error::ErrorObject<'static> { - jsonrpsee::types::error::ErrorObject::owned( +) -> jsonrpsee_types::error::ErrorObject<'static> { + jsonrpsee_types::error::ErrorObject::owned( code, msg.into(), data.map(|data| { - jsonrpsee::core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data)) + jsonrpsee_core::to_json_raw_value(&reth_primitives::hex::encode_prefixed(data)) .expect("serializing String can't fail") }), ) diff --git a/crates/rpc/rpc-testing-util/Cargo.toml b/crates/rpc/rpc-testing-util/Cargo.toml index 898fec038f70..8ab37d1b18d0 100644 --- a/crates/rpc/rpc-testing-util/Cargo.toml +++ b/crates/rpc/rpc-testing-util/Cargo.toml @@ -29,3 +29,4 @@ similar-asserts.workspace = true [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros", "rt"] } +reth-rpc-eth-api.workspace = true diff --git a/crates/rpc/rpc-testing-util/tests/it/trace.rs b/crates/rpc/rpc-testing-util/tests/it/trace.rs index a6439f0744c4..029e9fbbc8b5 100644 --- a/crates/rpc/rpc-testing-util/tests/it/trace.rs +++ b/crates/rpc/rpc-testing-util/tests/it/trace.rs @@ -1,7 +1,7 @@ use futures::StreamExt; use jsonrpsee::http_client::HttpClientBuilder; -use reth_rpc_api::EthApiClient; use reth_rpc_api_testing_util::{debug::DebugApiExt, trace::TraceApiExt, utils::parse_env_url}; +use reth_rpc_eth_api::EthApiClient; use reth_rpc_types::trace::{ filter::TraceFilter, parity::TraceType, tracerequest::TraceCallRequest, }; diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index a589ef418c64..b2c5c717d73b 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -23,3 +23,4 @@ serde_json.workspace = true [features] optimism = ["reth-primitives/optimism"] +taiko = ["reth-primitives/taiko"] diff --git a/crates/rpc/rpc-types-compat/src/transaction/typed.rs b/crates/rpc/rpc-types-compat/src/transaction/typed.rs index 21e492218a4a..105a30023d73 100644 --- a/crates/rpc/rpc-types-compat/src/transaction/typed.rs +++ b/crates/rpc/rpc-types-compat/src/transaction/typed.rs @@ -40,6 +40,7 @@ pub fn to_primitive_transaction( input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: tx.max_priority_fee_per_gas.to(), + is_anchor: false, }), TypedTransactionRequest::EIP4844(tx) => Transaction::Eip4844(TxEip4844 { chain_id: tx.chain_id, diff --git a/crates/rpc/rpc-types/Cargo.toml b/crates/rpc/rpc-types/Cargo.toml index 648b8b24f2ca..7a6e081a24ff 100644 --- a/crates/rpc/rpc-types/Cargo.toml +++ b/crates/rpc/rpc-types/Cargo.toml @@ -29,11 +29,6 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true jsonrpsee-types = { workspace = true, optional = true } -[features] -default = ["jsonrpsee-types"] -arbitrary = ["alloy-primitives/arbitrary", "alloy-rpc-types/arbitrary"] - - [dev-dependencies] # misc alloy-primitives = { workspace = true, features = ["rand", "rlp", "serde", "arbitrary"] } @@ -44,3 +39,6 @@ rand.workspace = true similar-asserts.workspace = true bytes.workspace = true +[features] +default = ["jsonrpsee-types"] +arbitrary = ["alloy-primitives/arbitrary", "alloy-rpc-types/arbitrary"] \ No newline at end of file diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 87539eab4ae5..966d7c5f6a11 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -16,7 +16,7 @@ workspace = true reth-chainspec.workspace = true reth-primitives.workspace = true reth-rpc-api.workspace = true -reth-rpc-server-types.workspace = true +reth-rpc-eth-api.workspace = true reth-rpc-types.workspace = true reth-errors.workspace = true reth-provider = { workspace = true, features = ["test-utils"] } @@ -28,17 +28,16 @@ reth-tasks = { workspace = true, features = ["rayon"] } reth-consensus-common.workspace = true reth-rpc-types-compat.workspace = true revm-inspectors = { workspace = true, features = ["js-tracer"] } -reth-evm.workspace = true reth-network-peers.workspace = true -reth-execution-types.workspace = true - +reth-evm.workspace = true +reth-rpc-eth-types.workspace = true +reth-rpc-server-types.workspace = true reth-evm-optimism = { workspace = true, optional = true } # eth +alloy-dyn-abi.workspace = true alloy-rlp.workspace = true -alloy-dyn-abi = { workspace = true, features = ["eip712"] } alloy-primitives.workspace = true -alloy-sol-types.workspace = true alloy-genesis.workspace = true revm = { workspace = true, features = [ "optional_block_gas_limit", @@ -46,6 +45,7 @@ revm = { workspace = true, features = [ "optional_no_base_fee", ] } revm-primitives = { workspace = true, features = ["serde"] } +secp256k1.workspace = true # rpc jsonrpsee.workspace = true @@ -53,39 +53,29 @@ http.workspace = true http-body.workspace = true hyper.workspace = true jsonwebtoken.workspace = true +serde_json.workspace = true +jsonrpsee-types = { workspace = true, optional = true } # async async-trait.workspace = true tokio = { workspace = true, features = ["sync"] } +tokio-stream.workspace = true tower.workspace = true -tokio-stream = { workspace = true, features = ["sync"] } pin-project.workspace = true parking_lot.workspace = true -# metrics -reth-metrics.workspace = true -metrics.workspace = true - # misc -secp256k1 = { workspace = true, features = [ - "global-context", - "rand-std", - "recovery", -] } -serde = { workspace = true, features = ["derive"] } -serde_json.workspace = true -thiserror.workspace = true -rand.workspace = true tracing.workspace = true tracing-futures = "0.2" -schnellru.workspace = true futures.workspace = true -derive_more.workspace = true -dyn-clone.workspace = true +rand.workspace = true +serde.workspace = true +thiserror.workspace = true [dev-dependencies] reth-evm-ethereum.workspace = true reth-testing-utils.workspace = true +jsonrpsee-types.workspace = true jsonrpsee = { workspace = true, features = ["client"] } assert_matches.workspace = true @@ -96,7 +86,11 @@ optimism = [ "reth-primitives/optimism", "reth-rpc-types-compat/optimism", "reth-provider/optimism", - "dep:reth-evm-optimism", - "reth-evm-optimism/optimism", + "reth-rpc-api/optimism", + "reth-rpc-eth-api/optimism", "reth-revm/optimism", + "jsonrpsee-types", + "reth-evm-optimism", + "reth-rpc-eth-types/optimism", ] +taiko = ["reth-primitives/taiko", "reth-rpc-api/taiko"] diff --git a/crates/rpc/rpc/src/admin.rs b/crates/rpc/rpc/src/admin.rs index 71f95fedec9a..f294a52c1bf3 100644 --- a/crates/rpc/rpc/src/admin.rs +++ b/crates/rpc/rpc/src/admin.rs @@ -1,4 +1,5 @@ -use crate::result::ToRpcResult; +use std::sync::Arc; + use alloy_genesis::ChainConfig; use alloy_primitives::B256; use async_trait::async_trait; @@ -7,11 +8,11 @@ use reth_chainspec::ChainSpec; use reth_network_api::{NetworkInfo, PeerKind, Peers}; use reth_network_peers::{AnyNode, NodeRecord}; use reth_rpc_api::AdminApiServer; +use reth_rpc_server_types::ToRpcResult; use reth_rpc_types::{ admin::{EthProtocolInfo, NodeInfo, Ports, ProtocolInfo}, PeerEthProtocolInfo, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, }; -use std::sync::Arc; /// `admin` API implementation. /// @@ -37,7 +38,7 @@ where { /// Handler for `admin_addPeer` fn add_peer(&self, record: NodeRecord) -> RpcResult { - self.network.add_peer(record.id, record.tcp_addr()); + self.network.add_peer_with_udp(record.id, record.tcp_addr(), record.udp_addr()); Ok(true) } @@ -50,7 +51,7 @@ where /// Handler for `admin_addTrustedPeer` fn add_trusted_peer(&self, record: AnyNode) -> RpcResult { if let Some(record) = record.node_record() { - self.network.add_trusted_peer(record.id, record.tcp_addr()) + self.network.add_trusted_peer_with_udp(record.id, record.tcp_addr(), record.udp_addr()) } self.network.add_trusted_peer_id(record.peer_id()); Ok(true) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index b2d524a6325b..67363dff31c1 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -1,24 +1,23 @@ -use crate::{ - eth::{ - error::{EthApiError, EthResult}, - revm_utils::prepare_call_env, - EthTransactions, - }, - result::{internal_rpc_err, ToRpcResult}, - EthApiSpec, -}; +use std::sync::Arc; + use alloy_rlp::{Decodable, Encodable}; use async_trait::async_trait; use jsonrpsee::core::RpcResult; +use reth_chainspec::EthereumHardforks; +use reth_evm::ConfigureEvmEnv; use reth_primitives::{ - revm::env::tx_env_with_recovered, Address, Block, BlockId, BlockNumberOrTag, Bytes, - TransactionSignedEcRecovered, Withdrawals, B256, U256, + Address, Block, BlockId, BlockNumberOrTag, Bytes, TransactionSignedEcRecovered, Withdrawals, + B256, U256, }; use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderBox, TransactionVariant, + BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory, + TransactionVariant, }; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::DebugApiServer; +use reth_rpc_eth_api::helpers::{Call, EthApiSpec, EthTransactions, TraceExt}; +use reth_rpc_eth_types::{revm_utils::prepare_call_env, EthApiError, EthResult, StateCacheDb}; +use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult}; use reth_rpc_types::{ state::EvmOverrides, trace::geth::{ @@ -36,7 +35,6 @@ use revm_inspectors::tracing::{ js::{JsInspector, TransactionContext}, FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, }; -use std::sync::Arc; use tokio::sync::{AcquireError, OwnedSemaphorePermit}; /// `debug` API implementation. @@ -65,8 +63,13 @@ impl DebugApi { impl DebugApi where - Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Provider: BlockReaderIdExt + + HeaderProvider + + ChainSpecProvider + + StateProviderFactory + + EvmEnvProvider + + 'static, + Eth: TraceExt + 'static, { /// Acquires a permit to execute a tracing call. async fn acquire_trace_permit(&self) -> Result { @@ -74,7 +77,7 @@ where } /// Trace the entire block asynchronously - async fn trace_block_with( + async fn trace_block( &self, at: BlockId, transactions: Vec, @@ -97,9 +100,13 @@ where let mut transactions = transactions.into_iter().enumerate().peekable(); while let Some((index, tx)) = transactions.next() { let tx_hash = tx.hash; - let tx = tx_env_with_recovered(&tx); + let env = EnvWithHandlerCfg { - env: Env::boxed(cfg.cfg_env.clone(), block_env.clone(), tx), + env: Env::boxed( + cfg.cfg_env.clone(), + block_env.clone(), + Call::evm_config(this.eth_api()).tx_env(&tx), + ), handler_cfg: cfg.handler_cfg, }; let (result, state_changes) = this.trace_transaction( @@ -165,7 +172,7 @@ where .collect::>>()? }; - self.trace_block_with(parent.into(), transactions, cfg, block_env, opts).await + self.trace_block(parent.into(), transactions, cfg, block_env, opts).await } /// Replays a block and returns the trace of each transaction. @@ -182,7 +189,7 @@ where let ((cfg, block_env, _), block) = futures::try_join!( self.inner.eth_api.evm_env_at(block_hash.into()), - self.inner.eth_api.block_by_id_with_senders(block_id), + self.inner.eth_api.block_with_senders(block_id), )?; let block = block.ok_or_else(|| EthApiError::UnknownBlockNumber)?; @@ -190,7 +197,7 @@ where // its parent block's state let state_at = block.parent_hash; - self.trace_block_with( + self.trace_block( state_at.into(), block.into_transactions_ecrecovered().collect(), cfg, @@ -238,7 +245,11 @@ where )?; let env = EnvWithHandlerCfg { - env: Env::boxed(cfg.cfg_env.clone(), block_env, tx_env_with_recovered(&tx)), + env: Env::boxed( + cfg.cfg_env.clone(), + block_env, + Call::evm_config(this.eth_api()).tx_env(&tx), + ), handler_cfg: cfg.handler_cfg, }; @@ -324,6 +335,10 @@ where self.inner .eth_api .spawn_with_call_at(call, at, overrides, move |db, env| { + // wrapper is hack to get around 'higher-ranked lifetime error', + // see + let db = db.0; + let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?; let frame = inspector @@ -346,6 +361,10 @@ where .inner .eth_api .spawn_with_call_at(call, at, overrides, move |db, env| { + // wrapper is hack to get around 'higher-ranked lifetime error', see + // + let db = db.0; + let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?; let frame = inspector.try_into_mux_frame(&res, db)?; @@ -364,6 +383,10 @@ where .inner .eth_api .spawn_with_call_at(call, at, overrides, move |db, env| { + // wrapper is hack to get around 'higher-ranked lifetime error', see + // + let db = db.0; + let mut inspector = JsInspector::new(code, config)?; let (res, _) = this.eth_api().inspect(&mut *db, env.clone(), &mut inspector)?; @@ -415,7 +438,7 @@ where let target_block = block_number.unwrap_or_default(); let ((cfg, mut block_env, _), block) = futures::try_join!( self.inner.eth_api.evm_env_at(target_block), - self.inner.eth_api.block_by_id_with_senders(target_block), + self.inner.eth_api.block_with_senders(target_block), )?; let opts = opts.unwrap_or_default(); @@ -439,6 +462,7 @@ where } let this = self.clone(); + self.inner .eth_api .spawn_with_state_at_block(at.into(), move |state| { @@ -453,9 +477,12 @@ where // Execute all transactions until index for tx in transactions { - let tx = tx_env_with_recovered(&tx); let env = EnvWithHandlerCfg { - env: Env::boxed(cfg.cfg_env.clone(), block_env.clone(), tx), + env: Env::boxed( + cfg.cfg_env.clone(), + block_env.clone(), + Call::evm_config(this.eth_api()).tx_env(&tx), + ), handler_cfg: cfg.handler_cfg, }; let (res, _) = this.inner.eth_api.transact(&mut db, env)?; @@ -518,7 +545,7 @@ where &self, opts: GethDebugTracingOptions, env: EnvWithHandlerCfg, - db: &mut CacheDB>, + db: &mut StateCacheDb<'_>, transaction_context: Option, ) -> EthResult<(GethTrace, revm_primitives::EvmState)> { let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts; @@ -614,8 +641,13 @@ where #[async_trait] impl DebugApiServer for DebugApi where - Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider + 'static, - Eth: EthApiSpec + 'static, + Provider: BlockReaderIdExt + + HeaderProvider + + ChainSpecProvider + + StateProviderFactory + + EvmEnvProvider + + 'static, + Eth: EthApiSpec + EthTransactions + TraceExt + 'static, { /// Handler for `debug_getRawHeader` async fn raw_header(&self, block_id: BlockId) -> RpcResult { diff --git a/crates/rpc/rpc/src/eth/api/block.rs b/crates/rpc/rpc/src/eth/api/block.rs deleted file mode 100644 index 18a547faf9e6..000000000000 --- a/crates/rpc/rpc/src/eth/api/block.rs +++ /dev/null @@ -1,217 +0,0 @@ -//! Contains RPC handler implementations specific to blocks. - -use crate::{ - eth::{ - api::transactions::build_transaction_receipt_with_block_receipts, - error::{EthApiError, EthResult}, - }, - EthApi, -}; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{BlockId, TransactionMeta}; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; -use reth_rpc_types::{AnyTransactionReceipt, Header, Index, RichBlock}; -use reth_rpc_types_compat::block::{from_block, uncle_block_from_header}; -use reth_transaction_pool::TransactionPool; -use std::sync::Arc; - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + Clone + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Returns the uncle headers of the given block - /// - /// Returns an empty vec if there are none. - pub(crate) fn ommers( - &self, - block_id: impl Into, - ) -> EthResult>> { - let block_id = block_id.into(); - Ok(self.provider().ommers_by_id(block_id)?) - } - - pub(crate) async fn ommer_by_block_and_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - let block_id = block_id.into(); - - let uncles = if block_id.is_pending() { - // Pending block can be fetched directly without need for caching - self.provider().pending_block()?.map(|block| block.ommers) - } else { - self.provider().ommers_by_id(block_id)? - } - .unwrap_or_default(); - - let index = usize::from(index); - let uncle = - uncles.into_iter().nth(index).map(|header| uncle_block_from_header(header).into()); - Ok(uncle) - } - - /// Returns all transaction receipts in the block. - /// - /// Returns `None` if the block wasn't found. - pub(crate) async fn block_receipts( - &self, - block_id: BlockId, - ) -> EthResult>> { - // Fetch block and receipts based on block_id - let block_and_receipts = if block_id.is_pending() { - self.provider() - .pending_block_and_receipts()? - .map(|(sb, receipts)| (sb, Arc::new(receipts))) - } else if let Some(block_hash) = self.provider().block_hash_for_id(block_id)? { - self.cache().get_block_and_receipts(block_hash).await? - } else { - None - }; - - // If no block and receipts found, return None - let Some((block, receipts)) = block_and_receipts else { - return Ok(None); - }; - - // Extract block details - let block_number = block.number; - let base_fee = block.base_fee_per_gas; - let block_hash = block.hash(); - let excess_blob_gas = block.excess_blob_gas; - let timestamp = block.timestamp; - let block = block.unseal(); - - #[cfg(feature = "optimism")] - let (block_timestamp, l1_block_info) = { - let body = reth_evm_optimism::extract_l1_info(&block); - (block.timestamp, body.ok()) - }; - - // Build transaction receipts - block - .body - .into_iter() - .zip(receipts.iter()) - .enumerate() - .map(|(idx, (tx, receipt))| { - let meta = TransactionMeta { - tx_hash: tx.hash, - index: idx as u64, - block_hash, - block_number, - base_fee, - excess_blob_gas, - timestamp, - }; - - #[cfg(feature = "optimism")] - let op_tx_meta = - self.build_op_tx_meta(&tx, l1_block_info.clone(), block_timestamp)?; - - build_transaction_receipt_with_block_receipts( - tx, - meta, - receipt.clone(), - &receipts, - #[cfg(feature = "optimism")] - op_tx_meta, - ) - }) - .collect::>>() - .map(Some) - } - - /// Returns the number transactions in the given block. - /// - /// Returns `None` if the block does not exist - pub(crate) async fn block_transaction_count( - &self, - block_id: impl Into, - ) -> EthResult> { - let block_id = block_id.into(); - - if block_id.is_pending() { - // Pending block can be fetched directly without need for caching - return Ok(self.provider().pending_block()?.map(|block| block.body.len())) - } - - let block_hash = match self.provider().block_hash_for_id(block_id)? { - Some(block_hash) => block_hash, - None => return Ok(None), - }; - - Ok(self.cache().get_block_transactions(block_hash).await?.map(|txs| txs.len())) - } - - /// Returns the block object for the given block id. - pub(crate) async fn block( - &self, - block_id: impl Into, - ) -> EthResult> { - self.block_with_senders(block_id) - .await - .map(|maybe_block| maybe_block.map(|block| block.block)) - } - - /// Returns the block object for the given block id. - pub(crate) async fn block_with_senders( - &self, - block_id: impl Into, - ) -> EthResult> { - let block_id = block_id.into(); - - if block_id.is_pending() { - // Pending block can be fetched directly without need for caching - let maybe_pending = self.provider().pending_block_with_senders()?; - return if maybe_pending.is_some() { - Ok(maybe_pending) - } else { - self.local_pending_block().await - } - } - - let block_hash = match self.provider().block_hash_for_id(block_id)? { - Some(block_hash) => block_hash, - None => return Ok(None), - }; - - Ok(self.cache().get_sealed_block_with_senders(block_hash).await?) - } - - /// Returns the populated rpc block object for the given block id. - /// - /// If `full` is true, the block object will contain all transaction objects, otherwise it will - /// only contain the transaction hashes. - pub(crate) async fn rpc_block( - &self, - block_id: impl Into, - full: bool, - ) -> EthResult> { - let block = match self.block_with_senders(block_id).await? { - Some(block) => block, - None => return Ok(None), - }; - let block_hash = block.hash(); - let total_difficulty = self - .provider() - .header_td_by_number(block.number)? - .ok_or(EthApiError::UnknownBlockNumber)?; - let block = from_block(block.unseal(), total_difficulty, full.into(), Some(block_hash))?; - Ok(Some(block.into())) - } - - /// Returns the block header for the given block id. - pub(crate) async fn rpc_block_header( - &self, - block_id: impl Into, - ) -> EthResult> { - let header = self.rpc_block(block_id, false).await?.map(|block| block.inner.header); - Ok(header) - } -} diff --git a/crates/rpc/rpc/src/eth/api/call.rs b/crates/rpc/rpc/src/eth/api/call.rs deleted file mode 100644 index 907065e476d4..000000000000 --- a/crates/rpc/rpc/src/eth/api/call.rs +++ /dev/null @@ -1,530 +0,0 @@ -//! Contains RPC handler implementations specific to endpoints that call/execute within evm. - -use crate::{ - eth::{ - error::{ensure_success, EthApiError, EthResult, RevertError, RpcInvalidTransactionError}, - revm_utils::{ - apply_state_overrides, build_call_evm_env, caller_gas_allowance, - cap_tx_gas_limit_with_caller_allowance, get_precompiles, prepare_call_env, - }, - EthTransactions, - }, - EthApi, -}; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, TxKind, U256}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProvider, StateProviderFactory, -}; -use reth_revm::database::StateProviderDatabase; -use reth_rpc_types::{ - state::{EvmOverrides, StateOverride}, - AccessListWithGasUsed, Bundle, EthCallResponse, StateContext, TransactionRequest, -}; -use reth_transaction_pool::TransactionPool; -use revm::{ - db::{CacheDB, DatabaseRef}, - primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ExecutionResult, HaltReason}, - DatabaseCommit, -}; -use revm_inspectors::access_list::AccessListInspector; -use tracing::trace; - -// Gas per transaction not creating a contract. -const MIN_TRANSACTION_GAS: u64 = 21_000u64; -/// Allowed error ratio for gas estimation -/// Taken from Geth's implementation in order to pass the hive tests -/// -const ESTIMATE_GAS_ERROR_RATIO: f64 = 0.015; - -impl EthApi -where - Pool: TransactionPool + Clone + 'static, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Estimate gas needed for execution of the `request` at the [`BlockId`]. - pub async fn estimate_gas_at( - &self, - request: TransactionRequest, - at: BlockId, - state_override: Option, - ) -> EthResult { - let (cfg, block_env, at) = self.evm_env_at(at).await?; - - self.on_blocking_task(|this| async move { - let state = this.state_at(at)?; - this.estimate_gas_with(cfg, block_env, request, state, state_override) - }) - .await - } - - /// Executes the call request (`eth_call`) and returns the output - pub async fn call( - &self, - request: TransactionRequest, - block_number: Option, - overrides: EvmOverrides, - ) -> EthResult { - let (res, _env) = - self.transact_call_at(request, block_number.unwrap_or_default(), overrides).await?; - - ensure_success(res.result) - } - - /// Simulate arbitrary number of transactions at an arbitrary blockchain index, with the - /// optionality of state overrides - pub async fn call_many( - &self, - bundle: Bundle, - state_context: Option, - mut state_override: Option, - ) -> EthResult> { - let Bundle { transactions, block_override } = bundle; - if transactions.is_empty() { - return Err(EthApiError::InvalidParams(String::from("transactions are empty."))) - } - - let StateContext { transaction_index, block_number } = state_context.unwrap_or_default(); - let transaction_index = transaction_index.unwrap_or_default(); - - let target_block = block_number.unwrap_or_default(); - let is_block_target_pending = target_block.is_pending(); - - let ((cfg, block_env, _), block) = futures::try_join!( - self.evm_env_at(target_block), - self.block_with_senders(target_block) - )?; - - let Some(block) = block else { return Err(EthApiError::UnknownBlockNumber) }; - let gas_limit = self.inner.gas_cap; - - // we're essentially replaying the transactions in the block here, hence we need the state - // that points to the beginning of the block, which is the state at the parent block - let mut at = block.parent_hash; - let mut replay_block_txs = true; - - let num_txs = transaction_index.index().unwrap_or(block.body.len()); - // but if all transactions are to be replayed, we can use the state at the block itself, - // however only if we're not targeting the pending block, because for pending we can't rely - // on the block's state being available - if !is_block_target_pending && num_txs == block.body.len() { - at = block.hash(); - replay_block_txs = false; - } - - let this = self.clone(); - self.spawn_with_state_at_block(at.into(), move |state| { - let mut results = Vec::with_capacity(transactions.len()); - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - if replay_block_txs { - // only need to replay the transactions in the block if not all transactions are - // to be replayed - let transactions = block.into_transactions_ecrecovered().take(num_txs); - for tx in transactions { - let tx = tx_env_with_recovered(&tx); - let env = - EnvWithHandlerCfg::new_with_cfg_env(cfg.clone(), block_env.clone(), tx); - let (res, _) = this.transact(&mut db, env)?; - db.commit(res.state); - } - } - - let block_overrides = block_override.map(Box::new); - - let mut transactions = transactions.into_iter().peekable(); - while let Some(tx) = transactions.next() { - // apply state overrides only once, before the first transaction - let state_overrides = state_override.take(); - let overrides = EvmOverrides::new(state_overrides, block_overrides.clone()); - - let env = prepare_call_env( - cfg.clone(), - block_env.clone(), - tx, - gas_limit, - &mut db, - overrides, - )?; - let (res, _) = this.transact(&mut db, env)?; - - match ensure_success(res.result) { - Ok(output) => { - results.push(EthCallResponse { value: Some(output), error: None }); - } - Err(err) => { - results.push(EthCallResponse { value: None, error: Some(err.to_string()) }); - } - } - - if transactions.peek().is_some() { - // need to apply the state changes of this call before executing the next call - db.commit(res.state); - } - } - - Ok(results) - }) - .await - } - - /// Estimates the gas usage of the `request` with the state. - /// - /// This will execute the [`TransactionRequest`] and find the best gas limit via binary search - pub fn estimate_gas_with( - &self, - mut cfg: CfgEnvWithHandlerCfg, - block: BlockEnv, - request: TransactionRequest, - state: S, - state_override: Option, - ) -> EthResult - where - S: StateProvider, - { - // Disabled because eth_estimateGas is sometimes used with eoa senders - // See - cfg.disable_eip3607 = true; - - // The basefee should be ignored for eth_createAccessList - // See: - // - cfg.disable_base_fee = true; - - // Keep a copy of gas related request values - let tx_request_gas_limit = request.gas; - let tx_request_gas_price = request.gas_price; - let block_env_gas_limit = block.gas_limit; - - // Determine the highest possible gas limit, considering both the request's specified limit - // and the block's limit. - let mut highest_gas_limit = tx_request_gas_limit - .map(|tx_gas_limit| U256::from(tx_gas_limit).max(block_env_gas_limit)) - .unwrap_or(block_env_gas_limit); - - // Configure the evm env - let mut env = build_call_evm_env(cfg, block, request)?; - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - // Apply any state overrides if specified. - if let Some(state_override) = state_override { - apply_state_overrides(state_override, &mut db)?; - } - - // Optimize for simple transfer transactions, potentially reducing the gas estimate. - if env.tx.data.is_empty() { - if let TxKind::Call(to) = env.tx.transact_to { - if let Ok(code) = db.db.account_code(to) { - let no_code_callee = code.map(|code| code.is_empty()).unwrap_or(true); - if no_code_callee { - // If the tx is a simple transfer (call to an account with no code) we can - // shortcircuit. But simply returning - // `MIN_TRANSACTION_GAS` is dangerous because there might be additional - // field combos that bump the price up, so we try executing the function - // with the minimum gas limit to make sure. - let mut env = env.clone(); - env.tx.gas_limit = MIN_TRANSACTION_GAS; - if let Ok((res, _)) = self.transact(&mut db, env) { - if res.result.is_success() { - return Ok(U256::from(MIN_TRANSACTION_GAS)) - } - } - } - } - } - } - - // Check funds of the sender (only useful to check if transaction gas price is more than 0). - // - // The caller allowance is check by doing `(account.balance - tx.value) / tx.gas_price` - if env.tx.gas_price > U256::ZERO { - // cap the highest gas limit by max gas caller can afford with given gas price - highest_gas_limit = highest_gas_limit.min(caller_gas_allowance(&mut db, &env.tx)?); - } - - // We can now normalize the highest gas limit to a u64 - let mut highest_gas_limit: u64 = highest_gas_limit.try_into().unwrap_or(u64::MAX); - - // If the provided gas limit is less than computed cap, use that - env.tx.gas_limit = env.tx.gas_limit.min(highest_gas_limit); - - trace!(target: "rpc::eth::estimate", ?env, "Starting gas estimation"); - - // Execute the transaction with the highest possible gas limit. - let (mut res, mut env) = match self.transact(&mut db, env.clone()) { - // Handle the exceptional case where the transaction initialization uses too much gas. - // If the gas price or gas limit was specified in the request, retry the transaction - // with the block's gas limit to determine if the failure was due to - // insufficient gas. - Err(EthApiError::InvalidTransaction(RpcInvalidTransactionError::GasTooHigh)) - if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() => - { - return Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) - } - // Propagate other results (successful or other errors). - ethres => ethres?, - }; - - let gas_refund = match res.result { - ExecutionResult::Success { gas_refunded, .. } => gas_refunded, - ExecutionResult::Halt { reason, gas_used } => { - // here we don't check for invalid opcode because already executed with highest gas - // limit - return Err(RpcInvalidTransactionError::halt(reason, gas_used).into()) - } - ExecutionResult::Revert { output, .. } => { - // if price or limit was included in the request then we can execute the request - // again with the block's gas limit to check if revert is gas related or not - return if tx_request_gas_limit.is_some() || tx_request_gas_price.is_some() { - Err(self.map_out_of_gas_err(block_env_gas_limit, env, &mut db)) - } else { - // the transaction did revert - Err(RpcInvalidTransactionError::Revert(RevertError::new(output)).into()) - } - } - }; - - // At this point we know the call succeeded but want to find the _best_ (lowest) gas the - // transaction succeeds with. We find this by doing a binary search over the possible range. - // - // NOTE: this is the gas the transaction used, which is less than the - // transaction requires to succeed. - let mut gas_used = res.result.gas_used(); - // the lowest value is capped by the gas used by the unconstrained transaction - let mut lowest_gas_limit = gas_used.saturating_sub(1); - - // As stated in Geth, there is a good chance that the transaction will pass if we set the - // gas limit to the execution gas used plus the gas refund, so we check this first - // 1 { - // An estimation error is allowed once the current gas limit range used in the binary - // search is small enough (less than 1.5% of the highest gas limit) - // { - // Increase the lowest gas limit if gas is too high - lowest_gas_limit = mid_gas_limit; - } - // Handle other cases, including successful transactions. - ethres => { - // Unpack the result and environment if the transaction was successful. - (res, env) = ethres?; - // Update the estimated gas range based on the transaction result. - update_estimated_gas_range( - res.result, - mid_gas_limit, - &mut highest_gas_limit, - &mut lowest_gas_limit, - )?; - } - } - - // New midpoint - mid_gas_limit = ((highest_gas_limit as u128 + lowest_gas_limit as u128) / 2) as u64; - } - - Ok(U256::from(highest_gas_limit)) - } - - /// Creates the `AccessList` for the `request` at the [`BlockId`] or latest. - pub(crate) async fn create_access_list_at( - &self, - request: TransactionRequest, - block_number: Option, - ) -> EthResult { - self.on_blocking_task(|this| async move { - this.create_access_list_with(request, block_number).await - }) - .await - } - - async fn create_access_list_with( - &self, - mut request: TransactionRequest, - at: Option, - ) -> EthResult { - let block_id = at.unwrap_or_default(); - let (cfg, block, at) = self.evm_env_at(block_id).await?; - let state = self.state_at(at)?; - - let mut env = build_call_evm_env(cfg, block, request.clone())?; - - // we want to disable this in eth_createAccessList, since this is common practice used by - // other node impls and providers - env.cfg.disable_block_gas_limit = true; - - // The basefee should be ignored for eth_createAccessList - // See: - // - env.cfg.disable_base_fee = true; - - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - if request.gas.is_none() && env.tx.gas_price > U256::ZERO { - // no gas limit was provided in the request, so we need to cap the request's gas limit - cap_tx_gas_limit_with_caller_allowance(&mut db, &mut env.tx)?; - } - - let from = request.from.unwrap_or_default(); - let to = if let Some(TxKind::Call(to)) = request.to { - to - } else { - let nonce = db.basic_ref(from)?.unwrap_or_default().nonce; - from.create(nonce) - }; - - // can consume the list since we're not using the request anymore - let initial = request.access_list.take().unwrap_or_default(); - - let precompiles = get_precompiles(env.handler_cfg.spec_id); - let mut inspector = AccessListInspector::new(initial, from, to, precompiles); - let (result, env) = self.inspect(&mut db, env, &mut inspector)?; - - match result.result { - ExecutionResult::Halt { reason, .. } => Err(match reason { - HaltReason::NonceOverflow => RpcInvalidTransactionError::NonceMaxValue, - halt => RpcInvalidTransactionError::EvmHalt(halt), - }), - ExecutionResult::Revert { output, .. } => { - Err(RpcInvalidTransactionError::Revert(RevertError::new(output))) - } - ExecutionResult::Success { .. } => Ok(()), - }?; - - let access_list = inspector.into_access_list(); - - let cfg_with_spec_id = - CfgEnvWithHandlerCfg { cfg_env: env.cfg.clone(), handler_cfg: env.handler_cfg }; - - // calculate the gas used using the access list - request.access_list = Some(access_list.clone()); - let gas_used = - self.estimate_gas_with(cfg_with_spec_id, env.block.clone(), request, &*db.db, None)?; - - Ok(AccessListWithGasUsed { access_list, gas_used }) - } - - /// Executes the requests again after an out of gas error to check if the error is gas related - /// or not - #[inline] - fn map_out_of_gas_err( - &self, - env_gas_limit: U256, - mut env: EnvWithHandlerCfg, - db: &mut CacheDB>, - ) -> EthApiError - where - S: StateProvider, - { - let req_gas_limit = env.tx.gas_limit; - env.tx.gas_limit = env_gas_limit.try_into().unwrap_or(u64::MAX); - let (res, _) = match self.transact(db, env) { - Ok(res) => res, - Err(err) => return err, - }; - match res.result { - ExecutionResult::Success { .. } => { - // transaction succeeded by manually increasing the gas limit to - // highest, which means the caller lacks funds to pay for the tx - RpcInvalidTransactionError::BasicOutOfGas(req_gas_limit).into() - } - ExecutionResult::Revert { output, .. } => { - // reverted again after bumping the limit - RpcInvalidTransactionError::Revert(RevertError::new(output)).into() - } - ExecutionResult::Halt { reason, .. } => { - RpcInvalidTransactionError::EvmHalt(reason).into() - } - } - } -} - -/// Updates the highest and lowest gas limits for binary search based on the execution result. -/// -/// This function refines the gas limit estimates used in a binary search to find the optimal gas -/// limit for a transaction. It adjusts the highest or lowest gas limits depending on whether the -/// execution succeeded, reverted, or halted due to specific reasons. -#[inline] -fn update_estimated_gas_range( - result: ExecutionResult, - tx_gas_limit: u64, - highest_gas_limit: &mut u64, - lowest_gas_limit: &mut u64, -) -> EthResult<()> { - match result { - ExecutionResult::Success { .. } => { - // Cap the highest gas limit with the succeeding gas limit. - *highest_gas_limit = tx_gas_limit; - } - ExecutionResult::Revert { .. } => { - // Increase the lowest gas limit. - *lowest_gas_limit = tx_gas_limit; - } - ExecutionResult::Halt { reason, .. } => { - match reason { - HaltReason::OutOfGas(_) | HaltReason::InvalidEFOpcode => { - // Both `OutOfGas` and `InvalidFEOpcode` can occur dynamically if the gas left - // is too low. Treat this as an out of gas condition, - // knowing that the call succeeds with a higher gas limit. - // - // Common usage of invalid opcode in OpenZeppelin: - // - - // Increase the lowest gas limit. - *lowest_gas_limit = tx_gas_limit; - } - err => { - // These cases should be unreachable because we know the transaction succeeds, - // but if they occur, treat them as an error. - return Err(RpcInvalidTransactionError::EvmHalt(err).into()) - } - } - } - }; - Ok(()) -} diff --git a/crates/rpc/rpc/src/eth/api/fees.rs b/crates/rpc/rpc/src/eth/api/fees.rs deleted file mode 100644 index 2493d6055778..000000000000 --- a/crates/rpc/rpc/src/eth/api/fees.rs +++ /dev/null @@ -1,228 +0,0 @@ -//! Contains RPC handler implementations for fee history. - -use crate::{ - eth::{ - api::fee_history::{calculate_reward_percentiles_for_block, FeeHistoryEntry}, - error::{EthApiError, EthResult}, - }, - EthApi, -}; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{BlockNumberOrTag, U256}; -use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; -use reth_rpc_types::FeeHistory; -use reth_transaction_pool::TransactionPool; -use tracing::debug; - -impl EthApi -where - Pool: TransactionPool + Clone + 'static, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Returns a suggestion for a gas price for legacy transactions. - /// - /// See also: - pub(crate) async fn gas_price(&self) -> EthResult { - let header = self.block(BlockNumberOrTag::Latest); - let suggested_tip = self.suggested_priority_fee(); - let (header, suggested_tip) = futures::try_join!(header, suggested_tip)?; - let base_fee = header.and_then(|h| h.base_fee_per_gas).unwrap_or_default(); - Ok(suggested_tip + U256::from(base_fee)) - } - - /// Returns a suggestion for a base fee for blob transactions. - pub(crate) async fn blob_base_fee(&self) -> EthResult { - self.block(BlockNumberOrTag::Latest) - .await? - .and_then(|h: reth_primitives::SealedBlock| h.next_block_blob_fee()) - .ok_or(EthApiError::ExcessBlobGasNotSet) - .map(U256::from) - } - - /// Returns a suggestion for the priority fee (the tip) - pub(crate) async fn suggested_priority_fee(&self) -> EthResult { - self.gas_oracle().suggest_tip_cap().await - } - - /// Reports the fee history, for the given amount of blocks, up until the given newest block. - /// - /// If `reward_percentiles` are provided the [`FeeHistory`] will include the _approximated_ - /// rewards for the requested range. - pub(crate) async fn fee_history( - &self, - mut block_count: u64, - newest_block: BlockNumberOrTag, - reward_percentiles: Option>, - ) -> EthResult { - if block_count == 0 { - return Ok(FeeHistory::default()) - } - - // See https://github.com/ethereum/go-ethereum/blob/2754b197c935ee63101cbbca2752338246384fec/eth/gasprice/feehistory.go#L218C8-L225 - let max_fee_history = if reward_percentiles.is_none() { - self.gas_oracle().config().max_header_history - } else { - self.gas_oracle().config().max_block_history - }; - - if block_count > max_fee_history { - debug!( - requested = block_count, - truncated = max_fee_history, - "Sanitizing fee history block count" - ); - block_count = max_fee_history - } - - let Some(end_block) = self.provider().block_number_for_id(newest_block.into())? else { - return Err(EthApiError::UnknownBlockNumber) - }; - - // need to add 1 to the end block to get the correct (inclusive) range - let end_block_plus = end_block + 1; - // Ensure that we would not be querying outside of genesis - if end_block_plus < block_count { - block_count = end_block_plus; - } - - // If reward percentiles were specified, we - // need to validate that they are monotonically - // increasing and 0 <= p <= 100 - // Note: The types used ensure that the percentiles are never < 0 - if let Some(percentiles) = &reward_percentiles { - if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) { - return Err(EthApiError::InvalidRewardPercentiles) - } - } - - // Fetch the headers and ensure we got all of them - // - // Treat a request for 1 block as a request for `newest_block..=newest_block`, - // otherwise `newest_block - 2 - // NOTE: We ensured that block count is capped - let start_block = end_block_plus - block_count; - - // Collect base fees, gas usage ratios and (optionally) reward percentile data - let mut base_fee_per_gas: Vec = Vec::new(); - let mut gas_used_ratio: Vec = Vec::new(); - - let mut base_fee_per_blob_gas: Vec = Vec::new(); - let mut blob_gas_used_ratio: Vec = Vec::new(); - - let mut rewards: Vec> = Vec::new(); - - // Check if the requested range is within the cache bounds - let fee_entries = self.fee_history_cache().get_history(start_block, end_block).await; - - if let Some(fee_entries) = fee_entries { - if fee_entries.len() != block_count as usize { - return Err(EthApiError::InvalidBlockRange) - } - - for entry in &fee_entries { - base_fee_per_gas.push(entry.base_fee_per_gas as u128); - gas_used_ratio.push(entry.gas_used_ratio); - base_fee_per_blob_gas.push(entry.base_fee_per_blob_gas.unwrap_or_default()); - blob_gas_used_ratio.push(entry.blob_gas_used_ratio); - - if let Some(percentiles) = &reward_percentiles { - let mut block_rewards = Vec::with_capacity(percentiles.len()); - for &percentile in percentiles { - block_rewards.push(self.approximate_percentile(entry, percentile)); - } - rewards.push(block_rewards); - } - } - let last_entry = fee_entries.last().expect("is not empty"); - - // Also need to include the `base_fee_per_gas` and `base_fee_per_blob_gas` for the next - // block - base_fee_per_gas - .push(last_entry.next_block_base_fee(&self.provider().chain_spec()) as u128); - - base_fee_per_blob_gas.push(last_entry.next_block_blob_fee().unwrap_or_default()); - } else { - // read the requested header range - let headers = self.provider().sealed_headers_range(start_block..=end_block)?; - if headers.len() != block_count as usize { - return Err(EthApiError::InvalidBlockRange) - } - - for header in &headers { - let ratio = if header.gas_limit > 0 {header.gas_used as f64 / header.gas_limit as f64} else {1.0}; - - base_fee_per_gas.push(header.base_fee_per_gas.unwrap_or_default() as u128); - gas_used_ratio.push(ratio); - base_fee_per_blob_gas.push(header.blob_fee().unwrap_or_default()); - blob_gas_used_ratio.push( - header.blob_gas_used.unwrap_or_default() as f64 / - reth_primitives::constants::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, - ); - - // Percentiles were specified, so we need to collect reward percentile ino - if let Some(percentiles) = &reward_percentiles { - let (transactions, receipts) = self - .cache() - .get_transactions_and_receipts(header.hash()) - .await? - .ok_or(EthApiError::InvalidBlockRange)?; - rewards.push( - calculate_reward_percentiles_for_block( - percentiles, - header.gas_used, - header.base_fee_per_gas.unwrap_or_default(), - &transactions, - &receipts, - ) - .unwrap_or_default(), - ); - } - } - - // The spec states that `base_fee_per_gas` "[..] includes the next block after the - // newest of the returned range, because this value can be derived from the - // newest block" - // - // The unwrap is safe since we checked earlier that we got at least 1 header. - let last_header = headers.last().expect("is present"); - base_fee_per_gas.push( - self.provider().chain_spec().base_fee_params_at_timestamp(last_header.timestamp).next_block_base_fee( - last_header.gas_used as u128, - last_header.gas_limit as u128, - last_header.base_fee_per_gas.unwrap_or_default() as u128, - )); - - // Same goes for the `base_fee_per_blob_gas`: - // > "[..] includes the next block after the newest of the returned range, because this value can be derived from the newest block. - base_fee_per_blob_gas - .push(last_header.next_block_blob_fee().unwrap_or_default()); - }; - - Ok(FeeHistory { - base_fee_per_gas, - gas_used_ratio, - base_fee_per_blob_gas, - blob_gas_used_ratio, - oldest_block: start_block, - reward: reward_percentiles.map(|_| rewards), - }) - } - - /// Approximates reward at a given percentile for a specific block - /// Based on the configured resolution - fn approximate_percentile(&self, entry: &FeeHistoryEntry, requested_percentile: f64) -> u128 { - let resolution = self.fee_history_cache().resolution(); - let rounded_percentile = - (requested_percentile * resolution as f64).round() / resolution as f64; - let clamped_percentile = rounded_percentile.clamp(0.0, 100.0); - - // Calculate the index in the precomputed rewards array - let index = (clamped_percentile / (1.0 / resolution as f64)).round() as usize; - // Fetch the reward from the FeeHistoryEntry - entry.rewards.get(index).cloned().unwrap_or_default() - } -} diff --git a/crates/rpc/rpc/src/eth/api/mod.rs b/crates/rpc/rpc/src/eth/api/mod.rs index 364a55842d3c..e69de29bb2d1 100644 --- a/crates/rpc/rpc/src/eth/api/mod.rs +++ b/crates/rpc/rpc/src/eth/api/mod.rs @@ -1,503 +0,0 @@ -//! The entire implementation of the namespace is quite large, hence it is divided across several -//! files. - -use crate::eth::{ - api::{ - fee_history::FeeHistoryCache, - pending_block::{PendingBlock, PendingBlockEnv, PendingBlockEnvOrigin}, - }, - cache::EthStateCache, - error::{EthApiError, EthResult}, - gas_oracle::GasPriceOracle, - signer::EthSigner, - traits::RawTransactionForwarder, -}; -use async_trait::async_trait; -use reth_chainspec::ChainInfo; -use reth_errors::{RethError, RethResult}; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{ - revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}, - Address, BlockId, BlockNumberOrTag, SealedBlockWithSenders, SealedHeader, B256, U256, U64, -}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory, -}; -use reth_rpc_types::{SyncInfo, SyncStatus}; -use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor}; -use reth_transaction_pool::TransactionPool; -use revm_primitives::{CfgEnv, SpecId}; -use std::{ - fmt::Debug, - future::Future, - sync::Arc, - time::{Duration, Instant}, -}; -use tokio::sync::{oneshot, Mutex}; - -mod block; -mod call; -pub(crate) mod fee_history; - -mod fees; -#[cfg(feature = "optimism")] -mod optimism; -mod pending_block; -mod server; -mod sign; -mod state; -mod transactions; - -pub use transactions::{EthTransactions, TransactionSource}; - -/// `Eth` API trait. -/// -/// Defines core functionality of the `eth` API implementation. -#[async_trait] -pub trait EthApiSpec: EthTransactions + Send + Sync { - /// Returns the current ethereum protocol version. - async fn protocol_version(&self) -> RethResult; - - /// Returns the chain id - fn chain_id(&self) -> U64; - - /// Returns provider chain info - fn chain_info(&self) -> RethResult; - - /// Returns a list of addresses owned by provider. - fn accounts(&self) -> Vec
; - - /// Returns `true` if the network is undergoing sync. - fn is_syncing(&self) -> bool; - - /// Returns the [SyncStatus] of the network - fn sync_status(&self) -> RethResult; -} - -/// `Eth` API implementation. -/// -/// This type provides the functionality for handling `eth_` related requests. -/// These are implemented two-fold: Core functionality is implemented as [`EthApiSpec`] -/// trait. Additionally, the required server implementations (e.g. [`reth_rpc_api::EthApiServer`]) -/// are implemented separately in submodules. The rpc handler implementation can then delegate to -/// the main impls. This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone -/// or in other network handlers (for example ipc). -pub struct EthApi { - /// All nested fields bundled together. - inner: Arc>, -} - -impl EthApi { - /// Sets a forwarder for `eth_sendRawTransaction` - /// - /// Note: this might be removed in the future in favor of a more generic approach. - pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { - self.inner.raw_transaction_forwarder.write().replace(forwarder); - } -} - -impl EthApi -where - Provider: BlockReaderIdExt + ChainSpecProvider, -{ - /// Creates a new, shareable instance using the default tokio task spawner. - #[allow(clippy::too_many_arguments)] - pub fn new( - provider: Provider, - pool: Pool, - network: Network, - eth_cache: EthStateCache, - gas_oracle: GasPriceOracle, - gas_cap: impl Into, - blocking_task_pool: BlockingTaskPool, - fee_history_cache: FeeHistoryCache, - evm_config: EvmConfig, - raw_transaction_forwarder: Option>, - ) -> Self { - Self::with_spawner( - provider, - pool, - network, - eth_cache, - gas_oracle, - gas_cap.into().into(), - Box::::default(), - blocking_task_pool, - fee_history_cache, - evm_config, - raw_transaction_forwarder, - ) - } - - /// Creates a new, shareable instance. - #[allow(clippy::too_many_arguments)] - pub fn with_spawner( - provider: Provider, - pool: Pool, - network: Network, - eth_cache: EthStateCache, - gas_oracle: GasPriceOracle, - gas_cap: u64, - task_spawner: Box, - blocking_task_pool: BlockingTaskPool, - fee_history_cache: FeeHistoryCache, - evm_config: EvmConfig, - raw_transaction_forwarder: Option>, - ) -> Self { - // get the block number of the latest block - let latest_block = provider - .header_by_number_or_tag(BlockNumberOrTag::Latest) - .ok() - .flatten() - .map(|header| header.number) - .unwrap_or_default(); - - let inner = EthApiInner { - provider, - pool, - network, - signers: parking_lot::RwLock::new(Default::default()), - eth_cache, - gas_oracle, - gas_cap, - starting_block: U256::from(latest_block), - task_spawner, - pending_block: Default::default(), - blocking_task_pool, - fee_history_cache, - evm_config, - raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder), - }; - - Self { inner: Arc::new(inner) } - } - - /// Executes the future on a new blocking task. - /// - /// This accepts a closure that creates a new future using a clone of this type and spawns the - /// future onto a new task that is allowed to block. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations. - pub(crate) async fn on_blocking_task(&self, c: C) -> EthResult - where - C: FnOnce(Self) -> F, - F: Future> + Send + 'static, - R: Send + 'static, - { - let (tx, rx) = oneshot::channel(); - let this = self.clone(); - let f = c(this); - self.inner.task_spawner.spawn_blocking(Box::pin(async move { - let res = f.await; - let _ = tx.send(res); - })); - rx.await.map_err(|_| EthApiError::InternalEthError)? - } - - /// Returns the state cache frontend - pub(crate) fn cache(&self) -> &EthStateCache { - &self.inner.eth_cache - } - - /// Returns the gas oracle frontend - pub(crate) fn gas_oracle(&self) -> &GasPriceOracle { - &self.inner.gas_oracle - } - - /// Returns the configured gas limit cap for `eth_call` and tracing related calls - pub fn gas_cap(&self) -> u64 { - self.inner.gas_cap - } - - /// Returns the inner `Provider` - pub fn provider(&self) -> &Provider { - &self.inner.provider - } - - /// Returns the inner `Network` - pub fn network(&self) -> &Network { - &self.inner.network - } - - /// Returns the inner `Pool` - pub fn pool(&self) -> &Pool { - &self.inner.pool - } - - /// Returns fee history cache - pub fn fee_history_cache(&self) -> &FeeHistoryCache { - &self.inner.fee_history_cache - } -} - -// === State access helpers === - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, -{ - /// Returns the state at the given [`BlockId`] enum. - /// - /// Note: if not [`BlockNumberOrTag::Pending`] then this will only return canonical state. See also - pub fn state_at_block_id(&self, at: BlockId) -> EthResult { - Ok(self.provider().state_by_block_id(at)?) - } - - /// Returns the state at the given [`BlockId`] enum or the latest. - /// - /// Convenience function to interprets `None` as `BlockId::Number(BlockNumberOrTag::Latest)` - pub fn state_at_block_id_or_latest( - &self, - block_id: Option, - ) -> EthResult { - if let Some(block_id) = block_id { - self.state_at_block_id(block_id) - } else { - Ok(self.latest_state()?) - } - } - - /// Returns the state at the given block number - pub fn state_at_hash(&self, block_hash: B256) -> RethResult { - Ok(self.provider().history_by_block_hash(block_hash)?) - } - - /// Returns the _latest_ state - pub fn latest_state(&self) -> RethResult { - Ok(self.provider().latest()?) - } -} - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + Clone + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + Clone + 'static, -{ - /// Configures the [`CfgEnvWithHandlerCfg`] and [`BlockEnv`] for the pending block - /// - /// If no pending block is available, this will derive it from the `latest` block - pub(crate) fn pending_block_env_and_cfg(&self) -> EthResult { - let origin: PendingBlockEnvOrigin = if let Some(pending) = - self.provider().pending_block_with_senders()? - { - PendingBlockEnvOrigin::ActualPending(pending) - } else { - // no pending block from the CL yet, so we use the latest block and modify the env - // values that we can - let latest = - self.provider().latest_header()?.ok_or_else(|| EthApiError::UnknownBlockNumber)?; - - let (mut latest_header, block_hash) = latest.split(); - // child block - latest_header.number += 1; - // assumed child block is in the next slot: 12s - latest_header.timestamp += 12; - // base fee of the child block - let chain_spec = self.provider().chain_spec(); - - latest_header.base_fee_per_gas = latest_header.next_block_base_fee( - chain_spec.base_fee_params_at_timestamp(latest_header.timestamp), - ); - - // update excess blob gas consumed above target - latest_header.excess_blob_gas = latest_header.next_block_excess_blob_gas(); - - // we're reusing the same block hash because we need this to lookup the block's state - let latest = SealedHeader::new(latest_header, block_hash); - - PendingBlockEnvOrigin::DerivedFromLatest(latest) - }; - - let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); - - let mut block_env = BlockEnv::default(); - // Note: for the PENDING block we assume it is past the known merge block and thus this will - // not fail when looking up the total difficulty value for the blockenv. - self.provider().fill_env_with_header( - &mut cfg, - &mut block_env, - origin.header(), - self.inner.evm_config.clone(), - )?; - - Ok(PendingBlockEnv { cfg, block_env, origin }) - } - - /// Returns the locally built pending block - pub(crate) async fn local_pending_block(&self) -> EthResult> { - let pending = self.pending_block_env_and_cfg()?; - if pending.origin.is_actual_pending() { - return Ok(pending.origin.into_actual_pending()) - } - - // no pending block from the CL yet, so we need to build it ourselves via txpool - self.on_blocking_task(|this| async move { - let mut lock = this.inner.pending_block.lock().await; - let now = Instant::now(); - - // check if the block is still good - if let Some(pending_block) = lock.as_ref() { - // this is guaranteed to be the `latest` header - if pending.block_env.number.to::() == pending_block.block.number && - pending.origin.header().hash() == pending_block.block.parent_hash && - now <= pending_block.expires_at - { - return Ok(Some(pending_block.block.clone())) - } - } - - // we rebuild the block - let pending_block = match pending.build_block(this.provider(), this.pool()) { - Ok(block) => block, - Err(err) => { - tracing::debug!(target: "rpc", "Failed to build pending block: {:?}", err); - return Ok(None) - } - }; - - let now = Instant::now(); - *lock = Some(PendingBlock { - block: pending_block.clone(), - expires_at: now + Duration::from_secs(1), - }); - - Ok(Some(pending_block)) - }) - .await - } -} - -impl std::fmt::Debug - for EthApi -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("EthApi").finish_non_exhaustive() - } -} - -impl Clone for EthApi { - fn clone(&self) -> Self { - Self { inner: Arc::clone(&self.inner) } - } -} - -#[async_trait] -impl EthApiSpec for EthApi -where - Pool: TransactionPool + Clone + 'static, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: NetworkInfo + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Returns the current ethereum protocol version. - /// - /// Note: This returns an `U64`, since this should return as hex string. - async fn protocol_version(&self) -> RethResult { - let status = self.network().network_status().await.map_err(RethError::other)?; - Ok(U64::from(status.protocol_version)) - } - - /// Returns the chain id - fn chain_id(&self) -> U64 { - U64::from(self.network().chain_id()) - } - - /// Returns the current info for the chain - fn chain_info(&self) -> RethResult { - Ok(self.provider().chain_info()?) - } - - fn accounts(&self) -> Vec
{ - self.inner.signers.read().iter().flat_map(|s| s.accounts()).collect() - } - - fn is_syncing(&self) -> bool { - self.network().is_syncing() - } - - /// Returns the [SyncStatus] of the network - fn sync_status(&self) -> RethResult { - let status = if self.is_syncing() { - let current_block = U256::from( - self.provider().chain_info().map(|info| info.best_number).unwrap_or_default(), - ); - SyncStatus::Info(SyncInfo { - starting_block: self.inner.starting_block, - current_block, - highest_block: current_block, - warp_chunks_amount: None, - warp_chunks_processed: None, - }) - } else { - SyncStatus::None - }; - Ok(status) - } -} - -/// The default gas limit for `eth_call` and adjacent calls. -/// -/// This is different from the default to regular 30M block gas limit -/// [`ETHEREUM_BLOCK_GAS_LIMIT`](reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT) to allow for -/// more complex calls. -pub const RPC_DEFAULT_GAS_CAP: GasCap = GasCap(50_000_000); - -/// The wrapper type for gas limit -#[derive(Debug, Clone, Copy)] -pub struct GasCap(u64); - -impl Default for GasCap { - fn default() -> Self { - RPC_DEFAULT_GAS_CAP - } -} - -impl From for GasCap { - fn from(gas_cap: u64) -> Self { - Self(gas_cap) - } -} - -impl From for u64 { - fn from(gas_cap: GasCap) -> Self { - gas_cap.0 - } -} - -/// Container type `EthApi` -struct EthApiInner { - /// The transaction pool. - pool: Pool, - /// The provider that can interact with the chain. - provider: Provider, - /// An interface to interact with the network - network: Network, - /// All configured Signers - signers: parking_lot::RwLock>>, - /// The async cache frontend for eth related data - eth_cache: EthStateCache, - /// The async gas oracle frontend for gas price suggestions - gas_oracle: GasPriceOracle, - /// Maximum gas limit for `eth_call` and call tracing RPC methods. - gas_cap: u64, - /// The block number at which the node started - starting_block: U256, - /// The type that can spawn tasks which would otherwise block. - task_spawner: Box, - /// Cached pending block if any - pending_block: Mutex>, - /// A pool dedicated to blocking tasks. - blocking_task_pool: BlockingTaskPool, - /// Cache for block fees history - fee_history_cache: FeeHistoryCache, - /// The type that defines how to configure the EVM - evm_config: EvmConfig, - /// Allows forwarding received raw transactions - raw_transaction_forwarder: parking_lot::RwLock>>, -} diff --git a/crates/rpc/rpc/src/eth/api/optimism.rs b/crates/rpc/rpc/src/eth/api/optimism.rs deleted file mode 100644 index af58450145b8..000000000000 --- a/crates/rpc/rpc/src/eth/api/optimism.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Optimism helpers. - -use revm::L1BlockInfo; - -/// Optimism Transaction Metadata -/// -/// Includes the L1 fee and data gas for the tx along with the L1 -/// block info. In order to pass the [`OptimismTxMeta`] into the -/// async colored `build_transaction_receipt_with_block_receipts` -/// function, a reference counter for the L1 block info is -/// used so the L1 block info can be shared between receipts. -#[derive(Debug, Default, Clone)] -pub(crate) struct OptimismTxMeta { - /// The L1 block info. - pub(crate) l1_block_info: Option, - /// The L1 fee for the block. - pub(crate) l1_fee: Option, - /// The L1 data gas for the block. - pub(crate) l1_data_gas: Option, -} - -impl OptimismTxMeta { - /// Creates a new [`OptimismTxMeta`]. - pub(crate) const fn new( - l1_block_info: Option, - l1_fee: Option, - l1_data_gas: Option, - ) -> Self { - Self { l1_block_info, l1_fee, l1_data_gas } - } -} diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index f238b4da079a..e69de29bb2d1 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -1,723 +0,0 @@ -//! Implementation of the [`jsonrpsee`] generated [`reth_rpc_api::EthApiServer`] trait -//! Handles RPC requests for the `eth_` namespace. - -use super::EthApiSpec; -use crate::{ - eth::{ - api::{EthApi, EthTransactions}, - error::EthApiError, - }, - result::{internal_rpc_err, ToRpcResult}, -}; -use alloy_dyn_abi::TypedData; -use jsonrpsee::core::RpcResult as Result; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64}; -use reth_provider::{ - BlockIdReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, - HeaderProvider, StateProviderFactory, -}; -use reth_rpc_api::EthApiServer; -use reth_rpc_types::{ - serde_helpers::JsonStorageKey, - state::{EvmOverrides, StateOverride}, - AccessListWithGasUsed, AnyTransactionReceipt, BlockOverrides, Bundle, - EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Header, Index, RichBlock, - StateContext, SyncStatus, TransactionRequest, Work, -}; -use reth_transaction_pool::TransactionPool; -use tracing::trace; - -#[async_trait::async_trait] -impl EthApiServer for EthApi -where - Self: EthApiSpec + EthTransactions, - Pool: TransactionPool + 'static, - Provider: BlockReader - + BlockIdReader - + BlockReaderIdExt - + ChainSpecProvider - + HeaderProvider - + StateProviderFactory - + EvmEnvProvider - + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Handler for: `eth_protocolVersion` - async fn protocol_version(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_protocolVersion"); - EthApiSpec::protocol_version(self).await.to_rpc_result() - } - - /// Handler for: `eth_syncing` - fn syncing(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_syncing"); - EthApiSpec::sync_status(self).to_rpc_result() - } - - /// Handler for: `eth_coinbase` - async fn author(&self) -> Result
{ - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_accounts` - fn accounts(&self) -> Result> { - trace!(target: "rpc::eth", "Serving eth_accounts"); - Ok(EthApiSpec::accounts(self)) - } - - /// Handler for: `eth_blockNumber` - fn block_number(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_blockNumber"); - Ok(U256::from( - EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number, - )) - } - - /// Handler for: `eth_chainId` - async fn chain_id(&self) -> Result> { - trace!(target: "rpc::eth", "Serving eth_chainId"); - Ok(Some(EthApiSpec::chain_id(self))) - } - - /// Handler for: `eth_getBlockByHash` - async fn block_by_hash(&self, hash: B256, full: bool) -> Result> { - trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash"); - Ok(Self::rpc_block(self, hash, full).await?) - } - - /// Handler for: `eth_getBlockByNumber` - async fn block_by_number( - &self, - number: BlockNumberOrTag, - full: bool, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber"); - Ok(Self::rpc_block(self, number, full).await?) - } - - /// Handler for: `eth_getBlockTransactionCountByHash` - async fn block_transaction_count_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash"); - Ok(Self::block_transaction_count(self, hash).await?.map(U256::from)) - } - - /// Handler for: `eth_getBlockTransactionCountByNumber` - async fn block_transaction_count_by_number( - &self, - number: BlockNumberOrTag, - ) -> Result> { - trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber"); - Ok(Self::block_transaction_count(self, number).await?.map(U256::from)) - } - - /// Handler for: `eth_getUncleCountByBlockHash` - async fn block_uncles_count_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash"); - Ok(Self::ommers(self, hash)?.map(|ommers| U256::from(ommers.len()))) - } - - /// Handler for: `eth_getUncleCountByBlockNumber` - async fn block_uncles_count_by_number(&self, number: BlockNumberOrTag) -> Result> { - trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber"); - Ok(Self::ommers(self, number)?.map(|ommers| U256::from(ommers.len()))) - } - - /// Handler for: `eth_getBlockReceipts` - async fn block_receipts( - &self, - block_id: BlockId, - ) -> Result>> { - trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts"); - Ok(Self::block_receipts(self, block_id).await?) - } - - /// Handler for: `eth_getUncleByBlockHashAndIndex` - async fn uncle_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex"); - Ok(Self::ommer_by_block_and_index(self, hash, index).await?) - } - - /// Handler for: `eth_getUncleByBlockNumberAndIndex` - async fn uncle_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex"); - Ok(Self::ommer_by_block_and_index(self, number, index).await?) - } - - /// Handler for: `eth_getRawTransactionByHash` - async fn raw_transaction_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash"); - Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?) - } - - /// Handler for: `eth_getTransactionByHash` - async fn transaction_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash"); - Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into)) - } - - /// Handler for: `eth_getRawTransactionByBlockHashAndIndex` - async fn raw_transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex"); - Ok(Self::raw_transaction_by_block_and_tx_index(self, hash, index).await?) - } - - /// Handler for: `eth_getTransactionByBlockHashAndIndex` - async fn transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex"); - Ok(Self::transaction_by_block_and_tx_index(self, hash, index).await?) - } - - /// Handler for: `eth_getRawTransactionByBlockNumberAndIndex` - async fn raw_transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex"); - Ok(Self::raw_transaction_by_block_and_tx_index(self, number, index).await?) - } - - /// Handler for: `eth_getTransactionByBlockNumberAndIndex` - async fn transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex"); - Ok(Self::transaction_by_block_and_tx_index(self, number, index).await?) - } - - /// Handler for: `eth_getTransactionReceipt` - async fn transaction_receipt(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt"); - Ok(EthTransactions::transaction_receipt(self, hash).await?) - } - - /// Handler for: `eth_getBalance` - async fn balance(&self, address: Address, block_number: Option) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(self.on_blocking_task(|this| async move { this.balance(address, block_number) }).await?) - } - - /// Handler for: `eth_getStorageAt` - async fn storage_at( - &self, - address: Address, - index: JsonStorageKey, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - Ok(self - .on_blocking_task(|this| async move { this.storage_at(address, index, block_number) }) - .await?) - } - - /// Handler for: `eth_getTransactionCount` - async fn transaction_count( - &self, - address: Address, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(self - .on_blocking_task( - |this| async move { this.get_transaction_count(address, block_number) }, - ) - .await?) - } - - /// Handler for: `eth_getCode` - async fn get_code(&self, address: Address, block_number: Option) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(self - .on_blocking_task(|this| async move { this.get_code(address, block_number) }) - .await?) - } - - /// Handler for: `eth_getHeaderByNumber` - async fn header_by_number(&self, block_number: BlockNumberOrTag) -> Result> { - trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); - Ok(Self::rpc_block_header(self, block_number).await?) - } - - /// Handler for: `eth_getHeaderByHash` - async fn header_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash"); - Ok(Self::rpc_block_header(self, hash).await?) - } - - /// Handler for: `eth_call` - async fn call( - &self, - request: TransactionRequest, - block_number: Option, - state_overrides: Option, - block_overrides: Option>, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call"); - Ok(self - .call(request, block_number, EvmOverrides::new(state_overrides, block_overrides)) - .await?) - } - - /// Handler for: `eth_callMany` - async fn call_many( - &self, - bundle: Bundle, - state_context: Option, - state_override: Option, - ) -> Result> { - trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany"); - Ok(Self::call_many(self, bundle, state_context, state_override).await?) - } - - /// Handler for: `eth_createAccessList` - async fn create_access_list( - &self, - request: TransactionRequest, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList"); - let access_list_with_gas_used = self.create_access_list_at(request, block_number).await?; - - Ok(access_list_with_gas_used) - } - - /// Handler for: `eth_estimateGas` - async fn estimate_gas( - &self, - request: TransactionRequest, - block_number: Option, - state_override: Option, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas"); - Ok(self.estimate_gas_at(request, block_number.unwrap_or_default(), state_override).await?) - } - - /// Handler for: `eth_gasPrice` - async fn gas_price(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_gasPrice"); - return Ok(Self::gas_price(self).await?) - } - - /// Handler for: `eth_maxPriorityFeePerGas` - async fn max_priority_fee_per_gas(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas"); - return Ok(Self::suggested_priority_fee(self).await?) - } - - /// Handler for: `eth_blobBaseFee` - async fn blob_base_fee(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_blobBaseFee"); - return Ok(Self::blob_base_fee(self).await?) - } - - // FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further - // caching of it in the LRU cache. - // When new RPC call is executed, the cache gets locked, we check it for the historical fees - // according to the requested block range, and fill any cache misses (in both RPC response - // and cache itself) with the actual data queried from the database. - // To minimize the number of database seeks required to query the missing data, we calculate the - // first non-cached block number and last non-cached block number. After that, we query this - // range of consecutive blocks from the database. - /// Handler for: `eth_feeHistory` - async fn fee_history( - &self, - block_count: U64, - newest_block: BlockNumberOrTag, - reward_percentiles: Option>, - ) -> Result { - trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory"); - return Ok(Self::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?) - } - - /// Handler for: `eth_mining` - async fn is_mining(&self) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_hashrate` - async fn hashrate(&self) -> Result { - Ok(U256::ZERO) - } - - /// Handler for: `eth_getWork` - async fn get_work(&self) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_submitHashrate` - async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> Result { - Ok(false) - } - - /// Handler for: `eth_submitWork` - async fn submit_work(&self, _nonce: B64, _pow_hash: B256, _mix_digest: B256) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_sendTransaction` - async fn send_transaction(&self, request: TransactionRequest) -> Result { - trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction"); - Ok(EthTransactions::send_transaction(self, request).await?) - } - - /// Handler for: `eth_sendRawTransaction` - async fn send_raw_transaction(&self, tx: Bytes) -> Result { - trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction"); - Ok(EthTransactions::send_raw_transaction(self, tx).await?) - } - - /// Handler for: `eth_sign` - async fn sign(&self, address: Address, message: Bytes) -> Result { - trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign"); - Ok(Self::sign(self, address, &message).await?) - } - - /// Handler for: `eth_signTransaction` - async fn sign_transaction(&self, _transaction: TransactionRequest) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_signTypedData` - async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result { - trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData"); - Ok(Self::sign_typed_data(self, &data, address)?) - } - - /// Handler for: `eth_getProof` - async fn get_proof( - &self, - address: Address, - keys: Vec, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); - let res = Self::get_proof(self, address, keys, block_number).await; - - Ok(res.map_err(|e| match e { - EthApiError::InvalidBlockRange => { - internal_rpc_err("eth_getProof is unimplemented for historical blocks") - } - _ => e.into(), - })?) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - eth::{ - cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, - FeeHistoryCacheConfig, - }, - EthApi, - }; - use jsonrpsee::types::error::INVALID_PARAMS_CODE; - use reth_chainspec::BaseFeeParams; - use reth_evm_ethereum::EthEvmConfig; - use reth_network_api::noop::NoopNetwork; - use reth_primitives::{ - constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned, - B256, U64, - }; - use reth_provider::{ - test_utils::{MockEthProvider, NoopProvider}, - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, - }; - use reth_rpc_api::EthApiServer; - use reth_rpc_types::FeeHistory; - use reth_tasks::pool::BlockingTaskPool; - use reth_testing_utils::{generators, generators::Rng}; - use reth_transaction_pool::test_utils::{testing_pool, TestPool}; - - fn build_test_eth_api< - P: BlockReaderIdExt - + BlockReader - + ChainSpecProvider - + EvmEnvProvider - + StateProviderFactory - + Unpin - + Clone - + 'static, - >( - provider: P, - ) -> EthApi { - let evm_config = EthEvmConfig::default(); - let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config); - let fee_history_cache = - FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); - - EthApi::new( - provider.clone(), - testing_pool(), - NoopNetwork::default(), - cache.clone(), - GasPriceOracle::new(provider, Default::default(), cache), - ETHEREUM_BLOCK_GAS_LIMIT, - BlockingTaskPool::build().expect("failed to build tracing pool"), - fee_history_cache, - evm_config, - None, - ) - } - - // Function to prepare the EthApi with mock data - fn prepare_eth_api( - newest_block: u64, - mut oldest_block: Option, - block_count: u64, - mock_provider: MockEthProvider, - ) -> (EthApi, Vec, Vec) { - let mut rng = generators::rng(); - - // Build mock data - let mut gas_used_ratios = Vec::new(); - let mut base_fees_per_gas = Vec::new(); - let mut last_header = None; - let mut parent_hash = B256::default(); - - for i in (0..block_count).rev() { - let hash = rng.gen(); - let gas_limit: u64 = rng.gen(); - let gas_used: u64 = rng.gen(); - // Note: Generates a u32 to avoid overflows later - let base_fee_per_gas: Option = rng.gen::().then(|| rng.gen::() as u64); - - let header = Header { - number: newest_block - i, - gas_limit, - gas_used, - base_fee_per_gas, - parent_hash, - ..Default::default() - }; - last_header = Some(header.clone()); - parent_hash = hash; - - let mut transactions = vec![]; - for _ in 0..100 { - let random_fee: u128 = rng.gen(); - - if let Some(base_fee_per_gas) = header.base_fee_per_gas { - let transaction = TransactionSigned { - transaction: reth_primitives::Transaction::Eip1559( - reth_primitives::TxEip1559 { - max_priority_fee_per_gas: random_fee, - max_fee_per_gas: random_fee + base_fee_per_gas as u128, - ..Default::default() - }, - ), - ..Default::default() - }; - - transactions.push(transaction); - } else { - let transaction = TransactionSigned { - transaction: reth_primitives::Transaction::Legacy(Default::default()), - ..Default::default() - }; - - transactions.push(transaction); - } - } - - mock_provider.add_block( - hash, - Block { header: header.clone(), body: transactions, ..Default::default() }, - ); - mock_provider.add_header(hash, header); - - oldest_block.get_or_insert(hash); - gas_used_ratios.push(gas_used as f64 / gas_limit as f64); - base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default()); - } - - // Add final base fee (for the next block outside of the request) - let last_header = last_header.unwrap(); - base_fees_per_gas.push(BaseFeeParams::ethereum().next_block_base_fee( - last_header.gas_used as u128, - last_header.gas_limit as u128, - last_header.base_fee_per_gas.unwrap_or_default() as u128, - )); - - let eth_api = build_test_eth_api(mock_provider); - - (eth_api, base_fees_per_gas, gas_used_ratios) - } - - /// Invalid block range - #[tokio::test] - async fn test_fee_history_empty() { - let response = as EthApiServer>::fee_history( - &build_test_eth_api(NoopProvider::default()), - U64::from(1), - BlockNumberOrTag::Latest, - None, - ) - .await; - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Invalid block range (request is before genesis) - async fn test_fee_history_invalid_block_range_before_genesis() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - U64::from(newest_block + 1), - newest_block.into(), - Some(vec![10.0]), - ) - .await; - - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Invalid block range (request is in the future) - async fn test_fee_history_invalid_block_range_in_future() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - U64::from(1), - (newest_block + 1000).into(), - Some(vec![10.0]), - ) - .await; - - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Requesting no block should result in a default response - async fn test_fee_history_no_block_requested() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - U64::from(0), - newest_block.into(), - None, - ) - .await - .unwrap(); - assert_eq!( - response, - FeeHistory::default(), - "none: requesting no block should yield a default response" - ); - } - - #[tokio::test] - /// Requesting a single block should return 1 block (+ base fee for the next block over) - async fn test_fee_history_single_block() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, base_fees_per_gas, gas_used_ratios) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let fee_history = eth_api.fee_history(1, newest_block.into(), None).await.unwrap(); - assert_eq!( - fee_history.base_fee_per_gas, - &base_fees_per_gas[base_fees_per_gas.len() - 2..], - "one: base fee per gas is incorrect" - ); - assert_eq!( - fee_history.base_fee_per_gas.len(), - 2, - "one: should return base fee of the next block as well" - ); - assert_eq!( - &fee_history.gas_used_ratio, - &gas_used_ratios[gas_used_ratios.len() - 1..], - "one: gas used ratio is incorrect" - ); - assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect"); - assert!( - fee_history.reward.is_none(), - "one: no percentiles were requested, so there should be no rewards result" - ); - } - - /// Requesting all blocks should be ok - #[tokio::test] - async fn test_fee_history_all_blocks() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, base_fees_per_gas, gas_used_ratios) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let fee_history = - eth_api.fee_history(block_count, newest_block.into(), None).await.unwrap(); - - assert_eq!( - &fee_history.base_fee_per_gas, &base_fees_per_gas, - "all: base fee per gas is incorrect" - ); - assert_eq!( - fee_history.base_fee_per_gas.len() as u64, - block_count + 1, - "all: should return base fee of the next block as well" - ); - assert_eq!( - &fee_history.gas_used_ratio, &gas_used_ratios, - "all: gas used ratio is incorrect" - ); - assert_eq!( - fee_history.oldest_block, - newest_block - block_count + 1, - "all: oldest block is incorrect" - ); - assert!( - fee_history.reward.is_none(), - "all: no percentiles were requested, so there should be no rewards result" - ); - } -} diff --git a/crates/rpc/rpc/src/eth/api/sign.rs b/crates/rpc/rpc/src/eth/api/sign.rs deleted file mode 100644 index 5256de4a4dae..000000000000 --- a/crates/rpc/rpc/src/eth/api/sign.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Contains RPC handler implementations specific to sign endpoints - -use crate::{ - eth::{ - error::{EthResult, SignError}, - signer::{DevSigner, EthSigner}, - }, - EthApi, -}; -use alloy_dyn_abi::TypedData; -use reth_primitives::{Address, Bytes}; - -impl EthApi { - pub(crate) async fn sign(&self, account: Address, message: &[u8]) -> EthResult { - Ok(self.find_signer(&account)?.sign(account, message).await?.to_hex_bytes()) - } - - pub(crate) fn sign_typed_data(&self, data: &TypedData, account: Address) -> EthResult { - Ok(self.find_signer(&account)?.sign_typed_data(account, data)?.to_hex_bytes()) - } - - pub(crate) fn find_signer( - &self, - account: &Address, - ) -> Result, SignError> { - self.inner - .signers - .read() - .iter() - .find(|signer| signer.is_signer_for(account)) - .map(|signer| dyn_clone::clone_box(&**signer)) - .ok_or(SignError::NoAccount) - } - - /// Generates 20 random developer accounts. - /// Used in DEV mode. - pub fn with_dev_accounts(&self) { - let mut signers = self.inner.signers.write(); - *signers = DevSigner::random_signers(20); - } -} diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs deleted file mode 100644 index d7c1bafacf9f..000000000000 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Contains RPC handler implementations specific to state. - -use crate::{ - eth::error::{EthApiError, EthResult, RpcInvalidTransactionError}, - EthApi, -}; -use reth_evm::ConfigureEvm; -use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, U256}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProvider, StateProviderFactory, -}; -use reth_rpc_types::{serde_helpers::JsonStorageKey, EIP1186AccountProofResponse}; -use reth_rpc_types_compat::proof::from_primitive_account_proof; -use reth_transaction_pool::{PoolTransaction, TransactionPool}; - -impl EthApi -where - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Pool: TransactionPool + Clone + 'static, - Network: Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - pub(crate) fn get_code(&self, address: Address, block_id: Option) -> EthResult { - Ok(self - .state_at_block_id_or_latest(block_id)? - .account_code(address)? - .unwrap_or_default() - .original_bytes()) - } - - pub(crate) fn balance(&self, address: Address, block_id: Option) -> EthResult { - Ok(self - .state_at_block_id_or_latest(block_id)? - .account_balance(address)? - .unwrap_or_default()) - } - - /// Returns the number of transactions sent from an address at the given block identifier. - /// - /// If this is [`BlockNumberOrTag::Pending`] then this will look up the highest transaction in - /// pool and return the next nonce (highest + 1). - pub(crate) fn get_transaction_count( - &self, - address: Address, - block_id: Option, - ) -> EthResult { - if block_id == Some(BlockId::pending()) { - let address_txs = self.pool().get_transactions_by_sender(address); - if let Some(highest_nonce) = - address_txs.iter().map(|item| item.transaction.nonce()).max() - { - let tx_count = highest_nonce - .checked_add(1) - .ok_or(RpcInvalidTransactionError::NonceMaxValue)?; - return Ok(U256::from(tx_count)) - } - } - - let state = self.state_at_block_id_or_latest(block_id)?; - Ok(U256::from(state.account_nonce(address)?.unwrap_or_default())) - } - - pub(crate) fn storage_at( - &self, - address: Address, - index: JsonStorageKey, - block_id: Option, - ) -> EthResult { - Ok(B256::new( - self.state_at_block_id_or_latest(block_id)? - .storage(address, index.0)? - .unwrap_or_default() - .to_be_bytes(), - )) - } - - pub(crate) async fn get_proof( - &self, - address: Address, - keys: Vec, - block_id: Option, - ) -> EthResult { - let chain_info = self.provider().chain_info()?; - let block_id = block_id.unwrap_or_default(); - - // if we are trying to create a proof for the latest block, but have a BlockId as input - // that is not BlockNumberOrTag::Latest, then we need to figure out whether or not the - // BlockId corresponds to the latest block - let is_latest_block = match block_id { - BlockId::Number(BlockNumberOrTag::Number(num)) => num == chain_info.best_number, - BlockId::Hash(hash) => hash == chain_info.best_hash.into(), - BlockId::Number(BlockNumberOrTag::Latest) => true, - _ => false, - }; - - // TODO: remove when HistoricalStateProviderRef::proof is implemented - if !is_latest_block { - return Err(EthApiError::InvalidBlockRange) - } - - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || { - let state = this.state_at_block_id(block_id)?; - let storage_keys = keys.iter().map(|key| key.0).collect::>(); - let proof = state.proof(address, &storage_keys)?; - Ok(from_primitive_account_proof(proof)) - }) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::eth::{ - cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, FeeHistoryCacheConfig, - }; - use reth_evm_ethereum::EthEvmConfig; - use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, StorageKey, StorageValue}; - use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider}; - use reth_tasks::pool::BlockingTaskPool; - use reth_transaction_pool::test_utils::testing_pool; - use std::collections::HashMap; - - #[tokio::test] - async fn test_storage() { - // === Noop === - let pool = testing_pool(); - let evm_config = EthEvmConfig::default(); - - let cache = EthStateCache::spawn(NoopProvider::default(), Default::default(), evm_config); - let eth_api = EthApi::new( - NoopProvider::default(), - pool.clone(), - (), - cache.clone(), - GasPriceOracle::new(NoopProvider::default(), Default::default(), cache.clone()), - ETHEREUM_BLOCK_GAS_LIMIT, - BlockingTaskPool::build().expect("failed to build tracing pool"), - FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), - evm_config, - None, - ); - let address = Address::random(); - let storage = eth_api.storage_at(address, U256::ZERO.into(), None).unwrap(); - assert_eq!(storage, U256::ZERO.to_be_bytes()); - - // === Mock === - let mock_provider = MockEthProvider::default(); - let storage_value = StorageValue::from(1337); - let storage_key = StorageKey::random(); - let storage = HashMap::from([(storage_key, storage_value)]); - let account = ExtendedAccount::new(0, U256::ZERO).extend_storage(storage); - mock_provider.add_account(address, account); - - let cache = EthStateCache::spawn(mock_provider.clone(), Default::default(), evm_config); - let eth_api = EthApi::new( - mock_provider.clone(), - pool, - (), - cache.clone(), - GasPriceOracle::new(mock_provider, Default::default(), cache.clone()), - ETHEREUM_BLOCK_GAS_LIMIT, - BlockingTaskPool::build().expect("failed to build tracing pool"), - FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), - evm_config, - None, - ); - - let storage_key: U256 = storage_key.into(); - let storage = eth_api.storage_at(address, storage_key.into(), None).unwrap(); - assert_eq!(storage, storage_value.to_be_bytes()); - } -} diff --git a/crates/rpc/rpc/src/eth/api/transactions.rs b/crates/rpc/rpc/src/eth/api/transactions.rs index 8829a0434e49..e69de29bb2d1 100644 --- a/crates/rpc/rpc/src/eth/api/transactions.rs +++ b/crates/rpc/rpc/src/eth/api/transactions.rs @@ -1,1861 +0,0 @@ -//! Contains RPC handler implementations specific to transactions -use crate::{ - eth::{ - api::pending_block::PendingBlockEnv, - error::{EthApiError, EthResult, RpcInvalidTransactionError, SignError}, - revm_utils::prepare_call_env, - utils::recover_raw_transaction, - }, - EthApi, EthApiSpec, -}; -use alloy_primitives::TxKind as RpcTransactionKind; -use async_trait::async_trait; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{ - eip4844::calc_blob_gasprice, - revm::env::{fill_block_env_with_coinbase, tx_env_with_recovered}, - Address, BlockId, BlockNumberOrTag, Bytes, FromRecoveredPooledTransaction, Header, - IntoRecoveredTransaction, Receipt, SealedBlock, SealedBlockWithSenders, TransactionMeta, - TransactionSigned, TransactionSignedEcRecovered, - TxKind::{Call, Create}, - B256, U256, -}; -use reth_provider::{ - BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory, -}; -use reth_revm::database::StateProviderDatabase; -use reth_rpc_types::{ - state::EvmOverrides, - transaction::{ - EIP1559TransactionRequest, EIP2930TransactionRequest, EIP4844TransactionRequest, - LegacyTransactionRequest, - }, - AnyReceiptEnvelope, AnyTransactionReceipt, Index, Log, ReceiptWithBloom, Transaction, - TransactionInfo, TransactionReceipt, TransactionRequest, TypedTransactionRequest, - WithOtherFields, -}; -use reth_rpc_types_compat::transaction::from_recovered_with_block_context; -use reth_transaction_pool::{TransactionOrigin, TransactionPool}; -use revm::{ - db::CacheDB, - primitives::{ - db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, - ExecutionResult, ResultAndState, SpecId, - }, - GetInspector, Inspector, -}; -use revm_inspectors::tracing::{TracingInspector, TracingInspectorConfig}; -use std::future::Future; - -use crate::eth::revm_utils::FillableTransaction; -#[cfg(feature = "optimism")] -use reth_rpc_types::OptimismTransactionReceiptFields; -use revm_primitives::db::{Database, DatabaseRef}; - -/// Helper alias type for the state's [`CacheDB`] -pub(crate) type StateCacheDB = CacheDB>; - -/// Commonly used transaction related functions for the [EthApi] type in the `eth_` namespace. -/// -/// This includes utilities for transaction tracing, transacting and inspection. -/// -/// Async functions that are spawned onto the -/// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool) begin with `spawn_` -/// -/// ## Calls -/// -/// There are subtle differences between when transacting [TransactionRequest]: -/// -/// The endpoints `eth_call` and `eth_estimateGas` and `eth_createAccessList` should always -/// __disable__ the base fee check in the [EnvWithHandlerCfg] -/// [Cfg](revm_primitives::CfgEnvWithHandlerCfg). -/// -/// The behaviour for tracing endpoints is not consistent across clients. -/// Geth also disables the basefee check for tracing: -/// Erigon does not: -/// -/// See also -/// -/// This implementation follows the behaviour of Geth and disables the basefee check for tracing. -#[async_trait::async_trait] -pub trait EthTransactions: Send + Sync { - /// Executes the [EnvWithHandlerCfg] against the given [Database] without committing state - /// changes. - fn transact( - &self, - db: DB, - env: EnvWithHandlerCfg, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into; - - /// Executes the [EnvWithHandlerCfg] against the given [Database] without committing state - /// changes. - fn inspect( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into, - I: GetInspector; - - /// Same as [Self::inspect] but also returns the database again. - /// - /// Even though [Database] is also implemented on `&mut` - /// this is still useful if there are certain trait bounds on the Inspector's database generic - /// type - fn inspect_and_return_db( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg, DB)> - where - DB: Database, - ::Error: Into, - I: GetInspector; - - /// Replays all the transactions until the target transaction is found. - /// - /// All transactions before the target transaction are executed and their changes are written to - /// the _runtime_ db ([CacheDB]). - /// - /// Note: This assumes the target transaction is in the given iterator. - /// Returns the index of the target transaction in the given iterator. - fn replay_transactions_until( - &self, - db: &mut CacheDB, - cfg: CfgEnvWithHandlerCfg, - block_env: BlockEnv, - transactions: I, - target_tx_hash: B256, - ) -> Result - where - DB: DatabaseRef, - EthApiError: From<::Error>, - I: IntoIterator, - Tx: FillableTransaction; - - /// Returns default gas limit to use for `eth_call` and tracing RPC methods. - fn call_gas_limit(&self) -> u64; - - /// Executes the future on a new blocking task. - /// - /// Note: This is expected for futures that are dominated by blocking IO operations, for tracing - /// or CPU bound operations in general use [Self::spawn_blocking]. - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static; - - /// Executes a blocking on the tracing pol. - /// - /// Note: This is expected for futures that are predominantly CPU bound, for blocking IO futures - /// use [Self::spawn_blocking_future]. - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static; - - /// Returns the state at the given [BlockId] - fn state_at(&self, at: BlockId) -> EthResult; - - /// Executes the closure with the state that corresponds to the given [BlockId]. - fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - F: FnOnce(StateProviderBox) -> EthResult; - - /// Executes the closure with the state that corresponds to the given [BlockId] on a new task - async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, - T: Send + 'static; - - /// Returns the revm evm env for the requested [BlockId] - /// - /// If the [BlockId] this will return the [BlockId] of the block the env was configured - /// for. - /// If the [BlockId] is pending, this will return the "Pending" tag, otherwise this returns the - /// hash of the exact block. - async fn evm_env_at(&self, at: BlockId) - -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)>; - - /// Returns the revm evm env for the raw block header - /// - /// This is used for tracing raw blocks - async fn evm_env_for_raw_block( - &self, - at: &Header, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)>; - - /// Get all transactions in the block with the given hash. - /// - /// Returns `None` if block does not exist. - async fn transactions_by_block(&self, block: B256) - -> EthResult>>; - - /// Get the entire block for the given id. - /// - /// Returns `None` if block does not exist. - async fn block_by_id(&self, id: BlockId) -> EthResult>; - - /// Get the entire block for the given id. - /// - /// Returns `None` if block does not exist. - async fn block_by_id_with_senders( - &self, - id: BlockId, - ) -> EthResult>; - - /// Get all transactions in the block with the given hash. - /// - /// Returns `None` if block does not exist. - async fn transactions_by_block_id( - &self, - block: BlockId, - ) -> EthResult>>; - - /// Returns the EIP-2718 encoded transaction by hash. - /// - /// If this is a pooled EIP-4844 transaction, the blob sidecar is included. - /// - /// Checks the pool and state. - /// - /// Returns `Ok(None)` if no matching transaction was found. - async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult>; - - /// Returns the transaction by hash. - /// - /// Checks the pool and state. - /// - /// Returns `Ok(None)` if no matching transaction was found. - async fn transaction_by_hash(&self, hash: B256) -> EthResult>; - - /// Returns the transaction by including its corresponding [BlockId] - /// - /// Note: this supports pending transactions - async fn transaction_by_hash_at( - &self, - hash: B256, - ) -> EthResult>; - - /// Returns the _historical_ transaction and the block it was mined in - async fn historical_transaction_by_hash_at( - &self, - hash: B256, - ) -> EthResult>; - - /// Returns the transaction receipt for the given hash. - /// - /// Returns None if the transaction does not exist or is pending - /// Note: The tx receipt is not available for pending transactions. - async fn transaction_receipt(&self, hash: B256) -> EthResult>; - - /// Decodes and recovers the transaction and submits it to the pool. - /// - /// Returns the hash of the transaction. - async fn send_raw_transaction(&self, tx: Bytes) -> EthResult; - - /// Signs transaction with a matching signer, if any and submits the transaction to the pool. - /// Returns the hash of the signed transaction. - async fn send_transaction(&self, request: TransactionRequest) -> EthResult; - - /// Prepares the state and env for the given [TransactionRequest] at the given [BlockId] and - /// executes the closure on a new task returning the result of the closure. - /// - /// This returns the configured [EnvWithHandlerCfg] for the given [TransactionRequest] at the - /// given [BlockId] and with configured call settings: `prepare_call_env`. - async fn spawn_with_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - f: F, - ) -> EthResult - where - F: FnOnce(&mut StateCacheDB, EnvWithHandlerCfg) -> EthResult + Send + 'static, - R: Send + 'static; - - /// Executes the call request at the given [BlockId]. - async fn transact_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)>; - - /// Executes the call request at the given [BlockId] on a new task and returns the result of the - /// inspect call. - async fn spawn_inspect_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static; - - /// Executes the transaction on top of the given [BlockId] with a tracer configured by the - /// config. - /// - /// The callback is then called with the [TracingInspector] and the [ResultAndState] after the - /// configured [EnvWithHandlerCfg] was inspected. - /// - /// Caution: this is blocking - fn trace_at( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - F: FnOnce(TracingInspector, ResultAndState) -> EthResult; - - /// Same as [Self::trace_at] but also provides the used database to the callback. - /// - /// Executes the transaction on top of the given [BlockId] with a tracer configured by the - /// config. - /// - /// The callback is then called with the [TracingInspector] and the [ResultAndState] after the - /// configured [EnvWithHandlerCfg] was inspected. - async fn spawn_trace_at_with_state( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static; - - /// Fetches the transaction and the transaction's block - async fn transaction_and_block( - &self, - hash: B256, - ) -> EthResult>; - - /// Retrieves the transaction if it exists and returns its trace. - /// - /// Before the transaction is traced, all previous transaction in the block are applied to the - /// state by executing them first. - /// The callback `f` is invoked with the [ResultAndState] after the transaction was executed and - /// the database that points to the beginning of the transaction. - /// - /// Note: Implementers should use a threadpool where blocking is allowed, such as - /// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool). - async fn spawn_trace_transaction_in_block( - &self, - hash: B256, - config: TracingInspectorConfig, - f: F, - ) -> EthResult> - where - F: FnOnce(TransactionInfo, TracingInspector, ResultAndState, StateCacheDB) -> EthResult - + Send - + 'static, - R: Send + 'static, - { - self.spawn_trace_transaction_in_block_with_inspector(hash, TracingInspector::new(config), f) - .await - } - - /// Retrieves the transaction if it exists and returns its trace. - /// - /// Before the transaction is traced, all previous transaction in the block are applied to the - /// state by executing them first. - /// The callback `f` is invoked with the [ResultAndState] after the transaction was executed and - /// the database that points to the beginning of the transaction. - /// - /// Note: Implementers should use a threadpool where blocking is allowed, such as - /// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool). - async fn spawn_replay_transaction(&self, hash: B256, f: F) -> EthResult> - where - F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static; - - /// Retrieves the transaction if it exists and returns its trace. - /// - /// Before the transaction is traced, all previous transaction in the block are applied to the - /// state by executing them first. - /// The callback `f` is invoked with the [ResultAndState] after the transaction was executed and - /// the database that points to the beginning of the transaction. - /// - /// Note: Implementers should use a threadpool where blocking is allowed, such as - /// [BlockingTaskPool](reth_tasks::pool::BlockingTaskPool). - async fn spawn_trace_transaction_in_block_with_inspector( - &self, - hash: B256, - inspector: Insp, - f: F, - ) -> EthResult> - where - F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB) -> EthResult - + Send - + 'static, - Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - R: Send + 'static; - - /// Executes all transactions of a block and returns a list of callback results invoked for each - /// transaction in the block. - /// - /// This - /// 1. fetches all transactions of the block - /// 2. configures the EVM evn - /// 3. loops over all transactions and executes them - /// 4. calls the callback with the transaction info, the execution result, the changed state - /// _after_ the transaction [StateProviderDatabase] and the database that points to the state - /// right _before_ the transaction. - async fn trace_block_with( - &self, - block_id: BlockId, - config: TracingInspectorConfig, - f: F, - ) -> EthResult>> - where - // This is the callback that's invoked for each transaction with the inspector, the result, - // state and db - F: for<'a> Fn( - TransactionInfo, - TracingInspector, - ExecutionResult, - &'a EvmState, - &'a StateCacheDB, - ) -> EthResult - + Send - + 'static, - R: Send + 'static, - { - self.trace_block_until(block_id, None, config, f).await - } - - /// Executes all transactions of a block and returns a list of callback results invoked for each - /// transaction in the block. - /// - /// This - /// 1. fetches all transactions of the block - /// 2. configures the EVM evn - /// 3. loops over all transactions and executes them - /// 4. calls the callback with the transaction info, the execution result, the changed state - /// _after_ the transaction [EvmState] and the database that points to the state - /// right _before_ the transaction, in other words the state the transaction was - /// executed on: `changed_state = tx(cached_state)` - /// - /// This accepts a `inspector_setup` closure that returns the inspector to be used for tracing - /// a transaction. This is invoked for each transaction. - async fn trace_block_with_inspector( - &self, - block_id: BlockId, - insp_setup: Setup, - f: F, - ) -> EthResult>> - where - // This is the callback that's invoked for each transaction with the inspector, the result, - // state and db - F: for<'a> Fn( - TransactionInfo, - Insp, - ExecutionResult, - &'a EvmState, - &'a StateCacheDB, - ) -> EthResult - + Send - + 'static, - Setup: FnMut() -> Insp + Send + 'static, - Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - R: Send + 'static, - { - self.trace_block_until_with_inspector(block_id, None, insp_setup, f).await - } - - /// Executes all transactions of a block. - /// - /// If a `highest_index` is given, this will only execute the first `highest_index` - /// transactions, in other words, it will stop executing transactions after the - /// `highest_index`th transaction. - async fn trace_block_until( - &self, - block_id: BlockId, - highest_index: Option, - config: TracingInspectorConfig, - f: F, - ) -> EthResult>> - where - F: for<'a> Fn( - TransactionInfo, - TracingInspector, - ExecutionResult, - &'a EvmState, - &'a StateCacheDB, - ) -> EthResult - + Send - + 'static, - R: Send + 'static, - { - self.trace_block_until_with_inspector( - block_id, - highest_index, - move || TracingInspector::new(config), - f, - ) - .await - } - - /// Executes all transactions of a block. - /// - /// If a `highest_index` is given, this will only execute the first `highest_index` - /// transactions, in other words, it will stop executing transactions after the - /// `highest_index`th transaction. - /// - /// Note: This expect tx index to be 0-indexed, so the first transaction is at index 0. - /// - /// This accepts a `inspector_setup` closure that returns the inspector to be used for tracing - /// the transactions. - async fn trace_block_until_with_inspector( - &self, - block_id: BlockId, - highest_index: Option, - inspector_setup: Setup, - f: F, - ) -> EthResult>> - where - F: for<'a> Fn( - TransactionInfo, - Insp, - ExecutionResult, - &'a EvmState, - &'a StateCacheDB, - ) -> EthResult - + Send - + 'static, - Setup: FnMut() -> Insp + Send + 'static, - Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - R: Send + 'static; -} - -#[async_trait] -impl EthTransactions - for EthApi -where - Pool: TransactionPool + Clone + 'static, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - fn transact( - &self, - db: DB, - env: EnvWithHandlerCfg, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into, - { - let mut evm = self.inner.evm_config.evm_with_env(db, env); - let res = evm.transact()?; - let (_, env) = evm.into_db_and_env_with_handler_cfg(); - Ok((res, env)) - } - - fn inspect( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - DB: Database, - ::Error: Into, - I: GetInspector, - { - self.inspect_and_return_db(db, env, inspector).map(|(res, env, _)| (res, env)) - } - - fn inspect_and_return_db( - &self, - db: DB, - env: EnvWithHandlerCfg, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg, DB)> - where - DB: Database, - ::Error: Into, - I: GetInspector, - { - let mut evm = self.inner.evm_config.evm_with_env_and_inspector(db, env, inspector); - let res = evm.transact()?; - let (db, env) = evm.into_db_and_env_with_handler_cfg(); - Ok((res, env, db)) - } - - fn replay_transactions_until( - &self, - db: &mut CacheDB, - cfg: CfgEnvWithHandlerCfg, - block_env: BlockEnv, - transactions: I, - target_tx_hash: B256, - ) -> Result - where - DB: DatabaseRef, - EthApiError: From<::Error>, - I: IntoIterator, - Tx: FillableTransaction, - { - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()); - - let mut evm = self.inner.evm_config.evm_with_env(db, env); - let mut index = 0; - for tx in transactions { - if tx.hash() == target_tx_hash { - // reached the target transaction - break - } - - tx.try_fill_tx_env(evm.tx_mut())?; - evm.transact_commit()?; - index += 1; - } - Ok(index) - } - - fn call_gas_limit(&self) -> u64 { - self.inner.gas_cap - } - - async fn spawn_blocking_future(&self, c: F) -> EthResult - where - F: Future> + Send + 'static, - R: Send + 'static, - { - self.on_blocking_task(|_| c).await - } - - async fn spawn_blocking(&self, c: F) -> EthResult - where - F: FnOnce() -> EthResult + Send + 'static, - R: Send + 'static, - { - self.spawn_tracing_task_with(move |_| c()).await - } - - fn state_at(&self, at: BlockId) -> EthResult { - self.state_at_block_id(at) - } - - fn with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - F: FnOnce(StateProviderBox) -> EthResult, - { - let state = self.state_at(at)?; - f(state) - } - - async fn spawn_with_state_at_block(&self, at: BlockId, f: F) -> EthResult - where - F: FnOnce(StateProviderBox) -> EthResult + Send + 'static, - T: Send + 'static, - { - self.spawn_tracing_task_with(move |this| { - let state = this.state_at(at)?; - f(state) - }) - .await - } - - async fn evm_env_at( - &self, - at: BlockId, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv, BlockId)> { - if at.is_pending() { - let PendingBlockEnv { cfg, block_env, origin } = self.pending_block_env_and_cfg()?; - Ok((cfg, block_env, origin.state_block_id())) - } else { - // Use cached values if there is no pending block - let block_hash = self - .provider() - .block_hash_for_id(at)? - .ok_or_else(|| EthApiError::UnknownBlockNumber)?; - let (cfg, env) = self.cache().get_evm_env(block_hash).await?; - Ok((cfg, env, block_hash.into())) - } - } - - async fn evm_env_for_raw_block( - &self, - header: &Header, - ) -> EthResult<(CfgEnvWithHandlerCfg, BlockEnv)> { - // get the parent config first - let (cfg, mut block_env, _) = self.evm_env_at(header.parent_hash.into()).await?; - - let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE; - fill_block_env_with_coinbase(&mut block_env, header, after_merge, header.beneficiary); - - Ok((cfg, block_env)) - } - - async fn transactions_by_block( - &self, - block: B256, - ) -> EthResult>> { - Ok(self.cache().get_block_transactions(block).await?) - } - - async fn block_by_id(&self, id: BlockId) -> EthResult> { - self.block(id).await - } - - async fn block_by_id_with_senders( - &self, - id: BlockId, - ) -> EthResult> { - self.block_with_senders(id).await - } - - async fn transactions_by_block_id( - &self, - block: BlockId, - ) -> EthResult>> { - self.block_by_id(block).await.map(|block| block.map(|block| block.body)) - } - - async fn raw_transaction_by_hash(&self, hash: B256) -> EthResult> { - // Note: this is mostly used to fetch pooled transactions so we check the pool first - if let Some(tx) = - self.pool().get_pooled_transaction_element(hash).map(|tx| tx.envelope_encoded()) - { - return Ok(Some(tx)) - } - - self.on_blocking_task(|this| async move { - Ok(this.provider().transaction_by_hash(hash)?.map(|tx| tx.envelope_encoded())) - }) - .await - } - - async fn transaction_by_hash(&self, hash: B256) -> EthResult> { - // Try to find the transaction on disk - let mut resp = self - .on_blocking_task(|this| async move { - match this.provider().transaction_by_hash_with_meta(hash)? { - None => Ok(None), - Some((tx, meta)) => { - // Note: we assume this transaction is valid, because it's mined (or part of - // pending block) and already. We don't need to - // check for pre EIP-2 because this transaction could be pre-EIP-2. - let transaction = tx - .into_ecrecovered_unchecked() - .ok_or(EthApiError::InvalidTransactionSignature)?; - - let tx = TransactionSource::Block { - transaction, - index: meta.index, - block_hash: meta.block_hash, - block_number: meta.block_number, - base_fee: meta.base_fee, - }; - Ok(Some(tx)) - } - } - }) - .await?; - - if resp.is_none() { - // tx not found on disk, check pool - if let Some(tx) = - self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction()) - { - resp = Some(TransactionSource::Pool(tx)); - } - } - - Ok(resp) - } - - async fn transaction_by_hash_at( - &self, - transaction_hash: B256, - ) -> EthResult> { - match self.transaction_by_hash(transaction_hash).await? { - None => return Ok(None), - Some(tx) => { - let res = match tx { - tx @ TransactionSource::Pool(_) => (tx, BlockId::pending()), - TransactionSource::Block { - transaction, - index, - block_hash, - block_number, - base_fee, - } => { - let at = BlockId::Hash(block_hash.into()); - let tx = TransactionSource::Block { - transaction, - index, - block_hash, - block_number, - base_fee, - }; - (tx, at) - } - }; - Ok(Some(res)) - } - } - } - - async fn historical_transaction_by_hash_at( - &self, - hash: B256, - ) -> EthResult> { - match self.transaction_by_hash_at(hash).await? { - None => Ok(None), - Some((tx, at)) => Ok(at.as_block_hash().map(|hash| (tx, hash))), - } - } - - async fn transaction_receipt(&self, hash: B256) -> EthResult> { - let result = self - .on_blocking_task(|this| async move { - let (tx, meta) = match this.provider().transaction_by_hash_with_meta(hash)? { - Some((tx, meta)) => (tx, meta), - None => return Ok(None), - }; - - let receipt = match this.provider().receipt_by_hash(hash)? { - Some(recpt) => recpt, - None => return Ok(None), - }; - - Ok(Some((tx, meta, receipt))) - }) - .await?; - - let (tx, meta, receipt) = match result { - Some((tx, meta, receipt)) => (tx, meta, receipt), - None => return Ok(None), - }; - - self.build_transaction_receipt(tx, meta, receipt).await.map(Some) - } - - async fn send_raw_transaction(&self, tx: Bytes) -> EthResult { - // On optimism, transactions are forwarded directly to the sequencer to be included in - // blocks that it builds. - let maybe_forwarder = self.inner.raw_transaction_forwarder.read().clone(); - if let Some(client) = maybe_forwarder { - tracing::debug!( target: "rpc::eth", "forwarding raw transaction to"); - client.forward_raw_transaction(&tx).await?; - } - - let recovered = recover_raw_transaction(tx)?; - let pool_transaction = ::from_recovered_pooled_transaction(recovered); - - // submit the transaction to the pool with a `Local` origin - let hash = self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; - - Ok(hash) - } - - async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult { - let from = match request.from { - Some(from) => from, - None => return Err(SignError::NoAccount.into()), - }; - - // set nonce if not already set before - if request.nonce.is_none() { - let nonce = self.get_transaction_count(from, Some(BlockId::pending()))?; - // note: `.to()` can't panic because the nonce is constructed from a `u64` - request.nonce = Some(nonce.to::()); - } - - let chain_id = self.chain_id(); - - let estimated_gas = self.estimate_gas_at(request.clone(), BlockId::pending(), None).await?; - let gas_limit = estimated_gas; - - let TransactionRequest { - to, - gas_price, - max_fee_per_gas, - max_priority_fee_per_gas, - gas, - value, - input: data, - nonce, - mut access_list, - max_fee_per_blob_gas, - blob_versioned_hashes, - sidecar, - .. - } = request; - - // todo: remove this inlining after https://github.com/alloy-rs/alloy/pull/183#issuecomment-1928161285 - let transaction = match ( - gas_price, - max_fee_per_gas, - access_list.take(), - max_fee_per_blob_gas, - blob_versioned_hashes, - sidecar, - ) { - // legacy transaction - // gas price required - (Some(_), None, None, None, None, None) => { - Some(TypedTransactionRequest::Legacy(LegacyTransactionRequest { - nonce: nonce.unwrap_or_default(), - gas_price: U256::from(gas_price.unwrap_or_default()), - gas_limit: U256::from(gas.unwrap_or_default()), - value: value.unwrap_or_default(), - input: data.into_input().unwrap_or_default(), - kind: to.unwrap_or(RpcTransactionKind::Create), - chain_id: None, - })) - } - // EIP2930 - // if only accesslist is set, and no eip1599 fees - (_, None, Some(access_list), None, None, None) => { - Some(TypedTransactionRequest::EIP2930(EIP2930TransactionRequest { - nonce: nonce.unwrap_or_default(), - gas_price: U256::from(gas_price.unwrap_or_default()), - gas_limit: U256::from(gas.unwrap_or_default()), - value: value.unwrap_or_default(), - input: data.into_input().unwrap_or_default(), - kind: to.unwrap_or(RpcTransactionKind::Create), - chain_id: 0, - access_list, - })) - } - // EIP1559 - // if 4844 fields missing - // gas_price, max_fee_per_gas, access_list, max_fee_per_blob_gas, blob_versioned_hashes, - // sidecar, - (None, _, _, None, None, None) => { - // Empty fields fall back to the canonical transaction schema. - Some(TypedTransactionRequest::EIP1559(EIP1559TransactionRequest { - nonce: nonce.unwrap_or_default(), - max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()), - max_priority_fee_per_gas: U256::from( - max_priority_fee_per_gas.unwrap_or_default(), - ), - gas_limit: U256::from(gas.unwrap_or_default()), - value: value.unwrap_or_default(), - input: data.into_input().unwrap_or_default(), - kind: to.unwrap_or(RpcTransactionKind::Create), - chain_id: 0, - access_list: access_list.unwrap_or_default(), - })) - } - // EIP4884 - // all blob fields required - ( - None, - _, - _, - Some(max_fee_per_blob_gas), - Some(blob_versioned_hashes), - Some(sidecar), - ) => { - // As per the EIP, we follow the same semantics as EIP-1559. - Some(TypedTransactionRequest::EIP4844(EIP4844TransactionRequest { - chain_id: 0, - nonce: nonce.unwrap_or_default(), - max_priority_fee_per_gas: U256::from( - max_priority_fee_per_gas.unwrap_or_default(), - ), - max_fee_per_gas: U256::from(max_fee_per_gas.unwrap_or_default()), - gas_limit: U256::from(gas.unwrap_or_default()), - value: value.unwrap_or_default(), - input: data.into_input().unwrap_or_default(), - #[allow(clippy::manual_unwrap_or_default)] // clippy is suggesting here unwrap_or_default - to: match to { - Some(RpcTransactionKind::Call(to)) => to, - _ => Address::default(), - }, - access_list: access_list.unwrap_or_default(), - - // eip-4844 specific. - max_fee_per_blob_gas: U256::from(max_fee_per_blob_gas), - blob_versioned_hashes, - sidecar, - })) - } - - _ => None, - }; - - let transaction = match transaction { - Some(TypedTransactionRequest::Legacy(mut req)) => { - req.chain_id = Some(chain_id.to()); - req.gas_limit = gas_limit.saturating_to(); - req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?; - - TypedTransactionRequest::Legacy(req) - } - Some(TypedTransactionRequest::EIP2930(mut req)) => { - req.chain_id = chain_id.to(); - req.gas_limit = gas_limit.saturating_to(); - req.gas_price = self.legacy_gas_price(gas_price.map(U256::from)).await?; - - TypedTransactionRequest::EIP2930(req) - } - Some(TypedTransactionRequest::EIP1559(mut req)) => { - let (max_fee_per_gas, max_priority_fee_per_gas) = self - .eip1559_fees( - max_fee_per_gas.map(U256::from), - max_priority_fee_per_gas.map(U256::from), - ) - .await?; - - req.chain_id = chain_id.to(); - req.gas_limit = gas_limit.saturating_to(); - req.max_fee_per_gas = max_fee_per_gas.saturating_to(); - req.max_priority_fee_per_gas = max_priority_fee_per_gas.saturating_to(); - - TypedTransactionRequest::EIP1559(req) - } - Some(TypedTransactionRequest::EIP4844(mut req)) => { - let (max_fee_per_gas, max_priority_fee_per_gas) = self - .eip1559_fees( - max_fee_per_gas.map(U256::from), - max_priority_fee_per_gas.map(U256::from), - ) - .await?; - - req.max_fee_per_gas = max_fee_per_gas; - req.max_priority_fee_per_gas = max_priority_fee_per_gas; - req.max_fee_per_blob_gas = - self.eip4844_blob_fee(max_fee_per_blob_gas.map(U256::from)).await?; - - req.chain_id = chain_id.to(); - req.gas_limit = gas_limit; - - TypedTransactionRequest::EIP4844(req) - } - None => return Err(EthApiError::ConflictingFeeFieldsInRequest), - }; - - let signed_tx = self.sign_request(&from, transaction)?; - - let recovered = - signed_tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?; - - let pool_transaction = match recovered.try_into() { - Ok(converted) => ::from_recovered_pooled_transaction(converted), - Err(_) => return Err(EthApiError::TransactionConversionError), - }; - - // submit the transaction to the pool with a `Local` origin - let hash = self.pool().add_transaction(TransactionOrigin::Local, pool_transaction).await?; - - Ok(hash) - } - - async fn spawn_with_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - f: F, - ) -> EthResult - where - F: FnOnce(&mut StateCacheDB, EnvWithHandlerCfg) -> EthResult + Send + 'static, - R: Send + 'static, - { - let (cfg, block_env, at) = self.evm_env_at(at).await?; - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || { - let state = this.state_at(at)?; - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - let env = prepare_call_env( - cfg, - block_env, - request, - this.call_gas_limit(), - &mut db, - overrides, - )?; - f(&mut db, env) - }) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } - - async fn transact_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> { - let this = self.clone(); - self.spawn_with_call_at(request, at, overrides, move |db, env| this.transact(db, env)).await - } - - async fn spawn_inspect_call_at( - &self, - request: TransactionRequest, - at: BlockId, - overrides: EvmOverrides, - inspector: I, - ) -> EthResult<(ResultAndState, EnvWithHandlerCfg)> - where - I: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - { - let this = self.clone(); - self.spawn_with_call_at(request, at, overrides, move |db, env| { - this.inspect(db, env, inspector) - }) - .await - } - - fn trace_at( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - F: FnOnce(TracingInspector, ResultAndState) -> EthResult, - { - let this = self.clone(); - self.with_state_at_block(at, |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let mut inspector = TracingInspector::new(config); - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - f(inspector, res) - }) - } - - async fn spawn_trace_at_with_state( - &self, - env: EnvWithHandlerCfg, - config: TracingInspectorConfig, - at: BlockId, - f: F, - ) -> EthResult - where - F: FnOnce(TracingInspector, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static, - { - let this = self.clone(); - self.spawn_with_state_at_block(at, move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - let mut inspector = TracingInspector::new(config); - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - f(inspector, res, db) - }) - .await - } - - async fn transaction_and_block( - &self, - hash: B256, - ) -> EthResult> { - let (transaction, at) = match self.transaction_by_hash_at(hash).await? { - None => return Ok(None), - Some(res) => res, - }; - - // Note: this is always either hash or pending - let block_hash = match at { - BlockId::Hash(hash) => hash.block_hash, - _ => return Ok(None), - }; - let block = self.cache().get_block_with_senders(block_hash).await?; - Ok(block.map(|block| (transaction, block.seal(block_hash)))) - } - - async fn spawn_replay_transaction(&self, hash: B256, f: F) -> EthResult> - where - F: FnOnce(TransactionInfo, ResultAndState, StateCacheDB) -> EthResult + Send + 'static, - R: Send + 'static, - { - let (transaction, block) = match self.transaction_and_block(hash).await? { - None => return Ok(None), - Some(res) => res, - }; - let (tx, tx_info) = transaction.split(); - - let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?; - - // we need to get the state of the parent block because we're essentially replaying the - // block the transaction is included in - let parent_block = block.parent_hash; - let block_txs = block.into_transactions_ecrecovered(); - - let this = self.clone(); - self.spawn_with_state_at_block(parent_block.into(), move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - // replay all transactions prior to the targeted transaction - this.replay_transactions_until( - &mut db, - cfg.clone(), - block_env.clone(), - block_txs, - tx.hash, - )?; - - let env = - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, tx_env_with_recovered(&tx)); - - let (res, _) = this.transact(&mut db, env)?; - f(tx_info, res, db) - }) - .await - .map(Some) - } - - async fn spawn_trace_transaction_in_block_with_inspector( - &self, - hash: B256, - mut inspector: Insp, - f: F, - ) -> EthResult> - where - F: FnOnce(TransactionInfo, Insp, ResultAndState, StateCacheDB) -> EthResult - + Send - + 'static, - Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - R: Send + 'static, - { - let (transaction, block) = match self.transaction_and_block(hash).await? { - None => return Ok(None), - Some(res) => res, - }; - let (tx, tx_info) = transaction.split(); - - let (cfg, block_env, _) = self.evm_env_at(block.hash().into()).await?; - - // we need to get the state of the parent block because we're essentially replaying the - // block the transaction is included in - let parent_block = block.parent_hash; - let block_txs = block.into_transactions_ecrecovered(); - - let this = self.clone(); - self.spawn_with_state_at_block(parent_block.into(), move |state| { - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - // replay all transactions prior to the targeted transaction - this.replay_transactions_until( - &mut db, - cfg.clone(), - block_env.clone(), - block_txs, - tx.hash, - )?; - - let env = - EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, tx_env_with_recovered(&tx)); - - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - f(tx_info, inspector, res, db) - }) - .await - .map(Some) - } - - async fn trace_block_until_with_inspector( - &self, - block_id: BlockId, - highest_index: Option, - mut inspector_setup: Setup, - f: F, - ) -> EthResult>> - where - F: for<'a> Fn( - TransactionInfo, - Insp, - ExecutionResult, - &'a EvmState, - &'a StateCacheDB, - ) -> EthResult - + Send - + 'static, - Setup: FnMut() -> Insp + Send + 'static, - Insp: for<'a> Inspector<&'a mut StateCacheDB> + Send + 'static, - R: Send + 'static, - { - let ((cfg, block_env, _), block) = - futures::try_join!(self.evm_env_at(block_id), self.block_with_senders(block_id))?; - - let Some(block) = block else { return Ok(None) }; - - if block.body.is_empty() { - // nothing to trace - return Ok(Some(Vec::new())) - } - - // replay all transactions of the block - self.spawn_tracing_task_with(move |this| { - // we need to get the state of the parent block because we're replaying this block on - // top of its parent block's state - let state_at = block.parent_hash; - let block_hash = block.hash(); - - let block_number = block_env.number.saturating_to::(); - let base_fee = block_env.basefee.saturating_to::(); - - // prepare transactions, we do everything upfront to reduce time spent with open state - let max_transactions = highest_index.map_or(block.body.len(), |highest| { - // we need + 1 because the index is 0-based - highest as usize + 1 - }); - let mut results = Vec::with_capacity(max_transactions); - - let mut transactions = block - .into_transactions_ecrecovered() - .take(max_transactions) - .enumerate() - .map(|(idx, tx)| { - let tx_info = TransactionInfo { - hash: Some(tx.hash()), - index: Some(idx as u64), - block_hash: Some(block_hash), - block_number: Some(block_number), - base_fee: Some(base_fee), - }; - let tx_env = tx_env_with_recovered(&tx); - (tx_info, tx_env) - }) - .peekable(); - - // now get the state - let state = this.state_at(state_at.into())?; - let mut db = CacheDB::new(StateProviderDatabase::new(state)); - - while let Some((tx_info, tx)) = transactions.next() { - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg.clone(), block_env.clone(), tx); - - let mut inspector = inspector_setup(); - let (res, _) = this.inspect(&mut db, env, &mut inspector)?; - let ResultAndState { result, state } = res; - results.push(f(tx_info, inspector, result, &state, &db)?); - - // need to apply the state changes of this transaction before executing the - // next transaction, but only if there's a next transaction - if transactions.peek().is_some() { - // commit the state changes to the DB - db.commit(state) - } - } - - Ok(results) - }) - .await - .map(Some) - } -} - -// === impl EthApi === - -impl EthApi -where - Self: Send + Sync + 'static, -{ - /// Spawns the given closure on a new blocking tracing task - async fn spawn_tracing_task_with(&self, f: F) -> EthResult - where - F: FnOnce(Self) -> EthResult + Send + 'static, - T: Send + 'static, - { - let this = self.clone(); - self.inner - .blocking_task_pool - .spawn(move || f(this)) - .await - .map_err(|_| EthApiError::InternalBlockingTaskError)? - } -} - -impl EthApi -where - Pool: TransactionPool + 'static, - Provider: - BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, - Network: NetworkInfo + 'static, - EvmConfig: ConfigureEvm, -{ - /// Returns the gas price if it is set, otherwise fetches a suggested gas price for legacy - /// transactions. - pub(crate) async fn legacy_gas_price(&self, gas_price: Option) -> EthResult { - match gas_price { - Some(gas_price) => Ok(gas_price), - None => { - // fetch a suggested gas price - self.gas_price().await - } - } - } - - /// Returns the EIP-1559 fees if they are set, otherwise fetches a suggested gas price for - /// EIP-1559 transactions. - /// - /// Returns (`max_fee`, `priority_fee`) - pub(crate) async fn eip1559_fees( - &self, - max_fee_per_gas: Option, - max_priority_fee_per_gas: Option, - ) -> EthResult<(U256, U256)> { - let max_fee_per_gas = match max_fee_per_gas { - Some(max_fee_per_gas) => max_fee_per_gas, - None => { - // fetch pending base fee - let base_fee = self - .block(BlockNumberOrTag::Pending) - .await? - .ok_or(EthApiError::UnknownBlockNumber)? - .base_fee_per_gas - .ok_or_else(|| { - EthApiError::InvalidTransaction( - RpcInvalidTransactionError::TxTypeNotSupported, - ) - })?; - U256::from(base_fee) - } - }; - - let max_priority_fee_per_gas = match max_priority_fee_per_gas { - Some(max_priority_fee_per_gas) => max_priority_fee_per_gas, - None => self.suggested_priority_fee().await?, - }; - Ok((max_fee_per_gas, max_priority_fee_per_gas)) - } - - /// Returns the EIP-4844 blob fee if it is set, otherwise fetches a blob fee. - pub(crate) async fn eip4844_blob_fee(&self, blob_fee: Option) -> EthResult { - match blob_fee { - Some(blob_fee) => Ok(blob_fee), - None => self.blob_base_fee().await, - } - } - - pub(crate) fn sign_request( - &self, - from: &Address, - request: TypedTransactionRequest, - ) -> EthResult { - for signer in self.inner.signers.read().iter() { - if signer.is_signer_for(from) { - return match signer.sign_transaction(request, from) { - Ok(tx) => Ok(tx), - Err(e) => Err(e.into()), - } - } - } - Err(EthApiError::InvalidTransactionSignature) - } - - /// Get Transaction by [`BlockId`] and the index of the transaction within that Block. - /// - /// Returns `Ok(None)` if the block does not exist, or the block as fewer transactions - pub(crate) async fn transaction_by_block_and_tx_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - if let Some(block) = self.block_with_senders(block_id.into()).await? { - let block_hash = block.hash(); - let block_number = block.number; - let base_fee_per_gas = block.base_fee_per_gas; - if let Some(tx) = block.into_transactions_ecrecovered().nth(index.into()) { - return Ok(Some(from_recovered_with_block_context( - tx, - block_hash, - block_number, - base_fee_per_gas, - index.into(), - ))) - } - } - - Ok(None) - } - - pub(crate) async fn raw_transaction_by_block_and_tx_index( - &self, - block_id: impl Into, - index: Index, - ) -> EthResult> { - if let Some(block) = self.block_with_senders(block_id.into()).await? { - if let Some(tx) = block.transactions().nth(index.into()) { - return Ok(Some(tx.envelope_encoded())) - } - } - - Ok(None) - } -} - -impl EthApi -where - Provider: BlockReaderIdExt + ChainSpecProvider, -{ - /// Helper function for `eth_getTransactionReceipt` - /// - /// Returns the receipt - #[cfg(not(feature = "optimism"))] - pub(crate) async fn build_transaction_receipt( - &self, - tx: TransactionSigned, - meta: TransactionMeta, - receipt: Receipt, - ) -> EthResult { - // get all receipts for the block - let all_receipts = match self.cache().get_receipts(meta.block_hash).await? { - Some(recpts) => recpts, - None => return Err(EthApiError::UnknownBlockNumber), - }; - build_transaction_receipt_with_block_receipts(tx, meta, receipt, &all_receipts) - } - - /// Helper function for `eth_getTransactionReceipt` (optimism) - /// - /// Returns the receipt - #[cfg(feature = "optimism")] - pub(crate) async fn build_transaction_receipt( - &self, - tx: TransactionSigned, - meta: TransactionMeta, - receipt: Receipt, - ) -> EthResult { - let (block, receipts) = self - .cache() - .get_block_and_receipts(meta.block_hash) - .await? - .ok_or(EthApiError::UnknownBlockNumber)?; - - let block = block.unseal(); - let l1_block_info = reth_evm_optimism::extract_l1_info(&block).ok(); - let optimism_tx_meta = self.build_op_tx_meta(&tx, l1_block_info, block.timestamp)?; - - build_transaction_receipt_with_block_receipts( - tx, - meta, - receipt, - &receipts, - optimism_tx_meta, - ) - } - - /// Builds op metadata object using the provided [`TransactionSigned`], L1 block info and - /// `block_timestamp`. The `L1BlockInfo` is used to calculate the l1 fee and l1 data gas for the - /// transaction. If the `L1BlockInfo` is not provided, the meta info will be empty. - #[cfg(feature = "optimism")] - pub(crate) fn build_op_tx_meta( - &self, - tx: &TransactionSigned, - l1_block_info: Option, - block_timestamp: u64, - ) -> EthResult { - use crate::eth::{api::optimism::OptimismTxMeta, optimism::OptimismEthApiError}; - use reth_evm_optimism::RethL1BlockInfo; - - let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) }; - - let (l1_fee, l1_data_gas) = if !tx.is_deposit() { - let envelope_buf = tx.envelope_encoded(); - - let inner_l1_fee = l1_block_info - .l1_tx_data_fee( - &self.inner.provider.chain_spec(), - block_timestamp, - &envelope_buf, - tx.is_deposit(), - ) - .map_err(|_| OptimismEthApiError::L1BlockFeeError)?; - let inner_l1_data_gas = l1_block_info - .l1_data_gas(&self.inner.provider.chain_spec(), block_timestamp, &envelope_buf) - .map_err(|_| OptimismEthApiError::L1BlockGasError)?; - ( - Some(inner_l1_fee.saturating_to::()), - Some(inner_l1_data_gas.saturating_to::()), - ) - } else { - (None, None) - }; - - Ok(OptimismTxMeta::new(Some(l1_block_info), l1_fee, l1_data_gas)) - } -} - -/// Represents from where a transaction was fetched. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum TransactionSource { - /// Transaction exists in the pool (Pending) - Pool(TransactionSignedEcRecovered), - /// Transaction already included in a block - /// - /// This can be a historical block or a pending block (received from the CL) - Block { - /// Transaction fetched via provider - transaction: TransactionSignedEcRecovered, - /// Index of the transaction in the block - index: u64, - /// Hash of the block. - block_hash: B256, - /// Number of the block. - block_number: u64, - /// base fee of the block. - base_fee: Option, - }, -} - -// === impl TransactionSource === - -impl TransactionSource { - /// Consumes the type and returns the wrapped transaction. - pub fn into_recovered(self) -> TransactionSignedEcRecovered { - self.into() - } - - /// Returns the transaction and block related info, if not pending - pub fn split(self) -> (TransactionSignedEcRecovered, TransactionInfo) { - match self { - Self::Pool(tx) => { - let hash = tx.hash(); - ( - tx, - TransactionInfo { - hash: Some(hash), - index: None, - block_hash: None, - block_number: None, - base_fee: None, - }, - ) - } - Self::Block { transaction, index, block_hash, block_number, base_fee } => { - let hash = transaction.hash(); - ( - transaction, - TransactionInfo { - hash: Some(hash), - index: Some(index), - block_hash: Some(block_hash), - block_number: Some(block_number), - base_fee: base_fee.map(u128::from), - }, - ) - } - } - } -} - -impl From for TransactionSignedEcRecovered { - fn from(value: TransactionSource) -> Self { - match value { - TransactionSource::Pool(tx) => tx, - TransactionSource::Block { transaction, .. } => transaction, - } - } -} - -impl From for Transaction { - fn from(value: TransactionSource) -> Self { - match value { - TransactionSource::Pool(tx) => reth_rpc_types_compat::transaction::from_recovered(tx), - TransactionSource::Block { transaction, index, block_hash, block_number, base_fee } => { - from_recovered_with_block_context( - transaction, - block_hash, - block_number, - base_fee, - index as usize, - ) - } - } - } -} - -/// Helper function to construct a transaction receipt -/// -/// Note: This requires _all_ block receipts because we need to calculate the gas used by the -/// transaction. -pub(crate) fn build_transaction_receipt_with_block_receipts( - transaction: TransactionSigned, - meta: TransactionMeta, - receipt: Receipt, - all_receipts: &[Receipt], - #[cfg(feature = "optimism")] optimism_tx_meta: crate::eth::api::optimism::OptimismTxMeta, -) -> EthResult { - // Note: we assume this transaction is valid, because it's mined (or part of pending block) and - // we don't need to check for pre EIP-2 - let from = - transaction.recover_signer_unchecked().ok_or(EthApiError::InvalidTransactionSignature)?; - - // get the previous transaction cumulative gas used - let gas_used = if meta.index == 0 { - receipt.cumulative_gas_used - } else { - let prev_tx_idx = (meta.index - 1) as usize; - all_receipts - .get(prev_tx_idx) - .map(|prev_receipt| receipt.cumulative_gas_used - prev_receipt.cumulative_gas_used) - .unwrap_or_default() - }; - - let blob_gas_used = transaction.transaction.blob_gas_used(); - // Blob gas price should only be present if the transaction is a blob transaction - let blob_gas_price = blob_gas_used.and_then(|_| meta.excess_blob_gas.map(calc_blob_gasprice)); - let logs_bloom = receipt.bloom_slow(); - - // get number of logs in the block - let mut num_logs = 0; - for prev_receipt in all_receipts.iter().take(meta.index as usize) { - num_logs += prev_receipt.logs.len(); - } - - let mut logs = Vec::with_capacity(receipt.logs.len()); - for (tx_log_idx, log) in receipt.logs.into_iter().enumerate() { - let rpclog = Log { - inner: log, - block_hash: Some(meta.block_hash), - block_number: Some(meta.block_number), - block_timestamp: Some(meta.timestamp), - transaction_hash: Some(meta.tx_hash), - transaction_index: Some(meta.index), - log_index: Some((num_logs + tx_log_idx) as u64), - removed: false, - }; - logs.push(rpclog); - } - - let rpc_receipt = reth_rpc_types::Receipt { - status: receipt.success.into(), - cumulative_gas_used: receipt.cumulative_gas_used as u128, - logs, - }; - - #[allow(clippy::needless_update)] - let res_receipt = TransactionReceipt { - inner: AnyReceiptEnvelope { - inner: ReceiptWithBloom { receipt: rpc_receipt, logs_bloom }, - r#type: transaction.transaction.tx_type().into(), - }, - transaction_hash: meta.tx_hash, - transaction_index: Some(meta.index), - block_hash: Some(meta.block_hash), - block_number: Some(meta.block_number), - from, - to: None, - gas_used: gas_used as u128, - contract_address: None, - effective_gas_price: transaction.effective_gas_price(meta.base_fee), - // TODO pre-byzantium receipts have a post-transaction state root - state_root: None, - // EIP-4844 fields - blob_gas_price, - blob_gas_used: blob_gas_used.map(u128::from), - }; - let mut res_receipt = WithOtherFields::new(res_receipt); - - #[cfg(feature = "optimism")] - { - let mut op_fields = OptimismTransactionReceiptFields::default(); - - if transaction.is_deposit() { - op_fields.deposit_nonce = receipt.deposit_nonce.map(reth_primitives::U64::from); - op_fields.deposit_receipt_version = - receipt.deposit_receipt_version.map(reth_primitives::U64::from); - } else if let Some(l1_block_info) = optimism_tx_meta.l1_block_info { - op_fields.l1_fee = optimism_tx_meta.l1_fee; - op_fields.l1_gas_used = optimism_tx_meta.l1_data_gas.map(|dg| { - dg + l1_block_info.l1_fee_overhead.unwrap_or_default().saturating_to::() - }); - op_fields.l1_fee_scalar = - Some(f64::from(l1_block_info.l1_base_fee_scalar) / 1_000_000.0); - op_fields.l1_gas_price = Some(l1_block_info.l1_base_fee.saturating_to()); - } - - res_receipt.other = op_fields.into(); - } - - match transaction.transaction.kind() { - Create => { - res_receipt.contract_address = Some(from.create(transaction.transaction.nonce())); - } - Call(addr) => { - res_receipt.to = Some(Address(*addr)); - } - } - - Ok(res_receipt) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::eth::{ - cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, FeeHistoryCacheConfig, - }; - use reth_evm_ethereum::EthEvmConfig; - use reth_network_api::noop::NoopNetwork; - use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex}; - use reth_provider::test_utils::NoopProvider; - use reth_tasks::pool::BlockingTaskPool; - use reth_transaction_pool::test_utils::testing_pool; - - #[tokio::test] - async fn send_raw_transaction() { - let noop_provider = NoopProvider::default(); - let noop_network_provider = NoopNetwork::default(); - - let pool = testing_pool(); - - let evm_config = EthEvmConfig::default(); - let cache = EthStateCache::spawn(noop_provider, Default::default(), evm_config); - let fee_history_cache = - FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); - let eth_api = EthApi::new( - noop_provider, - pool.clone(), - noop_network_provider, - cache.clone(), - GasPriceOracle::new(noop_provider, Default::default(), cache.clone()), - ETHEREUM_BLOCK_GAS_LIMIT, - BlockingTaskPool::build().expect("failed to build tracing pool"), - fee_history_cache, - evm_config, - None, - ); - - // https://etherscan.io/tx/0xa694b71e6c128a2ed8e2e0f6770bddbe52e3bb8f10e8472f9a79ab81497a8b5d - let tx_1 = Bytes::from(hex!("02f871018303579880850555633d1b82520894eee27662c2b8eba3cd936a23f039f3189633e4c887ad591c62bdaeb180c080a07ea72c68abfb8fca1bd964f0f99132ed9280261bdca3e549546c0205e800f7d0a05b4ef3039e9c9b9babc179a1878fb825b5aaf5aed2fa8744854150157b08d6f3")); - - let tx_1_result = eth_api.send_raw_transaction(tx_1).await.unwrap(); - assert_eq!( - pool.len(), - 1, - "expect 1 transactions in the pool, but pool size is {}", - pool.len() - ); - - // https://etherscan.io/tx/0x48816c2f32c29d152b0d86ff706f39869e6c1f01dc2fe59a3c1f9ecf39384694 - let tx_2 = Bytes::from(hex!("02f9043c018202b7843b9aca00850c807d37a08304d21d94ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b881bc16d674ec80000b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000063e2d99f00000000000000000000000000000000000000000000000000000000000000030b000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000065717fe021ea67801d1088cc80099004b05b64600000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e95fd5965fd1f1a6f0d4600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000428dca9537116148616a5a3e44035af17238fe9dc080a0c6ec1e41f5c0b9511c49b171ad4e04c6bb419c74d99fe9891d74126ec6e4e879a032069a753d7a2cfa158df95421724d24c0e9501593c09905abf3699b4a4405ce")); - - let tx_2_result = eth_api.send_raw_transaction(tx_2).await.unwrap(); - assert_eq!( - pool.len(), - 2, - "expect 2 transactions in the pool, but pool size is {}", - pool.len() - ); - - assert!(pool.get(&tx_1_result).is_some(), "tx1 not found in the pool"); - assert!(pool.get(&tx_2_result).is_some(), "tx2 not found in the pool"); - } -} diff --git a/crates/rpc/rpc/src/eth/bundle.rs b/crates/rpc/rpc/src/eth/bundle.rs index 97ea4bb4c0fe..894f2f80404b 100644 --- a/crates/rpc/rpc/src/eth/bundle.rs +++ b/crates/rpc/rpc/src/eth/bundle.rs @@ -1,19 +1,15 @@ //! `Eth` bundle implementation and helpers. -use crate::eth::{ - error::{EthApiError, EthResult, RpcInvalidTransactionError}, - revm_utils::FillableTransaction, - utils::recover_raw_transaction, - EthTransactions, -}; +use std::sync::Arc; + use jsonrpsee::core::RpcResult; +use reth_evm::{ConfigureEvm, ConfigureEvmEnv}; use reth_primitives::{ keccak256, revm_primitives::db::{DatabaseCommit, DatabaseRef}, PooledTransactionsElement, U256, }; use reth_revm::database::StateProviderDatabase; -use reth_rpc_api::EthCallBundleApiServer; use reth_rpc_types::{EthCallBundle, EthCallBundleResponse, EthCallBundleTransactionResult}; use reth_tasks::pool::BlockingTaskGuard; use revm::{ @@ -21,7 +17,14 @@ use revm::{ primitives::{ResultAndState, TxEnv}, }; use revm_primitives::{EnvKzgSettings, EnvWithHandlerCfg, MAX_BLOB_GAS_PER_BLOCK}; -use std::sync::Arc; + +use reth_rpc_eth_api::{ + helpers::{Call, EthTransactions, LoadPendingBlock}, + EthCallBundleApiServer, +}; +use reth_rpc_eth_types::{ + utils::recover_raw_transaction, EthApiError, EthResult, RpcInvalidTransactionError, +}; /// `Eth` bundle implementation. pub struct EthBundle { @@ -38,7 +41,7 @@ impl EthBundle { impl EthBundle where - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadPendingBlock + Call + 'static, { /// Simulates a bundle of transactions at the top of a given block number with the state of /// another (or the same) block. This can be used to simulate future blocks with the current @@ -98,6 +101,8 @@ where // use the block number of the request block_env.number = U256::from(block_number); + let eth_api = self.inner.eth_api.clone(); + self.inner .eth_api .spawn_with_state_at_block(at, move |state| { @@ -115,8 +120,7 @@ where let mut total_gas_fess = U256::ZERO; let mut hash_bytes = Vec::with_capacity(32 * transactions.len()); - let mut evm = - revm::Evm::builder().with_db(db).with_env_with_handler_cfg(env).build(); + let mut evm = Call::evm_config(ð_api).evm_with_env(db, env); let mut results = Vec::with_capacity(transactions.len()); let mut transactions = transactions.into_iter().peekable(); @@ -129,13 +133,13 @@ where .map_err(|e| EthApiError::InvalidParams(e.to_string()))?; } - let tx = tx.into_ecrecovered_transaction(signer); + let tx = tx.into_transaction(); hash_bytes.extend_from_slice(tx.hash().as_slice()); let gas_price = tx .effective_tip_per_gas(basefee) .ok_or_else(|| RpcInvalidTransactionError::FeeCapTooLow)?; - tx.try_fill_tx_env(evm.tx_mut())?; + Call::evm_config(ð_api).fill_tx_env(evm.tx_mut(), &tx, signer); let ResultAndState { result, state } = evm.transact()?; let gas_used = result.gas_used(); @@ -166,7 +170,7 @@ where let tx_res = EthCallBundleTransactionResult { coinbase_diff, eth_sent_to_coinbase, - from_address: tx.signer(), + from_address: signer, gas_fees, gas_price: U256::from(gas_price), gas_used, @@ -212,7 +216,7 @@ where #[async_trait::async_trait] impl EthCallBundleApiServer for EthBundle where - Eth: EthTransactions + 'static, + Eth: EthTransactions + LoadPendingBlock + Call + 'static, { async fn call_bundle(&self, request: EthCallBundle) -> RpcResult { Ok(Self::call_bundle(self, request).await?) diff --git a/crates/rpc/rpc/src/eth/core.rs b/crates/rpc/rpc/src/eth/core.rs new file mode 100644 index 000000000000..f2eb81851f9b --- /dev/null +++ b/crates/rpc/rpc/src/eth/core.rs @@ -0,0 +1,601 @@ +//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait +//! Handles RPC requests for the `eth_` namespace. + +use std::sync::Arc; + +use reth_primitives::{BlockNumberOrTag, U256}; +use reth_provider::{BlockReaderIdExt, ChainSpecProvider}; +use reth_rpc_eth_api::{ + helpers::{EthSigner, SpawnBlocking}, + RawTransactionForwarder, +}; +use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasCap, GasPriceOracle, PendingBlock}; +use reth_tasks::{pool::BlockingTaskPool, TaskSpawner, TokioTaskExecutor}; +use tokio::sync::Mutex; + +use crate::eth::DevSigner; + +/// `Eth` API implementation. +/// +/// This type provides the functionality for handling `eth_` related requests. +/// These are implemented two-fold: Core functionality is implemented as +/// [`EthApiSpec`](reth_rpc_eth_api::helpers::EthApiSpec) trait. Additionally, the required server +/// implementations (e.g. [`EthApiServer`](reth_rpc_eth_api::EthApiServer)) are implemented +/// separately in submodules. The rpc handler implementation can then delegate to the main impls. +/// This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone or in other +/// network handlers (for example ipc). +pub struct EthApi { + /// All nested fields bundled together. + pub(super) inner: Arc>, +} + +impl EthApi { + /// Sets a forwarder for `eth_sendRawTransaction` + /// + /// Note: this might be removed in the future in favor of a more generic approach. + pub fn set_eth_raw_transaction_forwarder(&self, forwarder: Arc) { + self.inner.raw_transaction_forwarder.write().replace(forwarder); + } +} + +impl EthApi +where + Provider: BlockReaderIdExt + ChainSpecProvider, +{ + /// Creates a new, shareable instance using the default tokio task spawner. + #[allow(clippy::too_many_arguments)] + pub fn new( + provider: Provider, + pool: Pool, + network: Network, + eth_cache: EthStateCache, + gas_oracle: GasPriceOracle, + gas_cap: impl Into, + blocking_task_pool: BlockingTaskPool, + fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, + raw_transaction_forwarder: Option>, + ) -> Self { + Self::with_spawner( + provider, + pool, + network, + eth_cache, + gas_oracle, + gas_cap.into().into(), + Box::::default(), + blocking_task_pool, + fee_history_cache, + evm_config, + raw_transaction_forwarder, + ) + } + + /// Creates a new, shareable instance. + #[allow(clippy::too_many_arguments)] + pub fn with_spawner( + provider: Provider, + pool: Pool, + network: Network, + eth_cache: EthStateCache, + gas_oracle: GasPriceOracle, + gas_cap: u64, + task_spawner: Box, + blocking_task_pool: BlockingTaskPool, + fee_history_cache: FeeHistoryCache, + evm_config: EvmConfig, + raw_transaction_forwarder: Option>, + ) -> Self { + // get the block number of the latest block + let latest_block = provider + .header_by_number_or_tag(BlockNumberOrTag::Latest) + .ok() + .flatten() + .map(|header| header.number) + .unwrap_or_default(); + + let inner = EthApiInner { + provider, + pool, + network, + signers: parking_lot::RwLock::new(Default::default()), + eth_cache, + gas_oracle, + gas_cap, + starting_block: U256::from(latest_block), + task_spawner, + pending_block: Default::default(), + blocking_task_pool, + fee_history_cache, + evm_config, + raw_transaction_forwarder: parking_lot::RwLock::new(raw_transaction_forwarder), + }; + + Self { inner: Arc::new(inner) } + } + + /// Returns the state cache frontend + pub fn cache(&self) -> &EthStateCache { + &self.inner.eth_cache + } + + /// Returns the gas oracle frontend + pub fn gas_oracle(&self) -> &GasPriceOracle { + &self.inner.gas_oracle + } + + /// Returns the configured gas limit cap for `eth_call` and tracing related calls + pub fn gas_cap(&self) -> u64 { + self.inner.gas_cap + } + + /// Returns the inner `Provider` + pub fn provider(&self) -> &Provider { + &self.inner.provider + } + + /// Returns the inner `Network` + pub fn network(&self) -> &Network { + &self.inner.network + } + + /// Returns the inner `Pool` + pub fn pool(&self) -> &Pool { + &self.inner.pool + } + + /// Returns fee history cache + pub fn fee_history_cache(&self) -> &FeeHistoryCache { + &self.inner.fee_history_cache + } +} + +impl std::fmt::Debug + for EthApi +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EthApi").finish_non_exhaustive() + } +} + +impl Clone for EthApi { + fn clone(&self) -> Self { + Self { inner: Arc::clone(&self.inner) } + } +} + +impl SpawnBlocking + for EthApi +where + Self: Clone + Send + Sync + 'static, +{ + #[inline] + fn io_task_spawner(&self) -> impl reth_tasks::TaskSpawner { + self.inner.task_spawner() + } + + #[inline] + fn tracing_task_pool(&self) -> &reth_tasks::pool::BlockingTaskPool { + self.inner.blocking_task_pool() + } +} + +impl EthApi { + /// Generates 20 random developer accounts. + /// Used in DEV mode. + pub fn with_dev_accounts(&self) { + let mut signers = self.inner.signers.write(); + *signers = DevSigner::random_signers(20); + } +} + +/// Container type `EthApi` +#[allow(missing_debug_implementations)] +pub struct EthApiInner { + /// The transaction pool. + pool: Pool, + /// The provider that can interact with the chain. + provider: Provider, + /// An interface to interact with the network + network: Network, + /// All configured Signers + signers: parking_lot::RwLock>>, + /// The async cache frontend for eth related data + eth_cache: EthStateCache, + /// The async gas oracle frontend for gas price suggestions + gas_oracle: GasPriceOracle, + /// Maximum gas limit for `eth_call` and call tracing RPC methods. + gas_cap: u64, + /// The block number at which the node started + starting_block: U256, + /// The type that can spawn tasks which would otherwise block. + task_spawner: Box, + /// Cached pending block if any + pending_block: Mutex>, + /// A pool dedicated to CPU heavy blocking tasks. + blocking_task_pool: BlockingTaskPool, + /// Cache for block fees history + fee_history_cache: FeeHistoryCache, + /// The type that defines how to configure the EVM + evm_config: EvmConfig, + /// Allows forwarding received raw transactions + raw_transaction_forwarder: parking_lot::RwLock>>, +} + +impl EthApiInner { + /// Returns a handle to data on disk. + #[inline] + pub const fn provider(&self) -> &Provider { + &self.provider + } + + /// Returns a handle to data in memory. + #[inline] + pub const fn cache(&self) -> &EthStateCache { + &self.eth_cache + } + + /// Returns a handle to the pending block. + #[inline] + pub const fn pending_block(&self) -> &Mutex> { + &self.pending_block + } + + /// Returns a handle to the task spawner. + #[inline] + pub const fn task_spawner(&self) -> &dyn TaskSpawner { + &*self.task_spawner + } + + /// Returns a handle to the blocking thread pool. + #[inline] + pub const fn blocking_task_pool(&self) -> &BlockingTaskPool { + &self.blocking_task_pool + } + + /// Returns a handle to the EVM config. + #[inline] + pub const fn evm_config(&self) -> &EvmConfig { + &self.evm_config + } + + /// Returns a handle to the transaction pool. + #[inline] + pub const fn pool(&self) -> &Pool { + &self.pool + } + + /// Returns a handle to the transaction forwarder. + #[inline] + pub fn raw_tx_forwarder(&self) -> Option> { + self.raw_transaction_forwarder.read().clone() + } + + /// Returns the gas cap. + #[inline] + pub const fn gas_cap(&self) -> u64 { + self.gas_cap + } + + /// Returns a handle to the gas oracle. + #[inline] + pub const fn gas_oracle(&self) -> &GasPriceOracle { + &self.gas_oracle + } + + /// Returns a handle to the fee history cache. + #[inline] + pub const fn fee_history_cache(&self) -> &FeeHistoryCache { + &self.fee_history_cache + } + + /// Returns a handle to the signers. + #[inline] + pub const fn signers(&self) -> &parking_lot::RwLock>> { + &self.signers + } + + /// Returns the starting block. + #[inline] + pub const fn starting_block(&self) -> U256 { + self.starting_block + } +} + +#[cfg(test)] +mod tests { + use jsonrpsee_types::error::INVALID_PARAMS_CODE; + use reth_chainspec::BaseFeeParams; + use reth_evm_ethereum::EthEvmConfig; + use reth_network_api::noop::NoopNetwork; + use reth_primitives::{ + constants::ETHEREUM_BLOCK_GAS_LIMIT, Block, BlockNumberOrTag, Header, TransactionSigned, + B256, U64, + }; + use reth_provider::{ + test_utils::{MockEthProvider, NoopProvider}, + BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, + }; + use reth_rpc_eth_api::EthApiServer; + use reth_rpc_eth_types::{ + EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, + }; + use reth_rpc_types::FeeHistory; + use reth_tasks::pool::BlockingTaskPool; + use reth_testing_utils::{generators, generators::Rng}; + use reth_transaction_pool::test_utils::{testing_pool, TestPool}; + + use crate::EthApi; + + fn build_test_eth_api< + P: BlockReaderIdExt + + BlockReader + + ChainSpecProvider + + EvmEnvProvider + + StateProviderFactory + + Unpin + + Clone + + 'static, + >( + provider: P, + ) -> EthApi { + let evm_config = EthEvmConfig::default(); + let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config); + let fee_history_cache = + FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); + + EthApi::new( + provider.clone(), + testing_pool(), + NoopNetwork::default(), + cache.clone(), + GasPriceOracle::new(provider, Default::default(), cache), + ETHEREUM_BLOCK_GAS_LIMIT, + BlockingTaskPool::build().expect("failed to build tracing pool"), + fee_history_cache, + evm_config, + None, + ) + } + + // Function to prepare the EthApi with mock data + fn prepare_eth_api( + newest_block: u64, + mut oldest_block: Option, + block_count: u64, + mock_provider: MockEthProvider, + ) -> (EthApi, Vec, Vec) { + let mut rng = generators::rng(); + + // Build mock data + let mut gas_used_ratios = Vec::new(); + let mut base_fees_per_gas = Vec::new(); + let mut last_header = None; + let mut parent_hash = B256::default(); + + for i in (0..block_count).rev() { + let hash = rng.gen(); + let gas_limit: u64 = rng.gen(); + let gas_used: u64 = rng.gen(); + // Note: Generates a u32 to avoid overflows later + let base_fee_per_gas: Option = rng.gen::().then(|| rng.gen::() as u64); + + let header = Header { + number: newest_block - i, + gas_limit, + gas_used, + base_fee_per_gas, + parent_hash, + ..Default::default() + }; + last_header = Some(header.clone()); + parent_hash = hash; + + let mut transactions = vec![]; + for _ in 0..100 { + let random_fee: u128 = rng.gen(); + + if let Some(base_fee_per_gas) = header.base_fee_per_gas { + let transaction = TransactionSigned { + transaction: reth_primitives::Transaction::Eip1559( + reth_primitives::TxEip1559 { + max_priority_fee_per_gas: random_fee, + max_fee_per_gas: random_fee + base_fee_per_gas as u128, + ..Default::default() + }, + ), + ..Default::default() + }; + + transactions.push(transaction); + } else { + let transaction = TransactionSigned { + transaction: reth_primitives::Transaction::Legacy(Default::default()), + ..Default::default() + }; + + transactions.push(transaction); + } + } + + mock_provider.add_block( + hash, + Block { header: header.clone(), body: transactions, ..Default::default() }, + ); + mock_provider.add_header(hash, header); + + oldest_block.get_or_insert(hash); + gas_used_ratios.push(gas_used as f64 / gas_limit as f64); + base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default()); + } + + // Add final base fee (for the next block outside of the request) + let last_header = last_header.unwrap(); + base_fees_per_gas.push(BaseFeeParams::ethereum().next_block_base_fee( + last_header.gas_used as u128, + last_header.gas_limit as u128, + last_header.base_fee_per_gas.unwrap_or_default() as u128, + )); + + let eth_api = build_test_eth_api(mock_provider); + + (eth_api, base_fees_per_gas, gas_used_ratios) + } + + /// Invalid block range + #[tokio::test] + async fn test_fee_history_empty() { + let response = as EthApiServer>::fee_history( + &build_test_eth_api(NoopProvider::default()), + U64::from(1), + BlockNumberOrTag::Latest, + None, + ) + .await; + assert!(response.is_err()); + let error_object = response.unwrap_err(); + assert_eq!(error_object.code(), INVALID_PARAMS_CODE); + } + + #[tokio::test] + /// Invalid block range (request is before genesis) + async fn test_fee_history_invalid_block_range_before_genesis() { + let block_count = 10; + let newest_block = 1337; + let oldest_block = None; + + let (eth_api, _, _) = + prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); + + let response = as EthApiServer>::fee_history( + ð_api, + U64::from(newest_block + 1), + newest_block.into(), + Some(vec![10.0]), + ) + .await; + + assert!(response.is_err()); + let error_object = response.unwrap_err(); + assert_eq!(error_object.code(), INVALID_PARAMS_CODE); + } + + #[tokio::test] + /// Invalid block range (request is in the future) + async fn test_fee_history_invalid_block_range_in_future() { + let block_count = 10; + let newest_block = 1337; + let oldest_block = None; + + let (eth_api, _, _) = + prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); + + let response = as EthApiServer>::fee_history( + ð_api, + U64::from(1), + (newest_block + 1000).into(), + Some(vec![10.0]), + ) + .await; + + assert!(response.is_err()); + let error_object = response.unwrap_err(); + assert_eq!(error_object.code(), INVALID_PARAMS_CODE); + } + + #[tokio::test] + /// Requesting no block should result in a default response + async fn test_fee_history_no_block_requested() { + let block_count = 10; + let newest_block = 1337; + let oldest_block = None; + + let (eth_api, _, _) = + prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); + + let response = as EthApiServer>::fee_history( + ð_api, + U64::from(0), + newest_block.into(), + None, + ) + .await + .unwrap(); + assert_eq!( + response, + FeeHistory::default(), + "none: requesting no block should yield a default response" + ); + } + + #[tokio::test] + /// Requesting a single block should return 1 block (+ base fee for the next block over) + async fn test_fee_history_single_block() { + let block_count = 10; + let newest_block = 1337; + let oldest_block = None; + + let (eth_api, base_fees_per_gas, gas_used_ratios) = + prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); + + let fee_history = + eth_api.fee_history(U64::from(1), newest_block.into(), None).await.unwrap(); + assert_eq!( + fee_history.base_fee_per_gas, + &base_fees_per_gas[base_fees_per_gas.len() - 2..], + "one: base fee per gas is incorrect" + ); + assert_eq!( + fee_history.base_fee_per_gas.len(), + 2, + "one: should return base fee of the next block as well" + ); + assert_eq!( + &fee_history.gas_used_ratio, + &gas_used_ratios[gas_used_ratios.len() - 1..], + "one: gas used ratio is incorrect" + ); + assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect"); + assert!( + fee_history.reward.is_none(), + "one: no percentiles were requested, so there should be no rewards result" + ); + } + + /// Requesting all blocks should be ok + #[tokio::test] + async fn test_fee_history_all_blocks() { + let block_count = 10; + let newest_block = 1337; + let oldest_block = None; + + let (eth_api, base_fees_per_gas, gas_used_ratios) = + prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); + + let fee_history = + eth_api.fee_history(U64::from(block_count), newest_block.into(), None).await.unwrap(); + + assert_eq!( + &fee_history.base_fee_per_gas, &base_fees_per_gas, + "all: base fee per gas is incorrect" + ); + assert_eq!( + fee_history.base_fee_per_gas.len() as u64, + block_count + 1, + "all: should return base fee of the next block as well" + ); + assert_eq!( + &fee_history.gas_used_ratio, &gas_used_ratios, + "all: gas used ratio is incorrect" + ); + assert_eq!( + fee_history.oldest_block, + newest_block - block_count + 1, + "all: oldest block is incorrect" + ); + assert!( + fee_history.reward.is_none(), + "all: no percentiles were requested, so there should be no rewards result" + ); + } +} diff --git a/crates/rpc/rpc/src/eth/filter.rs b/crates/rpc/rpc/src/eth/filter.rs index 1fea2df4a4b4..1a2e55a5257c 100644 --- a/crates/rpc/rpc/src/eth/filter.rs +++ b/crates/rpc/rpc/src/eth/filter.rs @@ -1,34 +1,31 @@ -use super::cache::EthStateCache; -use crate::{ - eth::{ - error::EthApiError, - logs_utils::{self, append_matching_block_logs}, - }, - result::{rpc_error_with_code, ToRpcResult}, - EthSubscriptionIdProvider, +//! `eth_` `Filter` RPC handler implementation + +use std::{ + collections::HashMap, + fmt, + iter::StepBy, + ops::RangeInclusive, + sync::Arc, + time::{Duration, Instant}, }; -use core::fmt; use async_trait::async_trait; use jsonrpsee::{core::RpcResult, server::IdProvider}; use reth_chainspec::ChainInfo; use reth_primitives::{IntoRecoveredTransaction, TxHash}; use reth_provider::{BlockIdReader, BlockReader, EvmEnvProvider, ProviderError}; -use reth_rpc_api::EthFilterApiServer; +use reth_rpc_eth_api::EthFilterApiServer; +use reth_rpc_eth_types::{ + logs_utils::{self, append_matching_block_logs}, + EthApiError, EthFilterError, EthStateCache, EthSubscriptionIdProvider, +}; +use reth_rpc_server_types::ToRpcResult; use reth_rpc_types::{ BlockNumHash, Filter, FilterBlockOption, FilterChanges, FilterId, FilteredParams, Log, PendingTransactionFilterKind, }; - use reth_tasks::TaskSpawner; use reth_transaction_pool::{NewSubpoolTransactionStream, PoolTransaction, TransactionPool}; -use std::{ - collections::HashMap, - iter::StepBy, - ops::RangeInclusive, - sync::Arc, - time::{Duration, Instant}, -}; use tokio::{ sync::{mpsc::Receiver, Mutex}, time::MissedTickBehavior, @@ -132,7 +129,7 @@ where ::Transaction: 'static, { /// Returns all the filter changes for the given id, if any - pub async fn filter_changes(&self, id: FilterId) -> Result { + pub async fn filter_changes(&self, id: FilterId) -> Result { let info = self.inner.provider.chain_info()?; let best_number = info.best_number; @@ -140,7 +137,7 @@ where // the last time changes were polled, in other words the best block at last poll + 1 let (start_block, kind) = { let mut filters = self.inner.active_filters.inner.lock().await; - let filter = filters.get_mut(&id).ok_or(FilterError::FilterNotFound(id))?; + let filter = filters.get_mut(&id).ok_or(EthFilterError::FilterNotFound(id))?; if filter.block > best_number { // no new blocks since the last poll @@ -204,16 +201,16 @@ where /// Returns an error if no matching log filter exists. /// /// Handler for `eth_getFilterLogs` - pub async fn filter_logs(&self, id: FilterId) -> Result, FilterError> { + pub async fn filter_logs(&self, id: FilterId) -> Result, EthFilterError> { let filter = { let filters = self.inner.active_filters.inner.lock().await; if let FilterKind::Log(ref filter) = - filters.get(&id).ok_or_else(|| FilterError::FilterNotFound(id.clone()))?.kind + filters.get(&id).ok_or_else(|| EthFilterError::FilterNotFound(id.clone()))?.kind { *filter.clone() } else { // Not a log filter - return Err(FilterError::FilterNotFound(id)) + return Err(EthFilterError::FilterNotFound(id)) } }; @@ -347,7 +344,7 @@ where Pool: TransactionPool + 'static, { /// Returns logs matching given filter object. - async fn logs_for_filter(&self, filter: Filter) -> Result, FilterError> { + async fn logs_for_filter(&self, filter: Filter) -> Result, EthFilterError> { match filter.block_option { FilterBlockOption::AtBlockHash(block_hash) => { // for all matching logs in the block @@ -428,16 +425,16 @@ where from_block: u64, to_block: u64, chain_info: ChainInfo, - ) -> Result, FilterError> { + ) -> Result, EthFilterError> { trace!(target: "rpc::eth::filter", from=from_block, to=to_block, ?filter, "finding logs in range"); let best_number = chain_info.best_number; if to_block < from_block { - return Err(FilterError::InvalidBlockRangeParams) + return Err(EthFilterError::InvalidBlockRangeParams) } if to_block - from_block > self.max_blocks_per_filter { - return Err(FilterError::QueryExceedsMaxBlocks(self.max_blocks_per_filter)) + return Err(EthFilterError::QueryExceedsMaxBlocks(self.max_blocks_per_filter)) } let mut all_logs = Vec::new(); @@ -505,7 +502,7 @@ where // logs of a single block let is_multi_block_range = from_block != to_block; if is_multi_block_range && all_logs.len() > self.max_logs_per_response { - return Err(FilterError::QueryExceedsMaxResults( + return Err(EthFilterError::QueryExceedsMaxResults( self.max_logs_per_response, )) } @@ -682,51 +679,6 @@ enum FilterKind { PendingTransaction(PendingTransactionKind), } -/// Errors that can occur in the handler implementation -#[derive(Debug, thiserror::Error)] -pub enum FilterError { - #[error("filter not found")] - FilterNotFound(FilterId), - #[error("invalid block range params")] - InvalidBlockRangeParams, - #[error("query exceeds max block range {0}")] - QueryExceedsMaxBlocks(u64), - #[error("query exceeds max results {0}")] - QueryExceedsMaxResults(usize), - #[error(transparent)] - EthAPIError(#[from] EthApiError), - /// Error thrown when a spawned task failed to deliver a response. - #[error("internal filter error")] - InternalError, -} - -// convert the error -impl From for jsonrpsee::types::error::ErrorObject<'static> { - fn from(err: FilterError) -> Self { - match err { - FilterError::FilterNotFound(_) => rpc_error_with_code( - jsonrpsee::types::error::INVALID_PARAMS_CODE, - "filter not found", - ), - err @ FilterError::InternalError => { - rpc_error_with_code(jsonrpsee::types::error::INTERNAL_ERROR_CODE, err.to_string()) - } - FilterError::EthAPIError(err) => err.into(), - err @ FilterError::InvalidBlockRangeParams | - err @ FilterError::QueryExceedsMaxBlocks(_) | - err @ FilterError::QueryExceedsMaxResults(_) => { - rpc_error_with_code(jsonrpsee::types::error::INVALID_PARAMS_CODE, err.to_string()) - } - } - } -} - -impl From for FilterError { - fn from(err: ProviderError) -> Self { - Self::EthAPIError(err.into()) - } -} - /// An iterator that yields _inclusive_ block ranges of a given step size #[derive(Debug)] struct BlockRangeInclusiveIter { diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs new file mode 100644 index 000000000000..2ce6c7ed2e93 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -0,0 +1,34 @@ +//! Contains RPC handler implementations specific to blocks. + +use reth_provider::{BlockReaderIdExt, HeaderProvider}; +use reth_rpc_eth_api::helpers::{EthBlocks, LoadBlock, LoadPendingBlock, SpawnBlocking}; +use reth_rpc_eth_types::EthStateCache; + +use crate::EthApi; + +impl EthBlocks for EthApi +where + Self: LoadBlock, + Provider: HeaderProvider, +{ + #[inline] + fn provider(&self) -> impl reth_provider::HeaderProvider { + self.inner.provider() + } +} + +impl LoadBlock for EthApi +where + Self: LoadPendingBlock + SpawnBlocking, + Provider: BlockReaderIdExt, +{ + #[inline] + fn provider(&self) -> impl BlockReaderIdExt { + self.inner.provider() + } + + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/call.rs b/crates/rpc/rpc/src/eth/helpers/call.rs new file mode 100644 index 000000000000..c442c46b4b80 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/call.rs @@ -0,0 +1,27 @@ +//! Contains RPC handler implementations specific to endpoints that call/execute within evm. + +use reth_evm::ConfigureEvm; +use reth_rpc_eth_api::helpers::{Call, EthCall, LoadPendingBlock, LoadState, SpawnBlocking}; + +use crate::EthApi; + +impl EthCall for EthApi where + Self: Call + LoadPendingBlock +{ +} + +impl Call for EthApi +where + Self: LoadState + SpawnBlocking, + EvmConfig: ConfigureEvm, +{ + #[inline] + fn call_gas_limit(&self) -> u64 { + self.inner.gas_cap() + } + + #[inline] + fn evm_config(&self) -> &impl ConfigureEvm { + self.inner.evm_config() + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/fees.rs b/crates/rpc/rpc/src/eth/helpers/fees.rs new file mode 100644 index 000000000000..7380f4ea2c20 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/fees.rs @@ -0,0 +1,39 @@ +//! Contains RPC handler implementations for fee history. + +use reth_provider::{BlockIdReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider}; + +use reth_rpc_eth_api::helpers::{EthFees, LoadBlock, LoadFee}; +use reth_rpc_eth_types::{EthStateCache, FeeHistoryCache, GasPriceOracle}; + +use crate::EthApi; + +impl EthFees for EthApi where + Self: LoadFee +{ +} + +impl LoadFee for EthApi +where + Self: LoadBlock, + Provider: BlockReaderIdExt + HeaderProvider + ChainSpecProvider, +{ + #[inline] + fn provider(&self) -> impl BlockIdReader + HeaderProvider + ChainSpecProvider { + self.inner.provider() + } + + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } + + #[inline] + fn gas_oracle(&self) -> &GasPriceOracle { + self.inner.gas_oracle() + } + + #[inline] + fn fee_history_cache(&self) -> &FeeHistoryCache { + self.inner.fee_history_cache() + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/mod.rs b/crates/rpc/rpc/src/eth/helpers/mod.rs new file mode 100644 index 000000000000..4c86e2b5fa18 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/mod.rs @@ -0,0 +1,18 @@ +//! The entire implementation of the namespace is quite large, hence it is divided across several +//! files. + +pub mod signer; + +mod block; +mod call; +mod fees; +#[cfg(feature = "optimism")] +pub mod optimism; +#[cfg(not(feature = "optimism"))] +mod pending_block; +#[cfg(not(feature = "optimism"))] +mod receipt; +mod spec; +mod state; +mod trace; +mod transaction; diff --git a/crates/rpc/rpc/src/eth/helpers/optimism.rs b/crates/rpc/rpc/src/eth/helpers/optimism.rs new file mode 100644 index 000000000000..751c06463a00 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/optimism.rs @@ -0,0 +1,231 @@ +//! Loads and formats OP transaction RPC response. + +use jsonrpsee_types::error::ErrorObject; +use reth_evm::ConfigureEvm; +use reth_evm_optimism::RethL1BlockInfo; +use reth_primitives::{ + BlockNumber, Receipt, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, B256, +}; +use reth_provider::{ + BlockIdReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ExecutionOutcome, + StateProviderFactory, +}; +use reth_rpc_types::{AnyTransactionReceipt, OptimismTransactionReceiptFields, ToRpcError}; +use reth_transaction_pool::TransactionPool; +use revm::L1BlockInfo; +use revm_primitives::{BlockEnv, ExecutionResult}; + +use reth_rpc_eth_api::helpers::{LoadPendingBlock, LoadReceipt, SpawnBlocking}; +use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, PendingBlock, ReceiptBuilder}; +use reth_rpc_server_types::result::internal_rpc_err; + +use crate::EthApi; + +/// L1 fee and data gas for a transaction, along with the L1 block info. +#[derive(Debug, Default, Clone)] +pub struct OptimismTxMeta { + /// The L1 block info. + pub l1_block_info: Option, + /// The L1 fee for the block. + pub l1_fee: Option, + /// The L1 data gas for the block. + pub l1_data_gas: Option, +} + +impl OptimismTxMeta { + /// Creates a new [`OptimismTxMeta`]. + pub const fn new( + l1_block_info: Option, + l1_fee: Option, + l1_data_gas: Option, + ) -> Self { + Self { l1_block_info, l1_fee, l1_data_gas } + } +} + +impl EthApi +where + Provider: BlockIdReader + ChainSpecProvider, +{ + /// Builds [`OptimismTxMeta`] object using the provided [`TransactionSigned`], L1 block + /// info and block timestamp. The [`L1BlockInfo`] is used to calculate the l1 fee and l1 data + /// gas for the transaction. If the [`L1BlockInfo`] is not provided, the meta info will be + /// empty. + pub fn build_op_tx_meta( + &self, + tx: &TransactionSigned, + l1_block_info: Option, + block_timestamp: u64, + ) -> EthResult { + let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) }; + + let (l1_fee, l1_data_gas) = if !tx.is_deposit() { + let envelope_buf = tx.envelope_encoded(); + + let inner_l1_fee = l1_block_info + .l1_tx_data_fee( + &self.inner.provider().chain_spec(), + block_timestamp, + &envelope_buf, + tx.is_deposit(), + ) + .map_err(|_| OptimismEthApiError::L1BlockFeeError)?; + let inner_l1_data_gas = l1_block_info + .l1_data_gas(&self.inner.provider().chain_spec(), block_timestamp, &envelope_buf) + .map_err(|_| OptimismEthApiError::L1BlockGasError)?; + ( + Some(inner_l1_fee.saturating_to::()), + Some(inner_l1_data_gas.saturating_to::()), + ) + } else { + (None, None) + }; + + Ok(OptimismTxMeta::new(Some(l1_block_info), l1_fee, l1_data_gas)) + } +} + +impl LoadReceipt for EthApi +where + Self: Send + Sync, + Provider: BlockIdReader + ChainSpecProvider, +{ + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } + + async fn build_transaction_receipt( + &self, + tx: TransactionSigned, + meta: TransactionMeta, + receipt: Receipt, + ) -> EthResult { + let (block, receipts) = self + .cache() + .get_block_and_receipts(meta.block_hash) + .await? + .ok_or(EthApiError::UnknownBlockNumber)?; + + let block = block.unseal(); + let l1_block_info = reth_evm_optimism::extract_l1_info(&block).ok(); + let optimism_tx_meta = self.build_op_tx_meta(&tx, l1_block_info, block.timestamp)?; + + let resp_builder = ReceiptBuilder::new(&tx, meta, &receipt, &receipts)?; + let resp_builder = op_receipt_fields(resp_builder, &tx, &receipt, optimism_tx_meta); + + Ok(resp_builder.build()) + } +} + +/// Applies OP specific fields to a receipt. +fn op_receipt_fields( + resp_builder: ReceiptBuilder, + tx: &TransactionSigned, + receipt: &Receipt, + optimism_tx_meta: OptimismTxMeta, +) -> ReceiptBuilder { + let mut op_fields = OptimismTransactionReceiptFields::default(); + + if tx.is_deposit() { + op_fields.deposit_nonce = receipt.deposit_nonce.map(reth_primitives::U64::from); + op_fields.deposit_receipt_version = + receipt.deposit_receipt_version.map(reth_primitives::U64::from); + } else if let Some(l1_block_info) = optimism_tx_meta.l1_block_info { + op_fields.l1_fee = optimism_tx_meta.l1_fee; + op_fields.l1_gas_used = optimism_tx_meta.l1_data_gas.map(|dg| { + dg + l1_block_info.l1_fee_overhead.unwrap_or_default().saturating_to::() + }); + op_fields.l1_fee_scalar = Some(f64::from(l1_block_info.l1_base_fee_scalar) / 1_000_000.0); + op_fields.l1_gas_price = Some(l1_block_info.l1_base_fee.saturating_to()); + } + + resp_builder.add_other_fields(op_fields.into()) +} + +impl LoadPendingBlock + for EthApi +where + Self: SpawnBlocking, + Provider: BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory, + Pool: TransactionPool, + EvmConfig: ConfigureEvm, +{ + #[inline] + fn provider( + &self, + ) -> impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory { + self.inner.provider() + } + + #[inline] + fn pool(&self) -> impl reth_transaction_pool::TransactionPool { + self.inner.pool() + } + + #[inline] + fn pending_block(&self) -> &tokio::sync::Mutex> { + self.inner.pending_block() + } + + #[inline] + fn evm_config(&self) -> &impl reth_evm::ConfigureEvm { + self.inner.evm_config() + } + + fn assemble_receipt( + &self, + tx: &TransactionSignedEcRecovered, + result: ExecutionResult, + cumulative_gas_used: u64, + ) -> Receipt { + Receipt { + tx_type: tx.tx_type(), + success: result.is_success(), + cumulative_gas_used, + logs: result.into_logs().into_iter().map(Into::into).collect(), + deposit_nonce: None, + deposit_receipt_version: None, + } + } + + fn receipts_root( + &self, + _block_env: &BlockEnv, + execution_outcome: &ExecutionOutcome, + block_number: BlockNumber, + ) -> B256 { + execution_outcome + .optimism_receipts_root_slow( + block_number, + self.provider().chain_spec().as_ref(), + _block_env.timestamp.to::(), + ) + .expect("Block is present") + } +} + +/// Optimism specific errors, that extend [`EthApiError`]. +#[derive(Debug, thiserror::Error)] +pub enum OptimismEthApiError { + /// Thrown when calculating L1 gas fee. + #[error("failed to calculate l1 gas fee")] + L1BlockFeeError, + /// Thrown when calculating L1 gas used + #[error("failed to calculate l1 gas used")] + L1BlockGasError, +} + +impl ToRpcError for OptimismEthApiError { + fn to_rpc_error(&self) -> ErrorObject<'static> { + match self { + Self::L1BlockFeeError | Self::L1BlockGasError => internal_rpc_err(self.to_string()), + } + } +} + +impl From for EthApiError { + fn from(err: OptimismEthApiError) -> Self { + Self::other(err) + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/pending_block.rs b/crates/rpc/rpc/src/eth/helpers/pending_block.rs new file mode 100644 index 000000000000..d1a47da75853 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/pending_block.rs @@ -0,0 +1,40 @@ +//! Support for building a pending block with transactions from local view of mempool. + +use reth_evm::ConfigureEvm; +use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; +use reth_rpc_eth_api::helpers::{LoadPendingBlock, SpawnBlocking}; +use reth_rpc_eth_types::PendingBlock; +use reth_transaction_pool::TransactionPool; + +use crate::EthApi; + +impl LoadPendingBlock + for EthApi +where + Self: SpawnBlocking, + Provider: BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory, + Pool: TransactionPool, + EvmConfig: reth_evm::ConfigureEvm, +{ + #[inline] + fn provider( + &self, + ) -> impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory { + self.inner.provider() + } + + #[inline] + fn pool(&self) -> impl TransactionPool { + self.inner.pool() + } + + #[inline] + fn pending_block(&self) -> &tokio::sync::Mutex> { + self.inner.pending_block() + } + + #[inline] + fn evm_config(&self) -> &impl ConfigureEvm { + self.inner.evm_config() + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs new file mode 100644 index 000000000000..db1fee781fd3 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -0,0 +1,16 @@ +//! Builds an RPC receipt response w.r.t. data layout of network. + +use reth_rpc_eth_api::helpers::LoadReceipt; +use reth_rpc_eth_types::EthStateCache; + +use crate::EthApi; + +impl LoadReceipt for EthApi +where + Self: Send + Sync, +{ + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } +} diff --git a/crates/rpc/rpc/src/eth/signer.rs b/crates/rpc/rpc/src/eth/helpers/signer.rs similarity index 85% rename from crates/rpc/rpc/src/eth/signer.rs rename to crates/rpc/rpc/src/eth/helpers/signer.rs index 50c06159c4f0..a4cb726a2915 100644 --- a/crates/rpc/rpc/src/eth/signer.rs +++ b/crates/rpc/rpc/src/eth/helpers/signer.rs @@ -1,49 +1,20 @@ //! An abstraction over ethereum signers. -use crate::eth::error::SignError; +use std::collections::HashMap; + use alloy_dyn_abi::TypedData; use reth_primitives::{ eip191_hash_message, sign_message, Address, Signature, TransactionSigned, B256, }; +use reth_rpc_eth_api::helpers::{signer::Result, EthSigner}; +use reth_rpc_eth_types::SignError; use reth_rpc_types::TypedTransactionRequest; - -use dyn_clone::DynClone; use reth_rpc_types_compat::transaction::to_primitive_transaction; use secp256k1::SecretKey; -use std::collections::HashMap; - -type Result = std::result::Result; - -/// An Ethereum Signer used via RPC. -#[async_trait::async_trait] -pub(crate) trait EthSigner: Send + Sync + DynClone { - /// Returns the available accounts for this signer. - fn accounts(&self) -> Vec
; - - /// Returns `true` whether this signer can sign for this address - fn is_signer_for(&self, addr: &Address) -> bool { - self.accounts().contains(addr) - } - - /// Returns the signature - async fn sign(&self, address: Address, message: &[u8]) -> Result; - - /// signs a transaction request using the given account in request - fn sign_transaction( - &self, - request: TypedTransactionRequest, - address: &Address, - ) -> Result; - - /// Encodes and signs the typed data according EIP-712. Payload must implement Eip712 trait. - fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result; -} - -dyn_clone::clone_trait_object!(EthSigner); /// Holds developer keys -#[derive(Clone)] -pub(crate) struct DevSigner { +#[derive(Debug, Clone)] +pub struct DevSigner { addresses: Vec
, accounts: HashMap, } @@ -121,9 +92,12 @@ impl EthSigner for DevSigner { #[cfg(test)] mod tests { - use super::*; - use reth_primitives::U256; use std::str::FromStr; + + use reth_primitives::U256; + + use super::*; + fn build_signer() -> DevSigner { let addresses = vec![]; let secret = diff --git a/crates/rpc/rpc/src/eth/helpers/spec.rs b/crates/rpc/rpc/src/eth/helpers/spec.rs new file mode 100644 index 000000000000..a93d662eaf6e --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/spec.rs @@ -0,0 +1,65 @@ +use reth_chainspec::ChainInfo; +use reth_errors::{RethError, RethResult}; +use reth_evm::ConfigureEvm; +use reth_network_api::NetworkInfo; +use reth_primitives::{Address, U256, U64}; +use reth_provider::{BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; +use reth_rpc_eth_api::helpers::EthApiSpec; +use reth_rpc_types::{SyncInfo, SyncStatus}; +use reth_transaction_pool::TransactionPool; + +use crate::EthApi; + +impl EthApiSpec for EthApi +where + Pool: TransactionPool + 'static, + Provider: + BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + 'static, + Network: NetworkInfo + 'static, + EvmConfig: ConfigureEvm, +{ + /// Returns the current ethereum protocol version. + /// + /// Note: This returns an [`U64`], since this should return as hex string. + async fn protocol_version(&self) -> RethResult { + let status = self.network().network_status().await.map_err(RethError::other)?; + Ok(U64::from(status.protocol_version)) + } + + /// Returns the chain id + fn chain_id(&self) -> U64 { + U64::from(self.network().chain_id()) + } + + /// Returns the current info for the chain + fn chain_info(&self) -> RethResult { + Ok(self.provider().chain_info()?) + } + + fn accounts(&self) -> Vec
{ + self.inner.signers().read().iter().flat_map(|s| s.accounts()).collect() + } + + fn is_syncing(&self) -> bool { + self.network().is_syncing() + } + + /// Returns the [`SyncStatus`] of the network + fn sync_status(&self) -> RethResult { + let status = if self.is_syncing() { + let current_block = U256::from( + self.provider().chain_info().map(|info| info.best_number).unwrap_or_default(), + ); + SyncStatus::Info(SyncInfo { + starting_block: self.inner.starting_block(), + current_block, + highest_block: current_block, + warp_chunks_amount: None, + warp_chunks_processed: None, + }) + } else { + SyncStatus::None + }; + Ok(status) + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/state.rs b/crates/rpc/rpc/src/eth/helpers/state.rs new file mode 100644 index 000000000000..dd28c6465665 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/state.rs @@ -0,0 +1,104 @@ +//! Contains RPC handler implementations specific to state. + +use reth_provider::StateProviderFactory; +use reth_transaction_pool::TransactionPool; + +use reth_rpc_eth_api::helpers::{EthState, LoadState, SpawnBlocking}; +use reth_rpc_eth_types::EthStateCache; + +use crate::EthApi; + +impl EthState for EthApi where + Self: LoadState + SpawnBlocking +{ +} + +impl LoadState for EthApi +where + Provider: StateProviderFactory, + Pool: TransactionPool, +{ + #[inline] + fn provider(&self) -> impl StateProviderFactory { + self.inner.provider() + } + + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } + + #[inline] + fn pool(&self) -> impl TransactionPool { + self.inner.pool() + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use reth_evm_ethereum::EthEvmConfig; + use reth_primitives::{ + constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, U256, + }; + use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider}; + use reth_rpc_eth_api::helpers::EthState; + use reth_rpc_eth_types::{ + EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, + }; + use reth_tasks::pool::BlockingTaskPool; + use reth_transaction_pool::test_utils::testing_pool; + + use super::*; + + #[tokio::test] + async fn test_storage() { + // === Noop === + let pool = testing_pool(); + let evm_config = EthEvmConfig::default(); + + let cache = EthStateCache::spawn(NoopProvider::default(), Default::default(), evm_config); + let eth_api = EthApi::new( + NoopProvider::default(), + pool.clone(), + (), + cache.clone(), + GasPriceOracle::new(NoopProvider::default(), Default::default(), cache.clone()), + ETHEREUM_BLOCK_GAS_LIMIT, + BlockingTaskPool::build().expect("failed to build tracing pool"), + FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), + evm_config, + None, + ); + let address = Address::random(); + let storage = eth_api.storage_at(address, U256::ZERO.into(), None).await.unwrap(); + assert_eq!(storage, U256::ZERO.to_be_bytes()); + + // === Mock === + let mock_provider = MockEthProvider::default(); + let storage_value = StorageValue::from(1337); + let storage_key = StorageKey::random(); + let storage = HashMap::from([(storage_key, storage_value)]); + let account = ExtendedAccount::new(0, U256::ZERO).extend_storage(storage); + mock_provider.add_account(address, account); + + let cache = EthStateCache::spawn(mock_provider.clone(), Default::default(), evm_config); + let eth_api = EthApi::new( + mock_provider.clone(), + pool, + (), + cache.clone(), + GasPriceOracle::new(mock_provider, Default::default(), cache.clone()), + ETHEREUM_BLOCK_GAS_LIMIT, + BlockingTaskPool::build().expect("failed to build tracing pool"), + FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()), + evm_config, + None, + ); + + let storage_key: U256 = storage_key.into(); + let storage = eth_api.storage_at(address, storage_key.into(), None).await.unwrap(); + assert_eq!(storage, storage_value.to_be_bytes()); + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/trace.rs b/crates/rpc/rpc/src/eth/helpers/trace.rs new file mode 100644 index 000000000000..fe1ee9f13cf4 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/trace.rs @@ -0,0 +1,17 @@ +//! Contains RPC handler implementations specific to tracing. + +use reth_evm::ConfigureEvm; +use reth_rpc_eth_api::helpers::{LoadState, Trace}; + +use crate::EthApi; + +impl Trace for EthApi +where + Self: LoadState, + EvmConfig: ConfigureEvm, +{ + #[inline] + fn evm_config(&self) -> &impl ConfigureEvm { + self.inner.evm_config() + } +} diff --git a/crates/rpc/rpc/src/eth/helpers/transaction.rs b/crates/rpc/rpc/src/eth/helpers/transaction.rs new file mode 100644 index 000000000000..9d86be1b2e24 --- /dev/null +++ b/crates/rpc/rpc/src/eth/helpers/transaction.rs @@ -0,0 +1,125 @@ +//! Contains RPC handler implementations specific to transactions + +use reth_provider::{BlockReaderIdExt, TransactionsProvider}; +use reth_rpc_eth_api::{ + helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, + RawTransactionForwarder, +}; +use reth_rpc_eth_types::EthStateCache; +use reth_transaction_pool::TransactionPool; + +use crate::EthApi; + +impl EthTransactions + for EthApi +where + Self: LoadTransaction, + Pool: TransactionPool + 'static, + Provider: BlockReaderIdExt, +{ + #[inline] + fn provider(&self) -> impl BlockReaderIdExt { + self.inner.provider() + } + + #[inline] + fn raw_tx_forwarder(&self) -> Option> { + self.inner.raw_tx_forwarder() + } + + #[inline] + fn signers(&self) -> &parking_lot::RwLock>> { + self.inner.signers() + } +} + +impl LoadTransaction + for EthApi +where + Self: SpawnBlocking, + Provider: TransactionsProvider, + Pool: TransactionPool, +{ + type Pool = Pool; + + #[inline] + fn provider(&self) -> impl reth_provider::TransactionsProvider { + self.inner.provider() + } + + #[inline] + fn cache(&self) -> &EthStateCache { + self.inner.cache() + } + + #[inline] + fn pool(&self) -> &Self::Pool { + self.inner.pool() + } +} + +#[cfg(test)] +mod tests { + use reth_evm_ethereum::EthEvmConfig; + use reth_network_api::noop::NoopNetwork; + use reth_primitives::{constants::ETHEREUM_BLOCK_GAS_LIMIT, hex_literal::hex, Bytes}; + use reth_provider::test_utils::NoopProvider; + use reth_rpc_eth_api::helpers::EthTransactions; + use reth_rpc_eth_types::{ + EthStateCache, FeeHistoryCache, FeeHistoryCacheConfig, GasPriceOracle, + }; + use reth_tasks::pool::BlockingTaskPool; + use reth_transaction_pool::{test_utils::testing_pool, TransactionPool}; + + use super::*; + + #[tokio::test] + async fn send_raw_transaction() { + let noop_provider = NoopProvider::default(); + let noop_network_provider = NoopNetwork::default(); + + let pool = testing_pool(); + + let evm_config = EthEvmConfig::default(); + let cache = EthStateCache::spawn(noop_provider, Default::default(), evm_config); + let fee_history_cache = + FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); + let eth_api = EthApi::new( + noop_provider, + pool.clone(), + noop_network_provider, + cache.clone(), + GasPriceOracle::new(noop_provider, Default::default(), cache.clone()), + ETHEREUM_BLOCK_GAS_LIMIT, + BlockingTaskPool::build().expect("failed to build tracing pool"), + fee_history_cache, + evm_config, + None, + ); + + // https://etherscan.io/tx/0xa694b71e6c128a2ed8e2e0f6770bddbe52e3bb8f10e8472f9a79ab81497a8b5d + let tx_1 = Bytes::from(hex!("02f871018303579880850555633d1b82520894eee27662c2b8eba3cd936a23f039f3189633e4c887ad591c62bdaeb180c080a07ea72c68abfb8fca1bd964f0f99132ed9280261bdca3e549546c0205e800f7d0a05b4ef3039e9c9b9babc179a1878fb825b5aaf5aed2fa8744854150157b08d6f3")); + + let tx_1_result = eth_api.send_raw_transaction(tx_1).await.unwrap(); + assert_eq!( + pool.len(), + 1, + "expect 1 transactions in the pool, but pool size is {}", + pool.len() + ); + + // https://etherscan.io/tx/0x48816c2f32c29d152b0d86ff706f39869e6c1f01dc2fe59a3c1f9ecf39384694 + let tx_2 = Bytes::from(hex!("02f9043c018202b7843b9aca00850c807d37a08304d21d94ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b881bc16d674ec80000b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000063e2d99f00000000000000000000000000000000000000000000000000000000000000030b000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000065717fe021ea67801d1088cc80099004b05b64600000000000000000000000000000000000000000000000001bc16d674ec80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f4a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009e95fd5965fd1f1a6f0d4600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000428dca9537116148616a5a3e44035af17238fe9dc080a0c6ec1e41f5c0b9511c49b171ad4e04c6bb419c74d99fe9891d74126ec6e4e879a032069a753d7a2cfa158df95421724d24c0e9501593c09905abf3699b4a4405ce")); + + let tx_2_result = eth_api.send_raw_transaction(tx_2).await.unwrap(); + assert_eq!( + pool.len(), + 2, + "expect 2 transactions in the pool, but pool size is {}", + pool.len() + ); + + assert!(pool.get(&tx_1_result).is_some(), "tx1 not found in the pool"); + assert!(pool.get(&tx_2_result).is_some(), "tx2 not found in the pool"); + } +} diff --git a/crates/rpc/rpc/src/eth/mod.rs b/crates/rpc/rpc/src/eth/mod.rs index 8d8e982c2c79..4e6a0cbb8c75 100644 --- a/crates/rpc/rpc/src/eth/mod.rs +++ b/crates/rpc/rpc/src/eth/mod.rs @@ -1,28 +1,17 @@ -//! `eth` namespace handler implementation. +//! Sever implementation of `eth` namespace API. -mod api; pub mod bundle; -pub mod cache; -pub mod error; -mod filter; -pub mod gas_oracle; -mod id_provider; -mod logs_utils; -mod pubsub; -pub mod revm_utils; -mod signer; -pub mod traits; -pub(crate) mod utils; - -#[cfg(feature = "optimism")] -pub mod optimism; - -pub use api::{ - fee_history::{fee_history_cache_new_blocks_task, FeeHistoryCache, FeeHistoryCacheConfig}, - EthApi, EthApiSpec, EthTransactions, TransactionSource, RPC_DEFAULT_GAS_CAP, -}; +pub mod core; +pub mod filter; +pub mod helpers; +pub mod pubsub; +/// Implementation of `eth` namespace API. pub use bundle::EthBundle; +pub use core::EthApi; pub use filter::{EthFilter, EthFilterConfig}; -pub use id_provider::EthSubscriptionIdProvider; pub use pubsub::EthPubSub; + +pub use helpers::signer::DevSigner; + +pub use reth_rpc_eth_api::RawTransactionForwarder; diff --git a/crates/rpc/rpc/src/eth/optimism.rs b/crates/rpc/rpc/src/eth/optimism.rs deleted file mode 100644 index fb1665b95785..000000000000 --- a/crates/rpc/rpc/src/eth/optimism.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Optimism specific types. - -use jsonrpsee::types::ErrorObject; -use reth_rpc_types::ToRpcError; - -use crate::{eth::error::EthApiError, result::internal_rpc_err}; - -/// Eth Optimism Api Error -#[cfg(feature = "optimism")] -#[derive(Debug, thiserror::Error)] -pub enum OptimismEthApiError { - /// Thrown when calculating L1 gas fee - #[error("failed to calculate l1 gas fee")] - L1BlockFeeError, - /// Thrown when calculating L1 gas used - #[error("failed to calculate l1 gas used")] - L1BlockGasError, -} - -impl ToRpcError for OptimismEthApiError { - fn to_rpc_error(&self) -> ErrorObject<'static> { - match self { - Self::L1BlockFeeError | Self::L1BlockGasError => internal_rpc_err(self.to_string()), - } - } -} - -impl From for EthApiError { - fn from(err: OptimismEthApiError) -> Self { - Self::other(err) - } -} diff --git a/crates/rpc/rpc/src/eth/pubsub.rs b/crates/rpc/rpc/src/eth/pubsub.rs index fdfa836b91ff..3585be9f8561 100644 --- a/crates/rpc/rpc/src/eth/pubsub.rs +++ b/crates/rpc/rpc/src/eth/pubsub.rs @@ -1,9 +1,7 @@ //! `eth_` `PubSub` RPC handler implementation -use crate::{ - eth::logs_utils, - result::{internal_rpc_err, invalid_params_rpc_err}, -}; +use std::sync::Arc; + use futures::StreamExt; use jsonrpsee::{ server::SubscriptionMessage, types::ErrorObject, PendingSubscriptionSink, SubscriptionSink, @@ -11,7 +9,9 @@ use jsonrpsee::{ use reth_network_api::NetworkInfo; use reth_primitives::{IntoRecoveredTransaction, TxHash}; use reth_provider::{BlockReader, CanonStateSubscriptions, EvmEnvProvider}; -use reth_rpc_api::EthPubSubApiServer; +use reth_rpc_eth_api::pubsub::EthPubSubApiServer; +use reth_rpc_eth_types::logs_utils; +use reth_rpc_server_types::result::{internal_rpc_err, invalid_params_rpc_err}; use reth_rpc_types::{ pubsub::{ Params, PubSubSyncStatus, SubscriptionKind, SubscriptionResult as EthSubscriptionResult, @@ -22,7 +22,6 @@ use reth_rpc_types::{ use reth_tasks::{TaskSpawner, TokioTaskExecutor}; use reth_transaction_pool::{NewTransactionEvent, TransactionPool}; use serde::Serialize; -use std::sync::Arc; use tokio_stream::{ wrappers::{BroadcastStream, ReceiverStream}, Stream, @@ -197,10 +196,10 @@ where /// Helper to convert a serde error into an [`ErrorObject`] #[derive(Debug, thiserror::Error)] #[error("Failed to serialize subscription item: {0}")] -pub(crate) struct SubscriptionSerializeError(#[from] serde_json::Error); +pub struct SubscriptionSerializeError(#[from] serde_json::Error); impl SubscriptionSerializeError { - pub(crate) const fn new(err: serde_json::Error) -> Self { + const fn new(err: serde_json::Error) -> Self { Self(err) } } diff --git a/crates/rpc/rpc/src/eth/traits.rs b/crates/rpc/rpc/src/eth/traits.rs deleted file mode 100644 index 0f73ded3c82f..000000000000 --- a/crates/rpc/rpc/src/eth/traits.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Additional helper traits that allow for more customization. - -use crate::eth::error::EthResult; -use std::fmt; - -/// A trait that allows for forwarding raw transactions. -/// -/// For example to a sequencer. -#[async_trait::async_trait] -pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static { - /// Forwards raw transaction bytes for `eth_sendRawTransaction` - async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>; -} diff --git a/crates/rpc/rpc/src/lib.rs b/crates/rpc/rpc/src/lib.rs index 17dc8fcb809f..8222a05722b5 100644 --- a/crates/rpc/rpc/src/lib.rs +++ b/crates/rpc/rpc/src/lib.rs @@ -40,18 +40,19 @@ mod net; mod otterscan; mod reth; mod rpc; +mod taiko; mod trace; mod txpool; mod web3; pub use admin::AdminApi; pub use debug::DebugApi; pub use engine::{EngineApi, EngineEthApi}; -pub use eth::{EthApi, EthApiSpec, EthFilter, EthPubSub, EthSubscriptionIdProvider}; +pub use eth::{EthApi, EthBundle, EthFilter, EthPubSub}; pub use net::NetApi; pub use otterscan::OtterscanApi; pub use reth::RethApi; pub use rpc::RPCApi; +pub use taiko::TaikoApi; pub use trace::TraceApi; pub use txpool::TxPoolApi; pub use web3::Web3Api; -pub mod result; diff --git a/crates/rpc/rpc/src/net.rs b/crates/rpc/rpc/src/net.rs index 8e6615a281bf..79e85ac48e02 100644 --- a/crates/rpc/rpc/src/net.rs +++ b/crates/rpc/rpc/src/net.rs @@ -1,8 +1,8 @@ -use crate::eth::EthApiSpec; use jsonrpsee::core::RpcResult as Result; use reth_network_api::PeersInfo; use reth_primitives::U64; use reth_rpc_api::NetApiServer; +use reth_rpc_eth_api::helpers::EthApiSpec; use reth_rpc_types::PeerCount; /// `Net` API implementation. diff --git a/crates/rpc/rpc/src/otterscan.rs b/crates/rpc/rpc/src/otterscan.rs index e658402f3a94..4088d71ca0fa 100644 --- a/crates/rpc/rpc/src/otterscan.rs +++ b/crates/rpc/rpc/src/otterscan.rs @@ -1,11 +1,10 @@ use alloy_primitives::Bytes; use async_trait::async_trait; use jsonrpsee::core::RpcResult; -use revm_inspectors::transfer::{TransferInspector, TransferKind}; -use revm_primitives::ExecutionResult; - use reth_primitives::{Address, BlockId, BlockNumberOrTag, TxHash, B256}; use reth_rpc_api::{EthApiServer, OtterscanServer}; +use reth_rpc_eth_api::helpers::TraceExt; +use reth_rpc_server_types::result::internal_rpc_err; use reth_rpc_types::{ trace::otterscan::{ BlockDetails, ContractCreator, InternalOperation, OperationType, OtsBlockTransactions, @@ -13,8 +12,8 @@ use reth_rpc_types::{ }, BlockTransactions, Transaction, }; - -use crate::{eth::EthTransactions, result::internal_rpc_err}; +use revm_inspectors::transfer::{TransferInspector, TransferKind}; +use revm_primitives::ExecutionResult; const API_LEVEL: u64 = 8; @@ -34,7 +33,7 @@ impl OtterscanApi { #[async_trait] impl OtterscanServer for OtterscanApi where - Eth: EthApiServer + EthTransactions, + Eth: EthApiServer + TraceExt + 'static, { /// Handler for `ots_hasCode` async fn has_code(&self, address: Address, block_number: Option) -> RpcResult { diff --git a/crates/rpc/rpc/src/reth.rs b/crates/rpc/rpc/src/reth.rs index 17925b5ab8bf..33dc74920406 100644 --- a/crates/rpc/rpc/src/reth.rs +++ b/crates/rpc/rpc/src/reth.rs @@ -1,12 +1,13 @@ -use crate::eth::error::{EthApiError, EthResult}; +use std::{collections::HashMap, future::Future, sync::Arc}; + use async_trait::async_trait; use jsonrpsee::core::RpcResult; use reth_errors::RethResult; use reth_primitives::{Address, BlockId, U256}; use reth_provider::{BlockReaderIdExt, ChangeSetReader, StateProviderFactory}; use reth_rpc_api::RethApiServer; +use reth_rpc_eth_types::{EthApiError, EthResult}; use reth_tasks::TaskSpawner; -use std::{collections::HashMap, future::Future, sync::Arc}; use tokio::sync::oneshot; /// `reth` API implementation. diff --git a/crates/rpc/rpc/src/taiko.rs b/crates/rpc/rpc/src/taiko.rs new file mode 100644 index 000000000000..c9d2108357cb --- /dev/null +++ b/crates/rpc/rpc/src/taiko.rs @@ -0,0 +1,161 @@ +use std::collections::BTreeMap; + +use alloy_primitives::Address; +use async_trait::async_trait; +use jsonrpsee::core::RpcResult; +use reth_provider::{BlockReader, L1OriginReader}; +use reth_rpc_api::TaikoApiServer; +use reth_rpc_server_types::result::internal_rpc_err; +use reth_rpc_types::{txpool::TxpoolContent, Transaction}; +use reth_transaction_pool::{AllPoolTransactions, PoolTransaction, TransactionPool}; + +/// Taiko API. +#[derive(Debug)] +pub struct TaikoApi { + provider: Provider, + pool: Pool, +} + +impl TaikoApi { + /// Creates a new instance of `Taiko`. + pub const fn new(provider: Provider, pool: Pool) -> Self { + Self { provider, pool } + } +} + +impl TaikoApi +where + Provider: BlockReader + L1OriginReader + 'static, + Pool: TransactionPool + 'static, +{ + fn content(&self) -> TxpoolContent { + #[inline] + fn insert( + tx: &T, + content: &mut BTreeMap>, + ) { + content.entry(tx.sender()).or_default().insert( + tx.nonce().to_string(), + reth_rpc_types_compat::transaction::from_recovered(tx.to_recovered_transaction()), + ); + } + + let AllPoolTransactions { pending, queued } = self.pool.all_transactions(); + + let mut content = TxpoolContent::default(); + for pending in pending { + insert(&pending.transaction, &mut content.pending); + } + for queued in queued { + insert(&queued.transaction, &mut content.queued); + } + + content + } + + fn get_txs( + &self, + locals: &[String], + ) -> ( + BTreeMap>, + BTreeMap>, + ) { + self.content() + .pending + .into_iter() + .map(|(address, txs)| (address, txs, locals.contains(&address.to_string()))) + .fold( + ( + BTreeMap::>::new(), + BTreeMap::>::new(), + ), + |(mut l, mut r), (address, txs, is_local)| { + if is_local { + l.insert(address, txs); + } else { + r.insert(address, txs); + } + + (l, r) + }, + ) + } + + async fn commit_txs(&self, locals: &[String]) -> RpcResult> { + let (_local_txs, _remote_txs) = self.get_txs(&locals); + Ok(vec![]) + } +} + +#[async_trait] +impl TaikoApiServer for TaikoApi +where + Provider: BlockReader + L1OriginReader + 'static, + Pool: TransactionPool + 'static, +{ + /// HeadL1Origin returns the latest L2 block's corresponding L1 origin. + // #[cfg(feature = "taiko")] + async fn head_l1_origin(&self) -> RpcResult> { + self.provider.read_head_l1_origin().map_err(|_| { + internal_rpc_err("taiko_headL1Origin failed to read latest l2 block's L1 origin") + }) + } + + /// L1OriginByID returns the L2 block's corresponding L1 origin. + // #[cfg(feature = "taiko")] + async fn l1_origin_by_id(&self, block_id: u64) -> RpcResult> { + self.provider.read_l1_origin(block_id).map_err(|_| { + internal_rpc_err("taiko_l1OriginByID failed to read L1 origin by block id") + }) + } + + /// GetL2ParentHeaders + // #[cfg(feature = "taiko")] + async fn get_l2_parent_headers( + &self, + block_id: u64, + ) -> RpcResult> { + let start = if block_id > 256 { block_id - 255 } else { 0 }; + let mut headers = Vec::with_capacity(256); + + for id in start..=block_id { + let option = self.provider.header_by_number(id).map_err(|_| { + internal_rpc_err("taiko_getL2ParentHeaders failed to read header by number") + })?; + let Some(header) = option else { + return Err(internal_rpc_err( + "taiko_getL2ParentHeaders failed to find parent header by number", + )); + }; + headers.push(header); + } + + Ok(headers) + } + + // TODO:(petar) implement this function + /// TxPoolContent retrieves the transaction pool content with the given upper limits. + async fn txpool_content( + &self, + beneficiary: Address, + base_fee: u64, + block_max_gas_limit: u64, + max_bytes_per_tx_list: u64, + locals: Vec, + max_transactions_lists: u64, + ) -> RpcResult>> { + let mut tx_lists = Vec::with_capacity(max_transactions_lists as usize); + + for _ in 0..max_transactions_lists { + let tx_list = self.commit_txs(&locals).await?; + + if tx_list.is_empty() { + break; + } + + tx_lists.push(tx_list); + } + + Ok(tx_lists) + } +} diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index e959a367e3f3..ff98194b91fb 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -1,18 +1,22 @@ -use crate::eth::{ - error::{EthApiError, EthResult}, - revm_utils::prepare_call_env, - utils::recover_raw_transaction, - EthTransactions, -}; +use std::{collections::HashSet, sync::Arc}; + use async_trait::async_trait; use jsonrpsee::core::RpcResult as Result; +use reth_chainspec::EthereumHardforks; use reth_consensus_common::calc::{ base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward, }; -use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, Header, B256, U256}; +use reth_evm::ConfigureEvmEnv; +use reth_primitives::{BlockId, Bytes, Header, B256, U256}; use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory}; use reth_revm::database::StateProviderDatabase; use reth_rpc_api::TraceApiServer; +use reth_rpc_eth_api::helpers::{Call, TraceExt}; +use reth_rpc_eth_types::{ + error::{EthApiError, EthResult}, + revm_utils::prepare_call_env, + utils::recover_raw_transaction, +}; use reth_rpc_types::{ state::{EvmOverrides, StateOverride}, trace::{ @@ -32,7 +36,6 @@ use revm_inspectors::{ opcode::OpcodeGasInspector, tracing::{parity::populate_state_diff, TracingInspector, TracingInspectorConfig}, }; -use std::{collections::HashSet, sync::Arc}; use tokio::sync::{AcquireError, OwnedSemaphorePermit}; /// `trace` API implementation. @@ -74,7 +77,7 @@ impl TraceApi { impl TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Eth: TraceExt + 'static, { /// Executes the given call and returns a number of possible traces for it. pub async fn trace_call(&self, trace_request: TraceCallRequest) -> EthResult { @@ -86,6 +89,10 @@ where let this = self.clone(); self.eth_api() .spawn_with_call_at(trace_request.call, at, overrides, move |db, env| { + // wrapper is hack to get around 'higher-ranked lifetime error', see + // + let db = db.0; + let (res, _) = this.eth_api().inspect(&mut *db, env, &mut inspector)?; let trace_res = inspector.into_parity_builder().into_trace_results_with_state( &res, @@ -107,8 +114,12 @@ where let tx = recover_raw_transaction(tx)?; let (cfg, block, at) = self.inner.eth_api.evm_env_at(block_id.unwrap_or_default()).await?; - let tx = tx_env_with_recovered(&tx.into_ecrecovered_transaction()); - let env = EnvWithHandlerCfg::new_with_cfg_env(cfg, block, tx); + + let env = EnvWithHandlerCfg::new_with_cfg_env( + cfg, + block, + Call::evm_config(self.eth_api()).tx_env(&tx.into_ecrecovered_transaction()), + ); let config = TracingInspectorConfig::from_parity_config(&trace_types); @@ -372,7 +383,7 @@ where }, ); - let block = self.inner.eth_api.block_by_id(block_id); + let block = self.inner.eth_api.block(block_id); let (maybe_traces, maybe_block) = futures::try_join!(traces, block)?; let mut maybe_traces = @@ -455,7 +466,7 @@ where let res = self .inner .eth_api - .trace_block_with_inspector( + .trace_block_inspector( block_id, OpcodeGasInspector::default, move |tx_info, inspector, _res, _, _| { @@ -470,7 +481,7 @@ where let Some(transactions) = res else { return Ok(None) }; - let Some(block) = self.inner.eth_api.block_by_id(block_id).await? else { return Ok(None) }; + let Some(block) = self.inner.eth_api.block(block_id).await? else { return Ok(None) }; Ok(Some(BlockOpcodeGas { block_hash: block.hash(), @@ -548,7 +559,7 @@ where impl TraceApiServer for TraceApi where Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, - Eth: EthTransactions + 'static, + Eth: TraceExt + 'static, { /// Executes the given call and returns a number of possible traces for it. /// diff --git a/crates/rpc/rpc/src/web3.rs b/crates/rpc/rpc/src/web3.rs index 4ed94ac85523..787604e25e23 100644 --- a/crates/rpc/rpc/src/web3.rs +++ b/crates/rpc/rpc/src/web3.rs @@ -1,9 +1,9 @@ -use crate::result::ToRpcResult; use async_trait::async_trait; use jsonrpsee::core::RpcResult; use reth_network_api::NetworkInfo; use reth_primitives::{keccak256, Bytes, B256}; use reth_rpc_api::Web3ApiServer; +use reth_rpc_server_types::ToRpcResult; /// `web3` API implementation. /// diff --git a/crates/stages/api/src/metrics/execution.rs b/crates/stages/api/src/metrics/execution.rs new file mode 100644 index 000000000000..b54ed02f653c --- /dev/null +++ b/crates/stages/api/src/metrics/execution.rs @@ -0,0 +1,20 @@ +use std::time::Duration; + +use reth_primitives_traits::constants::gas_units::{GIGAGAS, KILOGAS, MEGAGAS}; + +/// Returns a formatted gas throughput log, showing either: +/// * "Kgas/s", or 1,000 gas per second +/// * "Mgas/s", or 1,000,000 gas per second +/// * "Ggas/s", or 1,000,000,000 gas per second +/// +/// Depending on the magnitude of the gas throughput. +pub fn format_gas_throughput(gas: u64, execution_duration: Duration) -> String { + let gas_per_second = gas as f64 / execution_duration.as_secs_f64(); + if gas_per_second < MEGAGAS as f64 { + format!("{:.} Kgas/second", gas_per_second / KILOGAS as f64) + } else if gas_per_second < GIGAGAS as f64 { + format!("{:.} Mgas/second", gas_per_second / MEGAGAS as f64) + } else { + format!("{:.} Ggas/second", gas_per_second / GIGAGAS as f64) + } +} diff --git a/crates/stages/api/src/metrics/mod.rs b/crates/stages/api/src/metrics/mod.rs index bed2742c25fc..983247ae9c0b 100644 --- a/crates/stages/api/src/metrics/mod.rs +++ b/crates/stages/api/src/metrics/mod.rs @@ -1,5 +1,7 @@ +mod execution; mod listener; mod sync_metrics; +pub use execution::format_gas_throughput; pub use listener::{MetricEvent, MetricEventsSender, MetricsListener}; use sync_metrics::*; diff --git a/crates/stages/api/src/pipeline/mod.rs b/crates/stages/api/src/pipeline/mod.rs index 67ef53855b15..1be468702e43 100644 --- a/crates/stages/api/src/pipeline/mod.rs +++ b/crates/stages/api/src/pipeline/mod.rs @@ -13,7 +13,6 @@ use reth_provider::{ }; use reth_prune::PrunerBuilder; use reth_static_file::StaticFileProducer; -use reth_static_file_types::HighestStaticFiles; use reth_tokio_util::{EventSender, EventStream}; use std::pin::Pin; use tokio::sync::watch; @@ -248,26 +247,9 @@ where /// CAUTION: This method locks the static file producer Mutex, hence can block the thread if the /// lock is occupied. pub fn move_to_static_files(&self) -> RethResult<()> { - let static_file_producer = self.static_file_producer.lock(); - // Copies data from database to static files - let lowest_static_file_height = { - let provider = self.provider_factory.provider()?; - let stages_checkpoints = [StageId::Headers, StageId::Execution, StageId::Bodies] - .into_iter() - .map(|stage| { - provider.get_stage_checkpoint(stage).map(|c| c.map(|c| c.block_number)) - }) - .collect::, _>>()?; - - let targets = static_file_producer.get_static_file_targets(HighestStaticFiles { - headers: stages_checkpoints[0], - receipts: stages_checkpoints[1], - transactions: stages_checkpoints[2], - })?; - static_file_producer.run(targets)?; - stages_checkpoints.into_iter().min().expect("exists") - }; + let lowest_static_file_height = + self.static_file_producer.lock().copy_to_static_files()?.min(); // Deletes data which has been copied to static files. if let Some(prune_tip) = lowest_static_file_height { diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index a37c081b4da7..26db6f50f8ae 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -6,10 +6,7 @@ use reth_db_api::{cursor::DbCursorRO, database::Database, transaction::DbTx}; use reth_evm::execute::{BatchExecutor, BlockExecutorProvider}; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_exex::{ExExManagerHandle, ExExNotification}; -use reth_primitives::{ - constants::gas_units::{GIGAGAS, KILOGAS, MEGAGAS}, - BlockNumber, Header, StaticFileSegment, -}; +use reth_primitives::{BlockNumber, Header, StaticFileSegment}; use reth_provider::{ providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter}, BlockReader, DatabaseProviderRW, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown, @@ -18,9 +15,9 @@ use reth_provider::{ use reth_prune_types::PruneModes; use reth_revm::database::StateProviderDatabase; use reth_stages_api::{ - BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, ExecOutput, - ExecutionCheckpoint, MetricEvent, MetricEventsSender, Stage, StageCheckpoint, StageError, - StageId, UnwindInput, UnwindOutput, + format_gas_throughput, BlockErrorKind, CheckpointBlockRange, EntitiesCheckpoint, ExecInput, + ExecOutput, ExecutionCheckpoint, ExecutionStageThresholds, MetricEvent, MetricEventsSender, + Stage, StageCheckpoint, StageError, StageId, UnwindInput, UnwindOutput, }; use std::{ cmp::Ordering, @@ -546,83 +543,6 @@ fn calculate_gas_used_from_headers( Ok(gas_total) } -/// The thresholds at which the execution stage writes state changes to the database. -/// -/// If either of the thresholds (`max_blocks` and `max_changes`) are hit, then the execution stage -/// commits all pending changes to the database. -/// -/// A third threshold, `max_changesets`, can be set to periodically write changesets to the -/// current database transaction, which frees up memory. -#[derive(Debug, Clone)] -pub struct ExecutionStageThresholds { - /// The maximum number of blocks to execute before the execution stage commits. - pub max_blocks: Option, - /// The maximum number of state changes to keep in memory before the execution stage commits. - pub max_changes: Option, - /// The maximum cumulative amount of gas to process before the execution stage commits. - pub max_cumulative_gas: Option, - /// The maximum spent on blocks processing before the execution stage commits. - pub max_duration: Option, -} - -impl Default for ExecutionStageThresholds { - fn default() -> Self { - Self { - max_blocks: Some(500_000), - max_changes: Some(5_000_000), - // 50k full blocks of 30M gas - max_cumulative_gas: Some(30_000_000 * 50_000), - // 10 minutes - max_duration: Some(Duration::from_secs(10 * 60)), - } - } -} - -impl ExecutionStageThresholds { - /// Check if the batch thresholds have been hit. - #[inline] - pub fn is_end_of_batch( - &self, - blocks_processed: u64, - changes_processed: u64, - cumulative_gas_used: u64, - elapsed: Duration, - ) -> bool { - blocks_processed >= self.max_blocks.unwrap_or(u64::MAX) || - changes_processed >= self.max_changes.unwrap_or(u64::MAX) || - cumulative_gas_used >= self.max_cumulative_gas.unwrap_or(u64::MAX) || - elapsed >= self.max_duration.unwrap_or(Duration::MAX) - } -} - -impl From for ExecutionStageThresholds { - fn from(config: ExecutionConfig) -> Self { - Self { - max_blocks: config.max_blocks, - max_changes: config.max_changes, - max_cumulative_gas: config.max_cumulative_gas, - max_duration: config.max_duration, - } - } -} - -/// Returns a formatted gas throughput log, showing either: -/// * "Kgas/s", or 1,000 gas per second -/// * "Mgas/s", or 1,000,000 gas per second -/// * "Ggas/s", or 1,000,000,000 gas per second -/// -/// Depending on the magnitude of the gas throughput. -pub fn format_gas_throughput(gas: u64, execution_duration: Duration) -> String { - let gas_per_second = gas as f64 / execution_duration.as_secs_f64(); - if gas_per_second < MEGAGAS as f64 { - format!("{:.} Kgas/second", gas_per_second / KILOGAS as f64) - } else if gas_per_second < GIGAGAS as f64 { - format!("{:.} Mgas/second", gas_per_second / MEGAGAS as f64) - } else { - format!("{:.} Ggas/second", gas_per_second / GIGAGAS as f64) - } -} - /// Returns a `StaticFileProviderRWRefMut` static file producer after performing a consistency /// check. /// @@ -720,7 +640,7 @@ mod tests { StaticFileProviderFactory, }; use reth_prune_types::{PruneMode, ReceiptsLogPruneConfig}; - use reth_stages_api::StageUnitCheckpoint; + use reth_stages_api::{format_gas_throughput, StageUnitCheckpoint}; use std::collections::BTreeMap; fn stage() -> ExecutionStage { diff --git a/crates/stages/stages/src/stages/mod.rs b/crates/stages/stages/src/stages/mod.rs index 8d850b8ba13a..9c96f4b30a5b 100644 --- a/crates/stages/stages/src/stages/mod.rs +++ b/crates/stages/stages/src/stages/mod.rs @@ -66,7 +66,9 @@ mod tests { StaticFileProviderFactory, StorageReader, }; use reth_prune_types::{PruneMode, PruneModes}; - use reth_stages_api::{ExecInput, PipelineTarget, Stage, StageCheckpoint, StageId}; + use reth_stages_api::{ + ExecInput, ExecutionStageThresholds, PipelineTarget, Stage, StageCheckpoint, StageId, + }; use reth_testing_utils::generators::{self, random_block, random_block_range, random_receipt}; use std::{io::Write, sync::Arc}; diff --git a/crates/stages/types/src/execution.rs b/crates/stages/types/src/execution.rs new file mode 100644 index 000000000000..61f7313a380a --- /dev/null +++ b/crates/stages/types/src/execution.rs @@ -0,0 +1,50 @@ +use std::time::Duration; + +/// The thresholds at which the execution stage writes state changes to the database. +/// +/// If either of the thresholds (`max_blocks` and `max_changes`) are hit, then the execution stage +/// commits all pending changes to the database. +/// +/// A third threshold, `max_changesets`, can be set to periodically write changesets to the +/// current database transaction, which frees up memory. +#[derive(Debug, Clone)] +pub struct ExecutionStageThresholds { + /// The maximum number of blocks to execute before the execution stage commits. + pub max_blocks: Option, + /// The maximum number of state changes to keep in memory before the execution stage commits. + pub max_changes: Option, + /// The maximum cumulative amount of gas to process before the execution stage commits. + pub max_cumulative_gas: Option, + /// The maximum spent on blocks processing before the execution stage commits. + pub max_duration: Option, +} + +impl Default for ExecutionStageThresholds { + fn default() -> Self { + Self { + max_blocks: Some(500_000), + max_changes: Some(5_000_000), + // 50k full blocks of 30M gas + max_cumulative_gas: Some(30_000_000 * 50_000), + // 10 minutes + max_duration: Some(Duration::from_secs(10 * 60)), + } + } +} + +impl ExecutionStageThresholds { + /// Check if the batch thresholds have been hit. + #[inline] + pub fn is_end_of_batch( + &self, + blocks_processed: u64, + changes_processed: u64, + cumulative_gas_used: u64, + elapsed: Duration, + ) -> bool { + blocks_processed >= self.max_blocks.unwrap_or(u64::MAX) || + changes_processed >= self.max_changes.unwrap_or(u64::MAX) || + cumulative_gas_used >= self.max_cumulative_gas.unwrap_or(u64::MAX) || + elapsed >= self.max_duration.unwrap_or(Duration::MAX) + } +} diff --git a/crates/stages/types/src/lib.rs b/crates/stages/types/src/lib.rs index 93106bd886d1..0132c8b410d8 100644 --- a/crates/stages/types/src/lib.rs +++ b/crates/stages/types/src/lib.rs @@ -6,8 +6,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] mod id; @@ -21,6 +19,9 @@ pub use checkpoints::{ StageUnitCheckpoint, StorageHashingCheckpoint, }; +mod execution; +pub use execution::*; + /// Direction and target block for pipeline operations. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PipelineTarget { diff --git a/crates/static-file/static-file/Cargo.toml b/crates/static-file/static-file/Cargo.toml index 29a601f050d0..1a1921d58c5c 100644 --- a/crates/static-file/static-file/Cargo.toml +++ b/crates/static-file/static-file/Cargo.toml @@ -21,6 +21,7 @@ reth-nippy-jar.workspace = true reth-tokio-util.workspace = true reth-prune-types.workspace = true reth-static-file-types.workspace = true +reth-stages-types.workspace = true alloy-primitives.workspace = true diff --git a/crates/static-file/static-file/src/static_file_producer.rs b/crates/static-file/static-file/src/static_file_producer.rs index 44ea3a5c84b4..eb9422804495 100644 --- a/crates/static-file/static-file/src/static_file_producer.rs +++ b/crates/static-file/static-file/src/static_file_producer.rs @@ -5,8 +5,12 @@ use alloy_primitives::BlockNumber; use parking_lot::Mutex; use rayon::prelude::*; use reth_db_api::database::Database; -use reth_provider::{providers::StaticFileWriter, ProviderFactory, StaticFileProviderFactory}; +use reth_provider::{ + providers::StaticFileWriter, ProviderFactory, StageCheckpointReader as _, + StaticFileProviderFactory, +}; use reth_prune_types::PruneModes; +use reth_stages_types::StageId; use reth_static_file_types::HighestStaticFiles; use reth_storage_errors::provider::ProviderResult; use reth_tokio_util::{EventSender, EventStream}; @@ -56,7 +60,7 @@ pub struct StaticFileProducerInner { event_sender: EventSender, } -/// Static File targets, per data part, measured in [`BlockNumber`]. +/// Static File targets, per data segment, measured in [`BlockNumber`]. #[derive(Debug, Clone, Eq, PartialEq)] pub struct StaticFileTargets { headers: Option>, @@ -167,6 +171,28 @@ impl StaticFileProducerInner { Ok(targets) } + /// Copies data from database to static files according to + /// [stage checkpoints](reth_stages_types::StageCheckpoint). + /// + /// Returns highest block numbers for all static file segments. + pub fn copy_to_static_files(&self) -> ProviderResult { + let provider = self.provider_factory.provider()?; + let stages_checkpoints = [StageId::Headers, StageId::Execution, StageId::Bodies] + .into_iter() + .map(|stage| provider.get_stage_checkpoint(stage).map(|c| c.map(|c| c.block_number))) + .collect::, _>>()?; + + let highest_static_files = HighestStaticFiles { + headers: stages_checkpoints[0], + receipts: stages_checkpoints[1], + transactions: stages_checkpoints[2], + }; + let targets = self.get_static_file_targets(highest_static_files)?; + self.run(targets)?; + + Ok(highest_static_files) + } + /// Returns a static file targets at the provided finalized block numbers per segment. /// The target is determined by the check against highest `static_files` using /// [`reth_provider::providers::StaticFileProvider::get_highest_static_files`]. diff --git a/crates/static-file/types/src/lib.rs b/crates/static-file/types/src/lib.rs index f78d61f6961b..556ec8f90676 100644 --- a/crates/static-file/types/src/lib.rs +++ b/crates/static-file/types/src/lib.rs @@ -20,7 +20,7 @@ pub use segment::{SegmentConfig, SegmentHeader, SegmentRangeInclusive, StaticFil /// Default static file block count. pub const BLOCKS_PER_STATIC_FILE: u64 = 500_000; -/// Highest static file block numbers, per data part. +/// Highest static file block numbers, per data segment. #[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] pub struct HighestStaticFiles { /// Highest static file block of headers, inclusive. @@ -53,6 +53,11 @@ impl HighestStaticFiles { } } + /// Returns the minimum block of all segments. + pub fn min(&self) -> Option { + [self.headers, self.transactions, self.receipts].iter().filter_map(|&option| option).min() + } + /// Returns the maximum block of all segments. pub fn max(&self) -> Option { [self.headers, self.transactions, self.receipts].iter().filter_map(|&option| option).max() diff --git a/crates/storage/codecs/src/lib.rs b/crates/storage/codecs/src/lib.rs index b0927a1481cb..bea26090deb1 100644 --- a/crates/storage/codecs/src/lib.rs +++ b/crates/storage/codecs/src/lib.rs @@ -14,8 +14,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index 07d402d4afa8..7286e03f2da4 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -71,4 +71,4 @@ arbitrary = [ "dep:arbitrary", "dep:proptest", ] -optimism = [] +optimism = ["reth-primitives/optimism"] diff --git a/crates/storage/db-api/src/lib.rs b/crates/storage/db-api/src/lib.rs index 284321092320..dc7ab0eb4a65 100644 --- a/crates/storage/db-api/src/lib.rs +++ b/crates/storage/db-api/src/lib.rs @@ -58,8 +58,6 @@ )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] /// Common types used throughout the abstraction. pub mod common; diff --git a/crates/storage/db-api/src/models/mod.rs b/crates/storage/db-api/src/models/mod.rs index f5ef4ea5fcce..df6467336507 100644 --- a/crates/storage/db-api/src/models/mod.rs +++ b/crates/storage/db-api/src/models/mod.rs @@ -314,70 +314,69 @@ mod tests { // // this check is to ensure we do not inadvertently add too many fields to a struct which would // expand the flags field and break backwards compatibility + #[cfg(not(feature = "optimism"))] #[test] fn test_ensure_backwards_compatibility() { - #[cfg(not(feature = "optimism"))] - { - assert_eq!(Account::bitflag_encoded_bytes(), 2); - assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); - assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); - assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); - assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); - assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(Header::bitflag_encoded_bytes(), 4); - assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); - assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); - assert_eq!(Receipt::bitflag_encoded_bytes(), 1); - assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); - assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); - assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); - assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); - assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); - assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); - assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); - assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); - assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); - } - - #[cfg(feature = "optimism")] - { - assert_eq!(Account::bitflag_encoded_bytes(), 2); - assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); - assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); - assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); - assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); - assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(Header::bitflag_encoded_bytes(), 4); - assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); - assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); - assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); - assert_eq!(Receipt::bitflag_encoded_bytes(), 2); - assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); - assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); - assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); - assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); - assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); - assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); - assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); - assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); - assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); - assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); - assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); - } + assert_eq!(Account::bitflag_encoded_bytes(), 2); + assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); + assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); + assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); + assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); + assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(Header::bitflag_encoded_bytes(), 4); + assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); + assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); + assert_eq!(Receipt::bitflag_encoded_bytes(), 1); + assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); + assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); + assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); + assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); + assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); + assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); + assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); + assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); + assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); + } + + #[cfg(feature = "optimism")] + #[test] + fn test_ensure_backwards_compatibility() { + assert_eq!(Account::bitflag_encoded_bytes(), 2); + assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1); + assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0); + assert_eq!(CompactU256::bitflag_encoded_bytes(), 1); + assert_eq!(CompactU64::bitflag_encoded_bytes(), 1); + assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(Header::bitflag_encoded_bytes(), 4); + assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0); + assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(PruneMode::bitflag_encoded_bytes(), 1); + assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1); + assert_eq!(Receipt::bitflag_encoded_bytes(), 2); + assert_eq!(ReceiptWithBloom::bitflag_encoded_bytes(), 0); + assert_eq!(SealedHeader::bitflag_encoded_bytes(), 0); + assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1); + assert_eq!(StoredBlockOmmers::bitflag_encoded_bytes(), 0); + assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0); + assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1); + assert_eq!(TxEip1559::bitflag_encoded_bytes(), 4); + assert_eq!(TxEip2930::bitflag_encoded_bytes(), 3); + assert_eq!(TxEip4844::bitflag_encoded_bytes(), 5); + assert_eq!(TxLegacy::bitflag_encoded_bytes(), 3); + assert_eq!(Withdrawals::bitflag_encoded_bytes(), 0); } } diff --git a/crates/storage/db-common/Cargo.toml b/crates/storage/db-common/Cargo.toml index c2760f672793..d80236defd32 100644 --- a/crates/storage/db-common/Cargo.toml +++ b/crates/storage/db-common/Cargo.toml @@ -19,6 +19,7 @@ reth-trie.workspace = true reth-etl.workspace = true reth-codecs.workspace = true reth-stages-types.workspace = true +reth-fs-util.workspace = true # eth alloy-genesis.workspace = true @@ -26,6 +27,7 @@ alloy-genesis.workspace = true # misc eyre.workspace = true thiserror.workspace = true +boyer-moore-magiclen.workspace = true # io serde.workspace = true diff --git a/bin/reth/src/utils.rs b/crates/storage/db-common/src/db_tool/mod.rs similarity index 95% rename from bin/reth/src/utils.rs rename to crates/storage/db-common/src/db_tool/mod.rs index 1dd4f6893c1f..3884089b4370 100644 --- a/bin/reth/src/utils.rs +++ b/crates/storage/db-common/src/db_tool/mod.rs @@ -1,4 +1,4 @@ -//! Common CLI utility functions. +//! Common db operations use boyer_moore_magiclen::BMByte; use eyre::Result; @@ -16,15 +16,6 @@ use reth_provider::{ChainSpecProvider, ProviderFactory}; use std::{path::Path, rc::Rc, sync::Arc}; use tracing::info; -/// Exposing `open_db_read_only` function -pub mod db { - pub use reth_db::open_db_read_only; -} - -/// Re-exported from `reth_node_core`, also to prevent a breaking change. See the comment on -/// the `reth_node_core::args` re-export for more details. -pub use reth_node_core::utils::*; - /// Wrapper over DB that implements many useful DB queries. #[derive(Debug)] pub struct DbTool { diff --git a/crates/storage/db-common/src/init.rs b/crates/storage/db-common/src/init.rs index c6b4802b7829..76314f0c8b71 100644 --- a/crates/storage/db-common/src/init.rs +++ b/crates/storage/db-common/src/init.rs @@ -620,7 +620,7 @@ mod tests { ]), ..Default::default() }, - hardforks: BTreeMap::default(), + hardforks: Default::default(), genesis_hash: None, paris_block_and_final_difficulty: None, deposit_contract: None, diff --git a/crates/storage/db-common/src/lib.rs b/crates/storage/db-common/src/lib.rs index abcbc62762a4..173e53143408 100644 --- a/crates/storage/db-common/src/lib.rs +++ b/crates/storage/db-common/src/lib.rs @@ -9,3 +9,6 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] pub mod init; + +mod db_tool; +pub use db_tool::*; diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index c968647a982d..6d5bf4490a22 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -11,9 +11,6 @@ //! //! TODO(onbjerg): Find appropriate format for this... -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] - pub mod codecs; mod raw; @@ -411,6 +408,12 @@ tables! { /// Stores generic chain state info, like the last finalized block. table ChainState; + + /// CHANGE(taiko): Stores L1 origin information. + table L1Origins>; + + /// CHANGE(taiko): Stores latest L1 origin. + table HeadL1Origin; } /// Keys for the `ChainState` table. diff --git a/crates/storage/errors/src/provider.rs b/crates/storage/errors/src/provider.rs index 52a010474f96..52b4674aa048 100644 --- a/crates/storage/errors/src/provider.rs +++ b/crates/storage/errors/src/provider.rs @@ -18,6 +18,9 @@ pub type ProviderResult = Result; /// Bundled errors variants thrown by various providers. #[derive(Clone, Debug, thiserror_no_std::Error, PartialEq, Eq)] pub enum ProviderError { + /// Serde error. + #[error("{0}")] + Serde(String), /// Database error. #[error(transparent)] Database(#[from] crate::db::DatabaseError), diff --git a/crates/storage/nippy-jar/src/error.rs b/crates/storage/nippy-jar/src/error.rs index a440a9cb3e30..225d4fba30fb 100644 --- a/crates/storage/nippy-jar/src/error.rs +++ b/crates/storage/nippy-jar/src/error.rs @@ -24,7 +24,7 @@ pub enum NippyJarError { #[error("unexpected missing value: row:col {0}:{1}")] UnexpectedMissingValue(u64, u64), #[error(transparent)] - FilterError(#[from] cuckoofilter::CuckooError), + EthFilterError(#[from] cuckoofilter::CuckooError), #[error("nippy jar initialized without filter")] FilterMissing, #[error("filter has reached max capacity")] diff --git a/crates/storage/provider/Cargo.toml b/crates/storage/provider/Cargo.toml index 6cf456665bdf..69c35badbd82 100644 --- a/crates/storage/provider/Cargo.toml +++ b/crates/storage/provider/Cargo.toml @@ -53,6 +53,7 @@ pin-project.workspace = true parking_lot.workspace = true dashmap = { workspace = true, features = ["inline"] } strum.workspace = true +serde_json.workspace = true # test-utils alloy-rlp = { workspace = true, optional = true } diff --git a/crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs b/crates/storage/provider/src/bundle_state/execution_outcome.rs similarity index 100% rename from crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs rename to crates/storage/provider/src/bundle_state/execution_outcome.rs diff --git a/crates/storage/provider/src/bundle_state/mod.rs b/crates/storage/provider/src/bundle_state/mod.rs index d1a9e9b2a14d..eaf3dab43ee9 100644 --- a/crates/storage/provider/src/bundle_state/mod.rs +++ b/crates/storage/provider/src/bundle_state/mod.rs @@ -1,13 +1,12 @@ //! Bundle state module. //! This module contains all the logic related to bundle state. -mod bundle_state_with_receipts; + +mod execution_outcome; mod hashed_state_changes; mod state_changes; mod state_reverts; -pub use bundle_state_with_receipts::{ - AccountRevertInit, BundleStateInit, OriginalValuesKnown, RevertsInit, -}; +pub use execution_outcome::{AccountRevertInit, BundleStateInit, OriginalValuesKnown, RevertsInit}; pub use hashed_state_changes::HashedStateChanges; pub use state_changes::StateChanges; pub use state_reverts::{StateReverts, StorageRevertsIter}; diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 57e7e9615217..9c65103a4226 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -330,6 +330,14 @@ impl BlockReader for ProviderFactory { self.provider()?.block_with_senders(id, transaction_kind) } + fn sealed_block_with_senders( + &self, + id: BlockHashOrNumber, + transaction_kind: TransactionVariant, + ) -> ProviderResult> { + self.provider()?.sealed_block_with_senders(id, transaction_kind) + } + fn block_range(&self, range: RangeInclusive) -> ProviderResult> { self.provider()?.block_range(range) } @@ -519,22 +527,6 @@ impl EvmEnvProvider for ProviderFactory { self.provider()?.fill_env_with_header(cfg, block_env, header, evm_config) } - fn fill_block_env_at( - &self, - block_env: &mut BlockEnv, - at: BlockHashOrNumber, - ) -> ProviderResult<()> { - self.provider()?.fill_block_env_at(block_env, at) - } - - fn fill_block_env_with_header( - &self, - block_env: &mut BlockEnv, - header: &Header, - ) -> ProviderResult<()> { - self.provider()?.fill_block_env_with_header(block_env, header) - } - fn fill_cfg_env_at( &self, cfg: &mut CfgEnvWithHandlerCfg, diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 02287b96cad0..67d98d21d02c 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -3,7 +3,8 @@ use crate::{ providers::{database::metrics, static_file::StaticFileWriter, StaticFileProvider}, to_range, traits::{ - AccountExtReader, BlockSource, ChangeSetReader, ReceiptProvider, StageCheckpointWriter, + AccountExtReader, BlockSource, ChangeSetReader, L1OriginReader, L1OriginWriter, + ReceiptProvider, StageCheckpointWriter, }, AccountReader, BlockExecutionWriter, BlockHashReader, BlockNumReader, BlockReader, BlockWriter, EvmEnvProvider, FinalizedBlockReader, FinalizedBlockWriter, HashingWriter, HeaderProvider, @@ -14,7 +15,7 @@ use crate::{ WithdrawalsProvider, }; use itertools::{izip, Itertools}; -use reth_chainspec::{ChainInfo, ChainSpec}; +use reth_chainspec::{ChainInfo, ChainSpec, EthereumHardforks}; use reth_db::{tables, BlockNumberList}; use reth_db_api::{ common::KeyValue, @@ -32,10 +33,8 @@ use reth_evm::ConfigureEvmEnv; use reth_execution_types::{Chain, ExecutionOutcome}; use reth_network_p2p::headers::downloader::SyncTarget; use reth_primitives::{ - keccak256, - revm::{config::revm_spec, env::fill_block_env}, - Account, Address, Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithSenders, - GotExpected, Head, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, + keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockNumber, + BlockWithSenders, GotExpected, Header, L1Origin, Receipt, Requests, SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry, TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, @@ -48,7 +47,7 @@ use reth_trie::{ updates::TrieUpdates, HashedPostState, Nibbles, StateRoot, }; -use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg, SpecId}; +use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg}; use std::{ cmp::Ordering, collections::{hash_map, BTreeMap, BTreeSet, HashMap, HashSet}, @@ -231,7 +230,7 @@ where while let Some((sharded_key, list)) = item { // If the shard does not belong to the key, break. if !shard_belongs_to_key(&sharded_key) { - break + break; } cursor.delete_current()?; @@ -240,12 +239,12 @@ where let first = list.iter().next().expect("List can't be empty"); if first >= block_number { item = cursor.prev()?; - continue + continue; } else if block_number <= sharded_key.as_ref().highest_block_number { // Filter out all elements greater than block number. - return Ok(list.iter().take_while(|i| *i < block_number).collect::>()) + return Ok(list.iter().take_while(|i| *i < block_number).collect::>()); } else { - return Ok(list.iter().collect::>()) + return Ok(list.iter().collect::>()); } } @@ -359,6 +358,65 @@ impl DatabaseProvider { ) } + fn block_with_senders( + &self, + id: BlockHashOrNumber, + transaction_kind: TransactionVariant, + header_by_number: HF, + construct_block: BF, + ) -> ProviderResult> + where + H: AsRef
, + HF: FnOnce(BlockNumber) -> ProviderResult>, + BF: FnOnce( + H, + Vec, + Vec
, + Vec
, + Option, + Option, + ) -> ProviderResult>, + { + let Some(block_number) = self.convert_hash_or_number(id)? else { return Ok(None) }; + let Some(header) = header_by_number(block_number)? else { return Ok(None) }; + + let ommers = self.ommers(block_number.into())?.unwrap_or_default(); + let withdrawals = + self.withdrawals_by_block(block_number.into(), header.as_ref().timestamp)?; + let requests = self.requests_by_block(block_number.into(), header.as_ref().timestamp)?; + + // Get the block body + // + // If the body indices are not found, this means that the transactions either do not exist + // in the database yet, or they do exit but are not indexed. If they exist but are not + // indexed, we don't have enough information to return the block anyways, so we return + // `None`. + let Some(body) = self.block_body_indices(block_number)? else { return Ok(None) }; + + let tx_range = body.tx_num_range(); + + let (transactions, senders) = if tx_range.is_empty() { + (vec![], vec![]) + } else { + (self.transactions_by_tx_range(tx_range.clone())?, self.senders_by_tx_range(tx_range)?) + }; + + let body = transactions + .into_iter() + .map(|tx| match transaction_kind { + TransactionVariant::NoHash => TransactionSigned { + // Caller explicitly asked for no hash, so we don't calculate it + hash: B256::ZERO, + signature: tx.signature, + transaction: tx.transaction, + }, + TransactionVariant::WithHash => tx.with_hash(), + }) + .collect(); + + construct_block(header, body, senders, ommers, withdrawals, requests) + } + /// Returns a range of blocks from the database. /// /// Uses the provided `headers_range` to get the headers for the range, and `assemble_block` to @@ -733,7 +791,7 @@ impl DatabaseProvider { let block_bodies = self.get_or_take::(range)?; if block_bodies.is_empty() { - return Ok(Vec::new()) + return Ok(Vec::new()); } // Compute the first and last tx ID in the range @@ -742,7 +800,7 @@ impl DatabaseProvider { // If this is the case then all of the blocks in the range are empty if last_transaction < first_transaction { - return Ok(block_bodies.into_iter().map(|(n, _)| (n, Vec::new())).collect()) + return Ok(block_bodies.into_iter().map(|(n, _)| (n, Vec::new())).collect()); } // Get transactions and senders @@ -884,7 +942,7 @@ impl DatabaseProvider { let block_headers = self.get_or_take::(range.clone())?; if block_headers.is_empty() { - return Ok(Vec::new()) + return Ok(Vec::new()); } let block_header_hashes = @@ -1007,7 +1065,7 @@ impl DatabaseProvider { while let Some(Ok((entry_key, _))) = reverse_walker.next() { if selector(entry_key.clone()) <= key { - break + break; } reverse_walker.delete_current()?; deleted += 1; @@ -1156,7 +1214,7 @@ impl DatabaseProvider { // delete old shard so new one can be inserted. self.tx.delete::(shard_key, None)?; let list = list.iter().collect::>(); - return Ok(list) + return Ok(list); } Ok(Vec::new()) } @@ -1346,7 +1404,7 @@ impl HeaderProvider for DatabaseProvider { if let Some(td) = self.chain_spec.final_paris_total_difficulty(number) { // if this block is higher than the final paris(merge) block, return the final paris // difficulty - return Ok(Some(td)) + return Ok(Some(td)); } self.static_file_provider.get_with_static_file_or_database( @@ -1403,7 +1461,7 @@ impl HeaderProvider for DatabaseProvider { .ok_or_else(|| ProviderError::HeaderNotFound(number.into()))?; let sealed = header.seal(hash); if !predicate(&sealed) { - break + break; } headers.push(sealed); } @@ -1525,11 +1583,11 @@ impl BlockReader for DatabaseProvider { // If the Paris (Merge) hardfork block is known and block is after it, return empty // ommers. if self.chain_spec.final_paris_total_difficulty(number).is_some() { - return Ok(Some(Vec::new())) + return Ok(Some(Vec::new())); } let ommers = self.tx.get::(number)?.map(|o| o.ommers); - return Ok(ommers) + return Ok(ommers); } Ok(None) @@ -1552,48 +1610,41 @@ impl BlockReader for DatabaseProvider { id: BlockHashOrNumber, transaction_kind: TransactionVariant, ) -> ProviderResult> { - let Some(block_number) = self.convert_hash_or_number(id)? else { return Ok(None) }; - let Some(header) = self.header_by_number(block_number)? else { return Ok(None) }; - - let ommers = self.ommers(block_number.into())?.unwrap_or_default(); - let withdrawals = self.withdrawals_by_block(block_number.into(), header.timestamp)?; - let requests = self.requests_by_block(block_number.into(), header.timestamp)?; - - // Get the block body - // - // If the body indices are not found, this means that the transactions either do not exist - // in the database yet, or they do exit but are not indexed. If they exist but are not - // indexed, we don't have enough information to return the block anyways, so we return - // `None`. - let Some(body) = self.block_body_indices(block_number)? else { return Ok(None) }; - - let tx_range = body.tx_num_range(); - - let (transactions, senders) = if tx_range.is_empty() { - (vec![], vec![]) - } else { - (self.transactions_by_tx_range(tx_range.clone())?, self.senders_by_tx_range(tx_range)?) - }; - - let body = transactions - .into_iter() - .map(|tx| match transaction_kind { - TransactionVariant::NoHash => TransactionSigned { - // Caller explicitly asked for no hash, so we don't calculate it - hash: B256::ZERO, - signature: tx.signature, - transaction: tx.transaction, - }, - TransactionVariant::WithHash => tx.with_hash(), - }) - .collect(); + self.block_with_senders( + id, + transaction_kind, + |block_number| self.header_by_number(block_number), + |header, body, senders, ommers, withdrawals, requests| { + Block { header, body, ommers, withdrawals, requests } + // Note: we're using unchecked here because we know the block contains valid txs + // wrt to its height and can ignore the s value check so pre + // EIP-2 txs are allowed + .try_with_senders_unchecked(senders) + .map(Some) + .map_err(|_| ProviderError::SenderRecoveryError) + }, + ) + } - Block { header, body, ommers, withdrawals, requests } - // Note: we're using unchecked here because we know the block contains valid txs wrt to - // its height and can ignore the s value check so pre EIP-2 txs are allowed - .try_with_senders_unchecked(senders) - .map(Some) - .map_err(|_| ProviderError::SenderRecoveryError) + fn sealed_block_with_senders( + &self, + id: BlockHashOrNumber, + transaction_kind: TransactionVariant, + ) -> ProviderResult> { + self.block_with_senders( + id, + transaction_kind, + |block_number| self.sealed_header(block_number), + |header, body, senders, ommers, withdrawals, requests| { + SealedBlock { header, body, ommers, withdrawals, requests } + // Note: we're using unchecked here because we know the block contains valid txs + // wrt to its height and can ignore the s value check so pre + // EIP-2 txs are allowed + .try_with_senders_unchecked(senders) + .map(Some) + .map_err(|_| ProviderError::SenderRecoveryError) + }, + ) } fn block_range(&self, range: RangeInclusive) -> ProviderResult> { @@ -1789,7 +1840,7 @@ impl TransactionsProvider for DatabaseProvider { timestamp: header.timestamp, }; - return Ok(Some((transaction, meta))) + return Ok(Some((transaction, meta))); } } } @@ -1822,7 +1873,7 @@ impl TransactionsProvider for DatabaseProvider { .map(Into::into) .collect(), )) - } + }; } } Ok(None) @@ -1900,7 +1951,7 @@ impl ReceiptProvider for DatabaseProvider { Ok(Some(Vec::new())) } else { self.receipts_by_tx_range(tx_range).map(Some) - } + }; } } Ok(None) @@ -1935,7 +1986,7 @@ impl WithdrawalsProvider for DatabaseProvider { .get::(number) .map(|w| w.map(|w| w.withdrawals))? .unwrap_or_default(); - return Ok(Some(withdrawals)) + return Ok(Some(withdrawals)); } } Ok(None) @@ -2005,41 +2056,6 @@ impl EvmEnvProvider for DatabaseProvider { Ok(()) } - fn fill_block_env_at( - &self, - block_env: &mut BlockEnv, - at: BlockHashOrNumber, - ) -> ProviderResult<()> { - let hash = self.convert_number(at)?.ok_or(ProviderError::HeaderNotFound(at))?; - let header = self.header(&hash)?.ok_or(ProviderError::HeaderNotFound(at))?; - - self.fill_block_env_with_header(block_env, &header) - } - - fn fill_block_env_with_header( - &self, - block_env: &mut BlockEnv, - header: &Header, - ) -> ProviderResult<()> { - let total_difficulty = self - .header_td_by_number(header.number)? - .ok_or_else(|| ProviderError::HeaderNotFound(header.number.into()))?; - let spec_id = revm_spec( - &self.chain_spec, - Head { - number: header.number, - timestamp: header.timestamp, - difficulty: header.difficulty, - total_difficulty, - // Not required - hash: Default::default(), - }, - ); - let after_merge = spec_id >= SpecId::MERGE; - fill_block_env(block_env, &self.chain_spec, header, after_merge); - Ok(()) - } - fn fill_cfg_env_at( &self, cfg: &mut CfgEnvWithHandlerCfg, @@ -2379,7 +2395,7 @@ impl HashingWriter for DatabaseProvider { root: GotExpected { got: state_root, expected: expected_state_root }, block_number: *range.end(), block_hash: end_block_hash, - }))) + }))); } trie_updates.flush(&self.tx)?; } @@ -2459,8 +2475,8 @@ impl HistoryWriter for DatabaseProvider { StorageShardedKey::last(address, storage_key), rem_index, |storage_sharded_key| { - storage_sharded_key.address == address && - storage_sharded_key.sharded_key.key == storage_key + storage_sharded_key.address == address + && storage_sharded_key.sharded_key.key == storage_key }, )?; @@ -2575,7 +2591,7 @@ impl BlockExecutionWriter for DatabaseProvider { root: GotExpected { got: new_state_root, expected: parent_state_root }, block_number: parent_number, block_hash: parent_hash, - }))) + }))); } trie_updates.flush(&self.tx)?; } @@ -2754,7 +2770,7 @@ impl BlockWriter for DatabaseProvider { ) -> ProviderResult<()> { if blocks.is_empty() { debug!(target: "providers::db", "Attempted to append empty block range"); - return Ok(()) + return Ok(()); } let first_number = blocks.first().unwrap().number; @@ -2864,3 +2880,32 @@ fn range_size_hint(range: &impl RangeBounds) -> Option { }; end.checked_sub(start).map(|x| x as _) } + +impl L1OriginReader for DatabaseProvider { + fn read_l1_origin(&self, block_id: u64) -> ProviderResult> { + let result = self.tx.get::(L1Origin::key(block_id))?; + if let Some(bytes) = result { + Ok(Some( + serde_json::from_slice(&bytes).map_err(|e| ProviderError::Serde(e.to_string()))?, + )) + } else { + Ok(None) + } + } + + fn read_head_l1_origin(&self) -> ProviderResult> { + Ok(self.tx.get::(L1Origin::head_key())?) + } +} + +impl L1OriginWriter for DatabaseProvider { + fn insert_l1_origin(&self, block_id: u64, l1_origin: L1Origin) -> ProviderResult<()> { + let bytes = + serde_json::to_vec(&l1_origin).map_err(|e| ProviderError::Serde(e.to_string()))?; + Ok(self.tx.put::(L1Origin::key(block_id), bytes)?) + } + + fn insert_head_l1_origin(&self, block_id: u64) -> ProviderResult<()> { + Ok(self.tx.put::(L1Origin::head_key(), block_id)?) + } +} diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 9da41269c137..742b8f5d0c49 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -2,8 +2,8 @@ use crate::{ AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, DatabaseProviderFactory, - EvmEnvProvider, FullExecutionDataProvider, HeaderProvider, ProviderError, - PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider, + EvmEnvProvider, FullExecutionDataProvider, HeaderProvider, L1OriginReader, L1OriginWriter, + ProviderError, PruneCheckpointReader, ReceiptProvider, ReceiptProviderIdExt, RequestsProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, TreeViewer, WithdrawalsProvider, }; @@ -20,7 +20,7 @@ use reth_db_api::{ use reth_evm::ConfigureEvmEnv; use reth_primitives::{ Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, - BlockNumberOrTag, BlockWithSenders, Header, Receipt, SealedBlock, SealedBlockWithSenders, + BlockNumberOrTag, BlockWithSenders, Header, L1Origin, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; @@ -328,6 +328,14 @@ where self.database.block_with_senders(id, transaction_kind) } + fn sealed_block_with_senders( + &self, + id: BlockHashOrNumber, + transaction_kind: TransactionVariant, + ) -> ProviderResult> { + self.database.sealed_block_with_senders(id, transaction_kind) + } + fn block_range(&self, range: RangeInclusive) -> ProviderResult> { self.database.block_range(range) } @@ -538,22 +546,6 @@ where self.database.provider()?.fill_env_with_header(cfg, block_env, header, evm_config) } - fn fill_block_env_at( - &self, - block_env: &mut BlockEnv, - at: BlockHashOrNumber, - ) -> ProviderResult<()> { - self.database.provider()?.fill_block_env_at(block_env, at) - } - - fn fill_block_env_with_header( - &self, - block_env: &mut BlockEnv, - header: &Header, - ) -> ProviderResult<()> { - self.database.provider()?.fill_block_env_with_header(block_env, header) - } - fn fill_cfg_env_at( &self, cfg: &mut CfgEnvWithHandlerCfg, @@ -648,7 +640,7 @@ where if let Some(block) = self.tree.pending_block_num_hash() { if let Ok(pending) = self.tree.pending_state_provider(block.hash) { - return self.pending_with_provider(pending) + return self.pending_with_provider(pending); } } @@ -658,7 +650,7 @@ where fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult> { if let Some(state) = self.tree.find_pending_state_provider(block_hash) { - return Ok(Some(self.pending_with_provider(state)?)) + return Ok(Some(self.pending_with_provider(state)?)); } Ok(None) } @@ -919,3 +911,29 @@ where self.database.provider()?.basic_account(address) } } + +impl L1OriginReader for BlockchainProvider +where + DB: Database, +{ + fn read_l1_origin(&self, block_id: u64) -> ProviderResult> { + self.database.provider()?.read_l1_origin(block_id) + } + + fn read_head_l1_origin(&self) -> ProviderResult> { + self.database.provider()?.read_head_l1_origin() + } +} + +impl L1OriginWriter for BlockchainProvider +where + DB: Database, +{ + fn insert_l1_origin(&self, block_id: u64, l1_origin: L1Origin) -> ProviderResult<()> { + self.database.provider_rw()?.insert_l1_origin(block_id, l1_origin) + } + + fn insert_head_l1_origin(&self, block_id: u64) -> ProviderResult<()> { + self.database.provider_rw()?.insert_head_l1_origin(block_id) + } +} diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 39e588c7f5f4..19d6b06843d7 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -1457,6 +1457,15 @@ impl BlockReader for StaticFileProvider { Err(ProviderError::UnsupportedProvider) } + fn sealed_block_with_senders( + &self, + _id: BlockHashOrNumber, + _transaction_kind: TransactionVariant, + ) -> ProviderResult> { + // Required data not present in static_files + Err(ProviderError::UnsupportedProvider) + } + fn block_range(&self, _range: RangeInclusive) -> ProviderResult> { // Required data not present in static_files Err(ProviderError::UnsupportedProvider) diff --git a/crates/storage/provider/src/providers/static_file/mod.rs b/crates/storage/provider/src/providers/static_file/mod.rs index 5c2057b3b57d..e7073defeed0 100644 --- a/crates/storage/provider/src/providers/static_file/mod.rs +++ b/crates/storage/provider/src/providers/static_file/mod.rs @@ -69,6 +69,7 @@ mod tests { }; use reth_primitives::{static_file::find_fixed_range, BlockNumber, B256, U256}; use reth_testing_utils::generators::{self, random_header_range}; + use std::vec::IntoIter; #[test] fn test_snap() { @@ -128,9 +129,7 @@ mod tests { let provider = factory.provider().unwrap(); let tx = provider.tx_ref(); - // Hacky type inference. TODO fix - let mut none_vec = Some(vec![vec![vec![0u8]].into_iter()]); - let _ = none_vec.take(); + let none_vec: Option>>> = None; // Generate list of hashes for filters & PHF let mut cursor = tx.cursor_read::>().unwrap(); diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 974982121a7e..83de45c8aa4f 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -2,8 +2,9 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, FullExecutionDataProvider, HeaderProvider, - ReceiptProviderIdExt, RequestsProvider, StateProvider, StateProviderBox, StateProviderFactory, - StateRootProvider, TransactionVariant, TransactionsProvider, WithdrawalsProvider, + L1OriginReader, L1OriginWriter, ReceiptProviderIdExt, RequestsProvider, StateProvider, + StateProviderBox, StateProviderFactory, StateRootProvider, TransactionVariant, + TransactionsProvider, WithdrawalsProvider, }; use parking_lot::Mutex; use reth_chainspec::{ChainInfo, ChainSpec}; @@ -11,7 +12,7 @@ use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, - BlockWithSenders, Bytecode, Bytes, Header, Receipt, SealedBlock, SealedBlockWithSenders, + BlockWithSenders, Bytecode, Bytes, Header, L1Origin, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; @@ -249,7 +250,7 @@ impl TransactionsProvider for MockEthProvider { excess_blob_gas: block.header.excess_blob_gas, timestamp: block.header.timestamp, }; - return Ok(Some((tx.clone(), meta))) + return Ok(Some((tx.clone(), meta))); } } } @@ -261,7 +262,7 @@ impl TransactionsProvider for MockEthProvider { let mut current_tx_number: TxNumber = 0; for block in lock.values() { if current_tx_number + (block.body.len() as TxNumber) > id { - return Ok(Some(block.header.number)) + return Ok(Some(block.header.number)); } current_tx_number += block.body.len() as TxNumber; } @@ -474,6 +475,14 @@ impl BlockReader for MockEthProvider { Ok(None) } + fn sealed_block_with_senders( + &self, + _id: BlockHashOrNumber, + _transaction_kind: TransactionVariant, + ) -> ProviderResult> { + Ok(None) + } + fn block_range(&self, range: RangeInclusive) -> ProviderResult> { let lock = self.blocks.lock(); @@ -599,22 +608,6 @@ impl EvmEnvProvider for MockEthProvider { Ok(()) } - fn fill_block_env_at( - &self, - _block_env: &mut BlockEnv, - _at: BlockHashOrNumber, - ) -> ProviderResult<()> { - Ok(()) - } - - fn fill_block_env_with_header( - &self, - _block_env: &mut BlockEnv, - _header: &Header, - ) -> ProviderResult<()> { - Ok(()) - } - fn fill_cfg_env_at( &self, _cfg: &mut CfgEnvWithHandlerCfg, @@ -704,3 +697,23 @@ impl ChangeSetReader for MockEthProvider { Ok(Vec::default()) } } + +impl L1OriginReader for MockEthProvider { + fn read_l1_origin(&self, _block_id: u64) -> ProviderResult> { + Ok(None) + } + + fn read_head_l1_origin(&self) -> ProviderResult> { + Ok(None) + } +} + +impl L1OriginWriter for MockEthProvider { + fn insert_l1_origin(&self, _block_id: u64, _origin: L1Origin) -> ProviderResult<()> { + Ok(()) + } + + fn insert_head_l1_origin(&self, _block_id: u64) -> ProviderResult<()> { + Ok(()) + } +} diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 74577732d2a7..ec5e8555a727 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,17 +1,17 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, - ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, PruneCheckpointReader, - ReceiptProviderIdExt, RequestsProvider, StageCheckpointReader, StateProvider, StateProviderBox, - StateProviderFactory, StateRootProvider, TransactionVariant, TransactionsProvider, - WithdrawalsProvider, + ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, L1OriginReader, + L1OriginWriter, PruneCheckpointReader, ReceiptProviderIdExt, RequestsProvider, + StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, + TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; use reth_chainspec::{ChainInfo, ChainSpec, MAINNET}; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockWithSenders, - Bytecode, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, + Bytecode, Header, L1Origin, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; @@ -113,6 +113,14 @@ impl BlockReader for NoopProvider { Ok(None) } + fn sealed_block_with_senders( + &self, + _id: BlockHashOrNumber, + _transaction_kind: TransactionVariant, + ) -> ProviderResult> { + Ok(None) + } + fn block_range(&self, _range: RangeInclusive) -> ProviderResult> { Ok(vec![]) } @@ -358,22 +366,6 @@ impl EvmEnvProvider for NoopProvider { Ok(()) } - fn fill_block_env_at( - &self, - _block_env: &mut BlockEnv, - _at: BlockHashOrNumber, - ) -> ProviderResult<()> { - Ok(()) - } - - fn fill_block_env_with_header( - &self, - _block_env: &mut BlockEnv, - _header: &Header, - ) -> ProviderResult<()> { - Ok(()) - } - fn fill_cfg_env_at( &self, _cfg: &mut CfgEnvWithHandlerCfg, @@ -473,3 +465,23 @@ impl PruneCheckpointReader for NoopProvider { Ok(None) } } + +impl L1OriginReader for NoopProvider { + fn read_l1_origin(&self, _block_id: u64) -> ProviderResult> { + Ok(None) + } + + fn read_head_l1_origin(&self) -> ProviderResult> { + Ok(None) + } +} + +impl L1OriginWriter for NoopProvider { + fn insert_l1_origin(&self, _block_id: u64, _origin: L1Origin) -> ProviderResult<()> { + Ok(()) + } + + fn insert_head_l1_origin(&self, _block_id: u64) -> ProviderResult<()> { + Ok(()) + } +} diff --git a/crates/storage/provider/src/traits/full.rs b/crates/storage/provider/src/traits/full.rs index 6b35d6b25135..df7be2781c1f 100644 --- a/crates/storage/provider/src/traits/full.rs +++ b/crates/storage/provider/src/traits/full.rs @@ -2,8 +2,8 @@ use crate::{ AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader, - DatabaseProviderFactory, EvmEnvProvider, StageCheckpointReader, StateProviderFactory, - StaticFileProviderFactory, + DatabaseProviderFactory, EvmEnvProvider, L1OriginReader, StageCheckpointReader, + StateProviderFactory, StaticFileProviderFactory, }; use reth_db_api::database::Database; @@ -19,6 +19,7 @@ pub trait FullProvider: + ChangeSetReader + CanonStateSubscriptions + StageCheckpointReader + + L1OriginReader + Clone + Unpin + 'static @@ -36,6 +37,7 @@ impl FullProvider for T where + ChangeSetReader + CanonStateSubscriptions + StageCheckpointReader + + L1OriginReader + Clone + Unpin + 'static diff --git a/crates/storage/provider/src/traits/l1_origin.rs b/crates/storage/provider/src/traits/l1_origin.rs new file mode 100644 index 000000000000..0040091b485e --- /dev/null +++ b/crates/storage/provider/src/traits/l1_origin.rs @@ -0,0 +1,39 @@ +use auto_impl::auto_impl; +use reth_primitives::L1Origin; +use reth_storage_errors::provider::ProviderResult; + +/// Api trait for fetching `L1Origin` related data. +#[auto_impl::auto_impl(&, Arc)] +pub trait L1OriginReader: Send + Sync { + /// Tries to find in the given blocks L1 origin. + /// + /// # Returns + /// + /// Returns `None` if the L1 origin is not found. + fn read_l1_origin(&self, block_id: u64) -> ProviderResult>; + + /// Tries to find the last L1 origin. + /// + /// # Returns + /// + /// Returns `None` if the L1 origin is not found. + fn read_head_l1_origin(&self) -> ProviderResult>; +} + +/// L1 origin Writer +#[auto_impl(&, Arc, Box)] +pub trait L1OriginWriter: Send + Sync { + /// Insert L1 origin for the given block. + /// + /// # Returns + /// + /// Returns `Ok(())` on success, or an error if any operation fails. + fn insert_l1_origin(&self, block_id: u64, l1_origin: L1Origin) -> ProviderResult<()>; + + /// Inserts the latest L1 origin for the head block. + /// + /// # Returns + /// + /// Returns `Ok(())` on success, or an error if any operation fails. + fn insert_head_l1_origin(&self, block_id: u64) -> ProviderResult<()>; +} diff --git a/crates/storage/provider/src/traits/mod.rs b/crates/storage/provider/src/traits/mod.rs index bf69eda03b0b..fb869811d7fc 100644 --- a/crates/storage/provider/src/traits/mod.rs +++ b/crates/storage/provider/src/traits/mod.rs @@ -50,3 +50,6 @@ pub use tree_viewer::TreeViewer; mod finalized_block; pub use finalized_block::{FinalizedBlockReader, FinalizedBlockWriter}; + +mod l1_origin; +pub use l1_origin::{L1OriginReader, L1OriginWriter}; diff --git a/crates/storage/provider/src/traits/spec.rs b/crates/storage/provider/src/traits/spec.rs index 917051d97aca..798bfeae16fd 100644 --- a/crates/storage/provider/src/traits/spec.rs +++ b/crates/storage/provider/src/traits/spec.rs @@ -2,6 +2,7 @@ use reth_chainspec::ChainSpec; use std::sync::Arc; /// A trait for reading the current chainspec. +#[auto_impl::auto_impl(&, Arc)] pub trait ChainSpecProvider: Send + Sync { /// Get an [`Arc`] to the chainspec. fn chain_spec(&self) -> Arc; diff --git a/crates/storage/storage-api/src/block.rs b/crates/storage/storage-api/src/block.rs index 42ab05f22503..3dc22de8ae4f 100644 --- a/crates/storage/storage-api/src/block.rs +++ b/crates/storage/storage-api/src/block.rs @@ -118,6 +118,17 @@ pub trait BlockReader: transaction_kind: TransactionVariant, ) -> ProviderResult>; + /// Returns the sealed block with senders with matching number or hash from database. + /// + /// Returns the block's transactions in the requested variant. + /// + /// Returns `None` if block is not found. + fn sealed_block_with_senders( + &self, + id: BlockHashOrNumber, + transaction_kind: TransactionVariant, + ) -> ProviderResult>; + /// Returns all blocks in the given inclusive range. /// /// Note: returns only available blocks diff --git a/crates/storage/storage-api/src/receipts.rs b/crates/storage/storage-api/src/receipts.rs index b050ca3e248c..04eb81aad02d 100644 --- a/crates/storage/storage-api/src/receipts.rs +++ b/crates/storage/storage-api/src/receipts.rs @@ -38,6 +38,7 @@ pub trait ReceiptProvider: Send + Sync { /// so this trait can only be implemented for types that implement `BlockIdReader`. The /// `BlockIdReader` methods should be used to resolve `BlockId`s to block numbers or hashes, and /// retrieving the receipts should be done using the type's `ReceiptProvider` methods. +#[auto_impl::auto_impl(&, Arc)] pub trait ReceiptProviderIdExt: ReceiptProvider + BlockIdReader { /// Get receipt by block id fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult>> { diff --git a/crates/tasks/Cargo.toml b/crates/tasks/Cargo.toml index 63eb870fc15e..82c80c0932b8 100644 --- a/crates/tasks/Cargo.toml +++ b/crates/tasks/Cargo.toml @@ -23,6 +23,7 @@ reth-metrics.workspace = true metrics.workspace = true # misc +auto_impl.workspace = true tracing.workspace = true thiserror.workspace = true dyn-clone.workspace = true diff --git a/crates/tasks/src/lib.rs b/crates/tasks/src/lib.rs index 2d3f5f41b2b6..a0070698fcff 100644 --- a/crates/tasks/src/lib.rs +++ b/crates/tasks/src/lib.rs @@ -84,6 +84,7 @@ pub mod pool; /// ``` /// /// The [`TaskSpawner`] trait is [`DynClone`] so `Box` are also `Clone`. +#[auto_impl::auto_impl(&, Arc)] pub trait TaskSpawner: Send + Sync + Unpin + std::fmt::Debug + DynClone { /// Spawns the task onto the runtime. /// See also [`Handle::spawn`]. @@ -580,6 +581,7 @@ impl TaskSpawner for TaskExecutor { } /// `TaskSpawner` with extended behaviour +#[auto_impl::auto_impl(&, Arc)] pub trait TaskSpawnerExt: Send + Sync + Unpin + std::fmt::Debug + DynClone { /// This spawns a critical task onto the runtime. /// diff --git a/crates/tasks/src/pool.rs b/crates/tasks/src/pool.rs index dbb4e19de98d..10fedccedd1f 100644 --- a/crates/tasks/src/pool.rs +++ b/crates/tasks/src/pool.rs @@ -43,7 +43,8 @@ impl BlockingTaskGuard { /// /// This is a dedicated threadpool for blocking tasks which are CPU bound. /// RPC calls that perform blocking IO (disk lookups) are not executed on this pool but on the tokio -/// runtime's blocking pool, which performs poorly with CPU bound tasks. Once the tokio blocking +/// runtime's blocking pool, which performs poorly with CPU bound tasks (see +/// ). Once the tokio blocking /// pool is saturated it is converted into a queue, blocking tasks could then interfere with the /// queue and block other RPC calls. /// diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index 77edd6f3e541..151db24bed93 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -71,6 +71,7 @@ default = ["serde"] serde = ["dep:serde"] test-utils = ["rand", "paste", "serde"] arbitrary = ["proptest", "reth-primitives/arbitrary", "proptest-arbitrary-interop"] +taiko = ["reth-primitives/taiko"] [[bench]] name = "truncate" diff --git a/crates/transaction-pool/src/metrics.rs b/crates/transaction-pool/src/metrics.rs index 90d46854d43c..c75e3403cbd5 100644 --- a/crates/transaction-pool/src/metrics.rs +++ b/crates/transaction-pool/src/metrics.rs @@ -104,4 +104,10 @@ pub struct AllTransactionsMetrics { pub(crate) all_transactions_by_id: Gauge, /// Number of all transactions by all senders in the pool pub(crate) all_transactions_by_all_senders: Gauge, + /// Number of blob transactions nonce gaps. + pub(crate) blob_transactions_nonce_gaps: Counter, + /// The current blob base fee + pub(crate) blob_base_fee: Gauge, + /// The current base fee + pub(crate) base_fee: Gauge, } diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index 48048412eba0..a51cdc44ee4c 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -982,9 +982,13 @@ impl AllTransactions { } = block_info; self.last_seen_block_number = last_seen_block_number; self.last_seen_block_hash = last_seen_block_hash; + self.pending_fees.base_fee = pending_basefee; + self.metrics.base_fee.set(pending_basefee as f64); + if let Some(pending_blob_fee) = pending_blob_fee { self.pending_fees.blob_fee = pending_blob_fee; + self.metrics.blob_base_fee.set(pending_blob_fee as f64); } } @@ -1335,11 +1339,13 @@ impl AllTransactions { if let Some(ancestor) = ancestor { let Some(ancestor_tx) = self.txs.get(&ancestor) else { // ancestor tx is missing, so we can't insert the new blob + self.metrics.blob_transactions_nonce_gaps.increment(1); return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) }) }; if ancestor_tx.state.has_nonce_gap() { // the ancestor transaction already has a nonce gap, so we can't insert the new // blob + self.metrics.blob_transactions_nonce_gaps.increment(1); return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) }) } diff --git a/crates/transaction-pool/src/test_utils/gen.rs b/crates/transaction-pool/src/test_utils/gen.rs index 2be4d8aa9a9a..4654609af3a9 100644 --- a/crates/transaction-pool/src/test_utils/gen.rs +++ b/crates/transaction-pool/src/test_utils/gen.rs @@ -171,6 +171,7 @@ impl TransactionBuilder { value: self.value, access_list: self.access_list, input: self.input, + is_anchor: false, } .into(), self.signer, diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index 72c7a4121730..0eb52e71826a 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -44,10 +44,10 @@ macro_rules! set_value { ($this:ident => $field:ident) => { let new_value = $field; match $this { - MockTransaction::Legacy { ref mut $field, .. } | - MockTransaction::Eip1559 { ref mut $field, .. } | - MockTransaction::Eip4844 { ref mut $field, .. } | - MockTransaction::Eip2930 { ref mut $field, .. } => { + MockTransaction::Legacy { ref mut $field, .. } + | MockTransaction::Eip1559 { ref mut $field, .. } + | MockTransaction::Eip4844 { ref mut $field, .. } + | MockTransaction::Eip2930 { ref mut $field, .. } => { *$field = new_value; } } @@ -58,10 +58,10 @@ macro_rules! set_value { macro_rules! get_value { ($this:tt => $field:ident) => { match $this { - MockTransaction::Legacy { $field, .. } | - MockTransaction::Eip1559 { $field, .. } | - MockTransaction::Eip4844 { $field, .. } | - MockTransaction::Eip2930 { $field, .. } => $field.clone(), + MockTransaction::Legacy { $field, .. } + | MockTransaction::Eip1559 { $field, .. } + | MockTransaction::Eip4844 { $field, .. } + | MockTransaction::Eip2930 { $field, .. } => $field.clone(), } }; } @@ -333,8 +333,8 @@ impl MockTransaction { /// Sets the priority fee for dynamic fee transactions (EIP-1559 and EIP-4844) pub fn set_priority_fee(&mut self, val: u128) -> &mut Self { - if let Self::Eip1559 { max_priority_fee_per_gas, .. } | - Self::Eip4844 { max_priority_fee_per_gas, .. } = self + if let Self::Eip1559 { max_priority_fee_per_gas, .. } + | Self::Eip4844 { max_priority_fee_per_gas, .. } = self { *max_priority_fee_per_gas = val; } @@ -350,8 +350,8 @@ impl MockTransaction { /// Gets the priority fee for dynamic fee transactions (EIP-1559 and EIP-4844) pub const fn get_priority_fee(&self) -> Option { match self { - Self::Eip1559 { max_priority_fee_per_gas, .. } | - Self::Eip4844 { max_priority_fee_per_gas, .. } => Some(*max_priority_fee_per_gas), + Self::Eip1559 { max_priority_fee_per_gas, .. } + | Self::Eip4844 { max_priority_fee_per_gas, .. } => Some(*max_priority_fee_per_gas), _ => None, } } @@ -385,9 +385,9 @@ impl MockTransaction { pub fn set_accesslist(&mut self, list: AccessList) -> &mut Self { match self { Self::Legacy { .. } => {} - Self::Eip1559 { access_list: accesslist, .. } | - Self::Eip4844 { access_list: accesslist, .. } | - Self::Eip2930 { access_list: accesslist, .. } => { + Self::Eip1559 { access_list: accesslist, .. } + | Self::Eip4844 { access_list: accesslist, .. } + | Self::Eip2930 { access_list: accesslist, .. } => { *accesslist = list; } } @@ -400,8 +400,8 @@ impl MockTransaction { Self::Legacy { gas_price, .. } | Self::Eip2930 { gas_price, .. } => { *gas_price = val; } - Self::Eip1559 { max_fee_per_gas, max_priority_fee_per_gas, .. } | - Self::Eip4844 { max_fee_per_gas, max_priority_fee_per_gas, .. } => { + Self::Eip1559 { max_fee_per_gas, max_priority_fee_per_gas, .. } + | Self::Eip4844 { max_fee_per_gas, max_priority_fee_per_gas, .. } => { *max_fee_per_gas = val; *max_priority_fee_per_gas = val; } @@ -415,8 +415,8 @@ impl MockTransaction { Self::Legacy { ref mut gas_price, .. } | Self::Eip2930 { ref mut gas_price, .. } => { *gas_price = val; } - Self::Eip1559 { ref mut max_fee_per_gas, ref mut max_priority_fee_per_gas, .. } | - Self::Eip4844 { ref mut max_fee_per_gas, ref mut max_priority_fee_per_gas, .. } => { + Self::Eip1559 { ref mut max_fee_per_gas, ref mut max_priority_fee_per_gas, .. } + | Self::Eip4844 { ref mut max_fee_per_gas, ref mut max_priority_fee_per_gas, .. } => { *max_fee_per_gas = val; *max_priority_fee_per_gas = val; } @@ -560,39 +560,39 @@ impl MockTransaction { impl PoolTransaction for MockTransaction { fn hash(&self) -> &TxHash { match self { - Self::Legacy { hash, .. } | - Self::Eip1559 { hash, .. } | - Self::Eip4844 { hash, .. } | - Self::Eip2930 { hash, .. } => hash, + Self::Legacy { hash, .. } + | Self::Eip1559 { hash, .. } + | Self::Eip4844 { hash, .. } + | Self::Eip2930 { hash, .. } => hash, } } fn sender(&self) -> Address { match self { - Self::Legacy { sender, .. } | - Self::Eip1559 { sender, .. } | - Self::Eip4844 { sender, .. } | - Self::Eip2930 { sender, .. } => *sender, + Self::Legacy { sender, .. } + | Self::Eip1559 { sender, .. } + | Self::Eip4844 { sender, .. } + | Self::Eip2930 { sender, .. } => *sender, } } fn nonce(&self) -> u64 { match self { - Self::Legacy { nonce, .. } | - Self::Eip1559 { nonce, .. } | - Self::Eip4844 { nonce, .. } | - Self::Eip2930 { nonce, .. } => *nonce, + Self::Legacy { nonce, .. } + | Self::Eip1559 { nonce, .. } + | Self::Eip4844 { nonce, .. } + | Self::Eip2930 { nonce, .. } => *nonce, } } fn cost(&self) -> U256 { match self { - Self::Legacy { gas_price, value, gas_limit, .. } | - Self::Eip2930 { gas_limit, gas_price, value, .. } => { + Self::Legacy { gas_price, value, gas_limit, .. } + | Self::Eip2930 { gas_limit, gas_price, value, .. } => { U256::from(*gas_limit) * U256::from(*gas_price) + *value } - Self::Eip1559 { max_fee_per_gas, value, gas_limit, .. } | - Self::Eip4844 { max_fee_per_gas, value, gas_limit, .. } => { + Self::Eip1559 { max_fee_per_gas, value, gas_limit, .. } + | Self::Eip4844 { max_fee_per_gas, value, gas_limit, .. } => { U256::from(*gas_limit) * U256::from(*max_fee_per_gas) + *value } } @@ -614,17 +614,17 @@ impl PoolTransaction for MockTransaction { fn access_list(&self) -> Option<&AccessList> { match self { Self::Legacy { .. } => None, - Self::Eip1559 { access_list: accesslist, .. } | - Self::Eip4844 { access_list: accesslist, .. } | - Self::Eip2930 { access_list: accesslist, .. } => Some(accesslist), + Self::Eip1559 { access_list: accesslist, .. } + | Self::Eip4844 { access_list: accesslist, .. } + | Self::Eip2930 { access_list: accesslist, .. } => Some(accesslist), } } fn max_priority_fee_per_gas(&self) -> Option { match self { Self::Legacy { .. } | Self::Eip2930 { .. } => None, - Self::Eip1559 { max_priority_fee_per_gas, .. } | - Self::Eip4844 { max_priority_fee_per_gas, .. } => Some(*max_priority_fee_per_gas), + Self::Eip1559 { max_priority_fee_per_gas, .. } + | Self::Eip4844 { max_priority_fee_per_gas, .. } => Some(*max_priority_fee_per_gas), } } @@ -645,7 +645,7 @@ impl PoolTransaction for MockTransaction { // If the maximum fee per gas is less than the base fee, return None if max_fee_per_gas < base_fee { - return None + return None; } // Calculate the fee by subtracting the base fee from the maximum fee per gas @@ -654,7 +654,7 @@ impl PoolTransaction for MockTransaction { // If the maximum priority fee per gas is available, return the minimum of fee and priority // fee if let Some(priority_fee) = self.max_priority_fee_per_gas() { - return Some(fee.min(priority_fee)) + return Some(fee.min(priority_fee)); } // Otherwise, return the calculated fee @@ -665,8 +665,8 @@ impl PoolTransaction for MockTransaction { fn priority_fee_or_price(&self) -> u128 { match self { Self::Legacy { gas_price, .. } | Self::Eip2930 { gas_price, .. } => *gas_price, - Self::Eip1559 { max_priority_fee_per_gas, .. } | - Self::Eip4844 { max_priority_fee_per_gas, .. } => *max_priority_fee_per_gas, + Self::Eip1559 { max_priority_fee_per_gas, .. } + | Self::Eip4844 { max_priority_fee_per_gas, .. } => *max_priority_fee_per_gas, } } @@ -682,19 +682,19 @@ impl PoolTransaction for MockTransaction { fn input(&self) -> &[u8] { match self { Self::Legacy { .. } => &[], - Self::Eip1559 { input, .. } | - Self::Eip4844 { input, .. } | - Self::Eip2930 { input, .. } => input, + Self::Eip1559 { input, .. } + | Self::Eip4844 { input, .. } + | Self::Eip2930 { input, .. } => input, } } /// Returns the size of the transaction. fn size(&self) -> usize { match self { - Self::Legacy { size, .. } | - Self::Eip1559 { size, .. } | - Self::Eip4844 { size, .. } | - Self::Eip2930 { size, .. } => *size, + Self::Legacy { size, .. } + | Self::Eip1559 { size, .. } + | Self::Eip4844 { size, .. } + | Self::Eip2930 { size, .. } => *size, } } @@ -717,9 +717,9 @@ impl PoolTransaction for MockTransaction { fn chain_id(&self) -> Option { match self { Self::Legacy { chain_id, .. } => *chain_id, - Self::Eip1559 { chain_id, .. } | - Self::Eip4844 { chain_id, .. } | - Self::Eip2930 { chain_id, .. } => Some(*chain_id), + Self::Eip1559 { chain_id, .. } + | Self::Eip4844 { chain_id, .. } + | Self::Eip2930 { chain_id, .. } => Some(*chain_id), } } } @@ -816,6 +816,7 @@ impl TryFromRecoveredTransaction for MockTransaction { value, input, access_list, + is_anchor: false, }) => Ok(Self::Eip1559 { chain_id, hash, @@ -948,6 +949,7 @@ impl From for Transaction { value, access_list, input, + is_anchor: false, }), MockTransaction::Eip4844 { chain_id, diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 41d57e94165e..e43c45e17e82 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -39,7 +39,7 @@ pub type PeerId = reth_primitives::B512; /// /// Note: This requires `Clone` for convenience, since it is assumed that this will be implemented /// for a wrapped `Arc` type, see also [`Pool`](crate::Pool). -#[auto_impl::auto_impl(Arc)] +#[auto_impl::auto_impl(&, Arc)] pub trait TransactionPool: Send + Sync + Clone { /// The transaction type of the pool type Transaction: PoolTransaction; @@ -388,7 +388,7 @@ pub trait TransactionPool: Send + Sync + Clone { } /// Extension for [TransactionPool] trait that allows to set the current block info. -#[auto_impl::auto_impl(Arc)] +#[auto_impl::auto_impl(&, Arc)] pub trait TransactionPoolExt: TransactionPool { /// Sets the current block info for the pool. fn set_block_info(&self, info: BlockInfo); diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 79a93cf2e2a7..36413709f838 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -9,7 +9,7 @@ use crate::{ EthBlobTransactionSidecar, EthPoolTransaction, LocalTransactionConfig, PoolTransaction, TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator, }; -use reth_chainspec::ChainSpec; +use reth_chainspec::{ChainSpec, EthereumHardforks}; use reth_primitives::{ constants::{eip4844::MAX_BLOBS_PER_BLOCK, ETHEREUM_BLOCK_GAS_LIMIT}, Address, GotExpected, InvalidTransactionError, SealedBlock, TxKind, EIP1559_TX_TYPE_ID, diff --git a/crates/trie/common/src/lib.rs b/crates/trie/common/src/lib.rs index bc3749e6f936..f845c9ca5cd6 100644 --- a/crates/trie/common/src/lib.rs +++ b/crates/trie/common/src/lib.rs @@ -6,8 +6,6 @@ issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" )] #![cfg_attr(not(test), warn(unused_crate_dependencies))] -// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged -#![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] /// The implementation of hash builder. diff --git a/crates/trie/trie/src/forward_cursor.rs b/crates/trie/trie/src/forward_cursor.rs new file mode 100644 index 000000000000..1f14a462b1ef --- /dev/null +++ b/crates/trie/trie/src/forward_cursor.rs @@ -0,0 +1,51 @@ +/// The implementation of forward-only in memory cursor over the entries. +/// The cursor operates under the assumption that the supplied collection is pre-sorted. +#[derive(Debug)] +pub struct ForwardInMemoryCursor<'a, K, V> { + /// The reference to the pre-sorted collection of entries. + entries: &'a Vec<(K, V)>, + /// The index where cursor is currently positioned. + index: usize, +} + +impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> { + /// Create new forward cursor positioned at the beginning of the collection. + /// The cursor expects all of the entries have been sorted in advance. + pub const fn new(entries: &'a Vec<(K, V)>) -> Self { + Self { entries, index: 0 } + } + + /// Returns `true` if the cursor is empty, regardless of its position. + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } +} + +impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> +where + K: PartialOrd + Copy, + V: Copy, +{ + /// Advances the cursor forward while `comparator` returns `true` or until the collection is + /// exhausted. Returns the first entry for which `comparator` returns `false` or `None`. + fn advance_while_false(&mut self, comparator: impl Fn(&K) -> bool) -> Option<(K, V)> { + let mut entry = self.entries.get(self.index); + while entry.map_or(false, |entry| comparator(&entry.0)) { + self.index += 1; + entry = self.entries.get(self.index); + } + entry.copied() + } + + /// Returns the first entry from the current cursor position that's greater or equal to the + /// provided key. This method advances the cursor forward. + pub fn seek(&mut self, key: &K) -> Option<(K, V)> { + self.advance_while_false(|k| k < key) + } + + /// Returns the first entry from the current cursor position that's greater than the provided + /// key. This method advances the cursor forward. + pub fn first_after(&mut self, key: &K) -> Option<(K, V)> { + self.advance_while_false(|k| k <= key) + } +} diff --git a/crates/trie/trie/src/hashed_cursor/post_state.rs b/crates/trie/trie/src/hashed_cursor/post_state.rs index 41b051b2a7a7..ac262f3d44fc 100644 --- a/crates/trie/trie/src/hashed_cursor/post_state.rs +++ b/crates/trie/trie/src/hashed_cursor/post_state.rs @@ -1,6 +1,11 @@ use super::{HashedCursor, HashedCursorFactory, HashedStorageCursor}; -use crate::state::HashedPostStateSorted; +use crate::{ + forward_cursor::ForwardInMemoryCursor, HashedAccountsSorted, HashedPostStateSorted, + HashedStorageSorted, +}; +use reth_db::DatabaseError; use reth_primitives::{Account, B256, U256}; +use std::collections::HashSet; /// The hashed cursor factory for the post state. #[derive(Debug, Clone)] @@ -20,39 +25,44 @@ impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorF type AccountCursor = HashedPostStateAccountCursor<'a, CF::AccountCursor>; type StorageCursor = HashedPostStateStorageCursor<'a, CF::StorageCursor>; - fn hashed_account_cursor(&self) -> Result { + fn hashed_account_cursor(&self) -> Result { let cursor = self.cursor_factory.hashed_account_cursor()?; - Ok(HashedPostStateAccountCursor::new(cursor, self.post_state)) + Ok(HashedPostStateAccountCursor::new(cursor, &self.post_state.accounts)) } fn hashed_storage_cursor( &self, hashed_address: B256, - ) -> Result { + ) -> Result { let cursor = self.cursor_factory.hashed_storage_cursor(hashed_address)?; - Ok(HashedPostStateStorageCursor::new(cursor, self.post_state, hashed_address)) + Ok(HashedPostStateStorageCursor::new(cursor, self.post_state.storages.get(&hashed_address))) } } /// The cursor to iterate over post state hashed accounts and corresponding database entries. /// It will always give precedence to the data from the hashed post state. -#[derive(Debug, Clone)] -pub struct HashedPostStateAccountCursor<'b, C> { +#[derive(Debug)] +pub struct HashedPostStateAccountCursor<'a, C> { /// The database cursor. cursor: C, - /// The reference to the in-memory [`HashedPostStateSorted`]. - post_state: &'b HashedPostStateSorted, - /// The post state account index where the cursor is currently at. - post_state_account_index: usize, + /// Forward-only in-memory cursor over accounts. + post_state_cursor: ForwardInMemoryCursor<'a, B256, Account>, + /// Reference to the collection of account keys that were destroyed. + destroyed_accounts: &'a HashSet, /// The last hashed account that was returned by the cursor. /// De facto, this is a current cursor position. last_account: Option, } -impl<'b, C> HashedPostStateAccountCursor<'b, C> { +impl<'a, C> HashedPostStateAccountCursor<'a, C> +where + C: HashedCursor, +{ /// Create new instance of [`HashedPostStateAccountCursor`]. - pub const fn new(cursor: C, post_state: &'b HashedPostStateSorted) -> Self { - Self { cursor, post_state, last_account: None, post_state_account_index: 0 } + pub const fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self { + let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts); + let destroyed_accounts = &post_state_accounts.destroyed_accounts; + Self { cursor, post_state_cursor, destroyed_accounts, last_account: None } } /// Returns `true` if the account has been destroyed. @@ -61,34 +71,67 @@ impl<'b, C> HashedPostStateAccountCursor<'b, C> { /// This function only checks the post state, not the database, because the latter does not /// store destroyed accounts. fn is_account_cleared(&self, account: &B256) -> bool { - self.post_state.destroyed_accounts.contains(account) + self.destroyed_accounts.contains(account) + } + + fn seek_inner(&mut self, key: B256) -> Result, DatabaseError> { + // Take the next account from the post state with the key greater than or equal to the + // sought key. + let post_state_entry = self.post_state_cursor.seek(&key); + + // It's an exact match, return the account from post state without looking up in the + // database. + if post_state_entry.map_or(false, |entry| entry.0 == key) { + return Ok(post_state_entry) + } + + // It's not an exact match, reposition to the first greater or equal account that wasn't + // cleared. + let mut db_entry = self.cursor.seek(key)?; + while db_entry.as_ref().map_or(false, |(address, _)| self.is_account_cleared(address)) { + db_entry = self.cursor.next()?; + } + + // Compare two entries and return the lowest. + Ok(Self::compare_entries(post_state_entry, db_entry)) + } + + fn next_inner(&mut self, last_account: B256) -> Result, DatabaseError> { + // Take the next account from the post state with the key greater than the last sought key. + let post_state_entry = self.post_state_cursor.first_after(&last_account); + + // If post state was given precedence or account was cleared, move the cursor forward. + let mut db_entry = self.cursor.seek(last_account)?; + while db_entry.as_ref().map_or(false, |(address, _)| { + address <= &last_account || self.is_account_cleared(address) + }) { + db_entry = self.cursor.next()?; + } + + // Compare two entries and return the lowest. + Ok(Self::compare_entries(post_state_entry, db_entry)) } /// Return the account with the lowest hashed account key. /// /// Given the next post state and database entries, return the smallest of the two. /// If the account keys are the same, the post state entry is given precedence. - fn next_account( - post_state_item: Option<&(B256, Account)>, + fn compare_entries( + post_state_item: Option<(B256, Account)>, db_item: Option<(B256, Account)>, ) -> Option<(B256, Account)> { - match (post_state_item, db_item) { + if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) { // If both are not empty, return the smallest of the two // Post state is given precedence if keys are equal - (Some((post_state_address, post_state_account)), Some((db_address, db_account))) => { - if post_state_address <= &db_address { - Some((*post_state_address, *post_state_account)) - } else { - Some((db_address, db_account)) - } - } + Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry }) + } else { // Return either non-empty entry - _ => post_state_item.copied().or(db_item), + db_item.or(post_state_item) } } } -impl<'b, C> HashedCursor for HashedPostStateAccountCursor<'b, C> +impl<'a, C> HashedCursor for HashedPostStateAccountCursor<'a, C> where C: HashedCursor, { @@ -102,41 +145,11 @@ where /// /// The returned account key is memoized and the cursor remains positioned at that key until /// [`HashedCursor::seek`] or [`HashedCursor::next`] are called. - fn seek(&mut self, key: B256) -> Result, reth_db::DatabaseError> { - self.last_account = None; - - // Take the next account from the post state with the key greater than or equal to the - // sought key. - let mut post_state_entry = self.post_state.accounts.get(self.post_state_account_index); - while post_state_entry.map(|(k, _)| k < &key).unwrap_or_default() { - self.post_state_account_index += 1; - post_state_entry = self.post_state.accounts.get(self.post_state_account_index); - } - - // It's an exact match, return the account from post state without looking up in the - // database. - if let Some((address, account)) = post_state_entry { - if address == &key { - self.last_account = Some(*address); - return Ok(Some((*address, *account))) - } - } - - // It's not an exact match, reposition to the first greater or equal account that wasn't - // cleared. - let mut db_entry = self.cursor.seek(key)?; - while db_entry - .as_ref() - .map(|(address, _)| self.is_account_cleared(address)) - .unwrap_or_default() - { - db_entry = self.cursor.next()?; - } - - // Compare two entries and return the lowest. - let result = Self::next_account(post_state_entry, db_entry); - self.last_account = result.as_ref().map(|(address, _)| *address); - Ok(result) + fn seek(&mut self, key: B256) -> Result, DatabaseError> { + // Find the closes account. + let entry = self.seek_inner(key)?; + self.last_account = entry.as_ref().map(|entry| entry.0); + Ok(entry) } /// Retrieve the next entry from the cursor. @@ -146,208 +159,151 @@ where /// /// NOTE: This function will not return any entry unless [`HashedCursor::seek`] has been /// called. - fn next(&mut self) -> Result, reth_db::DatabaseError> { - let last_account = match self.last_account.as_ref() { - Some(account) => account, - None => return Ok(None), // no previous entry was found + fn next(&mut self) -> Result, DatabaseError> { + let next = match self.last_account { + Some(account) => { + let entry = self.next_inner(account)?; + self.last_account = entry.as_ref().map(|entry| entry.0); + entry + } + // no previous entry was found + None => None, }; - - // If post state was given precedence, move the cursor forward. - let mut db_entry = self.cursor.seek(*last_account)?; - while db_entry - .as_ref() - .map(|(address, _)| address <= last_account || self.is_account_cleared(address)) - .unwrap_or_default() - { - db_entry = self.cursor.next()?; - } - - // Take the next account from the post state with the key greater than the last sought key. - let mut post_state_entry = self.post_state.accounts.get(self.post_state_account_index); - while post_state_entry.map(|(k, _)| k <= last_account).unwrap_or_default() { - self.post_state_account_index += 1; - post_state_entry = self.post_state.accounts.get(self.post_state_account_index); - } - - // Compare two entries and return the lowest. - let result = Self::next_account(post_state_entry, db_entry); - self.last_account = result.as_ref().map(|(address, _)| *address); - Ok(result) + Ok(next) } } /// The cursor to iterate over post state hashed storages and corresponding database entries. /// It will always give precedence to the data from the post state. -#[derive(Debug, Clone)] -pub struct HashedPostStateStorageCursor<'b, C> { +#[derive(Debug)] +pub struct HashedPostStateStorageCursor<'a, C> { /// The database cursor. cursor: C, - /// The reference to the post state. - post_state: &'b HashedPostStateSorted, - /// The current hashed account key. - hashed_address: B256, - /// The post state index where the cursor is currently at. - post_state_storage_index: usize, + /// Forward-only in-memory cursor over non zero-valued account storage slots. + post_state_cursor: Option>, + /// Reference to the collection of storage slot keys that were cleared. + cleared_slots: Option<&'a HashSet>, + /// Flag indicating whether database storage was wiped. + storage_wiped: bool, /// The last slot that has been returned by the cursor. /// De facto, this is the cursor's position for the given account key. last_slot: Option, } -impl<'b, C> HashedPostStateStorageCursor<'b, C> { +impl<'a, C> HashedPostStateStorageCursor<'a, C> +where + C: HashedStorageCursor, +{ /// Create new instance of [`HashedPostStateStorageCursor`] for the given hashed address. - pub const fn new( - cursor: C, - post_state: &'b HashedPostStateSorted, - hashed_address: B256, - ) -> Self { - Self { cursor, post_state, hashed_address, last_slot: None, post_state_storage_index: 0 } - } - - /// Returns `true` if the storage for the given - /// The database is not checked since it already has no wiped storage entries. - fn is_db_storage_wiped(&self) -> bool { - match self.post_state.storages.get(&self.hashed_address) { - Some(storage) => storage.wiped, - None => false, - } + pub fn new(cursor: C, post_state_storage: Option<&'a HashedStorageSorted>) -> Self { + let post_state_cursor = + post_state_storage.map(|s| ForwardInMemoryCursor::new(&s.non_zero_valued_slots)); + let cleared_slots = post_state_storage.map(|s| &s.zero_valued_slots); + let storage_wiped = post_state_storage.map_or(false, |s| s.wiped); + Self { cursor, post_state_cursor, cleared_slots, storage_wiped, last_slot: None } } /// Check if the slot was zeroed out in the post state. /// The database is not checked since it already has no zero-valued slots. fn is_slot_zero_valued(&self, slot: &B256) -> bool { - self.post_state - .storages - .get(&self.hashed_address) - .map(|storage| storage.zero_valued_slots.contains(slot)) - .unwrap_or_default() + self.cleared_slots.map_or(false, |s| s.contains(slot)) + } + + /// Find the storage entry in post state or database that's greater or equal to provided subkey. + fn seek_inner(&mut self, subkey: B256) -> Result, DatabaseError> { + // Attempt to find the account's storage in post state. + let post_state_entry = self.post_state_cursor.as_mut().and_then(|c| c.seek(&subkey)); + + // If database storage was wiped or it's an exact match, + // return the storage slot from post state without looking up in the database. + if self.storage_wiped || post_state_entry.map_or(false, |entry| entry.0 == subkey) { + return Ok(post_state_entry) + } + + // It's not an exact match and storage was not wiped, + // reposition to the first greater or equal account. + let mut db_entry = self.cursor.seek(subkey)?; + while db_entry.as_ref().map_or(false, |entry| self.is_slot_zero_valued(&entry.0)) { + db_entry = self.cursor.next()?; + } + + // Compare two entries and return the lowest. + Ok(Self::compare_entries(post_state_entry, db_entry)) + } + + /// Find the storage entry that is right after current cursor position. + fn next_inner(&mut self, last_slot: B256) -> Result, DatabaseError> { + // Attempt to find the account's storage in post state. + let post_state_entry = + self.post_state_cursor.as_mut().and_then(|c| c.first_after(&last_slot)); + + // Return post state entry immediately if database was wiped. + if self.storage_wiped { + return Ok(post_state_entry) + } + + // If post state was given precedence, move the cursor forward. + // If the entry was already returned or is zero-valued, move to the next. + let mut db_entry = self.cursor.seek(last_slot)?; + while db_entry + .as_ref() + .map_or(false, |entry| entry.0 == last_slot || self.is_slot_zero_valued(&entry.0)) + { + db_entry = self.cursor.next()?; + } + + // Compare two entries and return the lowest. + Ok(Self::compare_entries(post_state_entry, db_entry)) } /// Return the storage entry with the lowest hashed storage key (hashed slot). /// /// Given the next post state and database entries, return the smallest of the two. /// If the storage keys are the same, the post state entry is given precedence. - fn next_slot( - post_state_item: Option<&(B256, U256)>, + fn compare_entries( + post_state_item: Option<(B256, U256)>, db_item: Option<(B256, U256)>, ) -> Option<(B256, U256)> { - match (post_state_item, db_item) { + if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) { // If both are not empty, return the smallest of the two // Post state is given precedence if keys are equal - (Some((post_state_slot, post_state_value)), Some((db_slot, db_value))) => { - if post_state_slot <= &db_slot { - Some((*post_state_slot, *post_state_value)) - } else { - Some((db_slot, db_value)) - } - } + Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry }) + } else { // Return either non-empty entry - _ => db_item.or_else(|| post_state_item.copied()), + db_item.or(post_state_item) } } } -impl<'b, C> HashedCursor for HashedPostStateStorageCursor<'b, C> +impl<'a, C> HashedCursor for HashedPostStateStorageCursor<'a, C> where C: HashedStorageCursor, { type Value = U256; /// Seek the next account storage entry for a given hashed key pair. - fn seek( - &mut self, - subkey: B256, - ) -> Result, reth_db::DatabaseError> { - // Attempt to find the account's storage in post state. - let mut post_state_entry = None; - if let Some(storage) = self.post_state.storages.get(&self.hashed_address) { - post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index); - - while post_state_entry.map(|(slot, _)| slot < &subkey).unwrap_or_default() { - self.post_state_storage_index += 1; - post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index); - } - } - - // It's an exact match, return the storage slot from post state without looking up in - // the database. - if let Some((slot, value)) = post_state_entry { - if slot == &subkey { - self.last_slot = Some(*slot); - return Ok(Some((*slot, *value))) - } - } - - // It's not an exact match, reposition to the first greater or equal account. - let db_entry = if self.is_db_storage_wiped() { - None - } else { - let mut db_entry = self.cursor.seek(subkey)?; - - while db_entry - .as_ref() - .map(|entry| self.is_slot_zero_valued(&entry.0)) - .unwrap_or_default() - { - db_entry = self.cursor.next()?; - } - - db_entry - }; - - // Compare two entries and return the lowest. - let result = Self::next_slot(post_state_entry, db_entry); - self.last_slot = result.as_ref().map(|entry| entry.0); - Ok(result) + fn seek(&mut self, subkey: B256) -> Result, DatabaseError> { + let entry = self.seek_inner(subkey)?; + self.last_slot = entry.as_ref().map(|entry| entry.0); + Ok(entry) } /// Return the next account storage entry for the current account key. - /// - /// # Panics - /// - /// If the account key is not set. [`HashedCursor::seek`] must be called first in order to - /// position the cursor. - fn next(&mut self) -> Result, reth_db::DatabaseError> { - let last_slot = match self.last_slot.as_ref() { - Some(slot) => slot, - None => return Ok(None), // no previous entry was found - }; - - let db_entry = if self.is_db_storage_wiped() { - None - } else { - // If post state was given precedence, move the cursor forward. - let mut db_entry = self.cursor.seek(*last_slot)?; - - // If the entry was already returned or is zero-values, move to the next. - while db_entry - .as_ref() - .map(|entry| &entry.0 == last_slot || self.is_slot_zero_valued(&entry.0)) - .unwrap_or_default() - { - db_entry = self.cursor.next()?; + fn next(&mut self) -> Result, DatabaseError> { + let next = match self.last_slot { + Some(last_slot) => { + let entry = self.next_inner(last_slot)?; + self.last_slot = entry.as_ref().map(|entry| entry.0); + entry } - - db_entry + // no previous entry was found + None => None, }; - - // Attempt to find the account's storage in post state. - let mut post_state_entry = None; - if let Some(storage) = self.post_state.storages.get(&self.hashed_address) { - post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index); - while post_state_entry.map(|(slot, _)| slot <= last_slot).unwrap_or_default() { - self.post_state_storage_index += 1; - post_state_entry = storage.non_zero_valued_slots.get(self.post_state_storage_index); - } - } - - // Compare two entries and return the lowest. - let result = Self::next_slot(post_state_entry, db_entry); - self.last_slot = result.as_ref().map(|entry| entry.0); - Ok(result) + Ok(next) } } -impl<'b, C> HashedStorageCursor for HashedPostStateStorageCursor<'b, C> +impl<'a, C> HashedStorageCursor for HashedPostStateStorageCursor<'a, C> where C: HashedStorageCursor, { @@ -355,13 +311,13 @@ where /// /// This function should be called before attempting to call [`HashedCursor::seek`] or /// [`HashedCursor::next`]. - fn is_storage_empty(&mut self) -> Result { - let is_empty = match self.post_state.storages.get(&self.hashed_address) { - Some(storage) => { + fn is_storage_empty(&mut self) -> Result { + let is_empty = match &self.post_state_cursor { + Some(cursor) => { // If the storage has been wiped at any point - storage.wiped && + self.storage_wiped && // and the current storage does not contain any non-zero values - storage.non_zero_valued_slots.is_empty() + cursor.is_empty() } None => self.cursor.is_storage_empty()?, }; diff --git a/crates/trie/trie/src/lib.rs b/crates/trie/trie/src/lib.rs index eea65a7b34d8..07af0775705a 100644 --- a/crates/trie/trie/src/lib.rs +++ b/crates/trie/trie/src/lib.rs @@ -17,6 +17,9 @@ /// The container indicates when the trie has been modified. pub mod prefix_set; +/// The implementation of forward-only in-memory cursor. +pub mod forward_cursor; + /// The cursor implementations for navigating account and storage tries. pub mod trie_cursor; diff --git a/crates/trie/trie/src/state.rs b/crates/trie/trie/src/state.rs index 821dcc971b62..de7ecc236dbe 100644 --- a/crates/trie/trie/src/state.rs +++ b/crates/trie/trie/src/state.rs @@ -149,16 +149,17 @@ impl HashedPostState { /// Converts hashed post state into [`HashedPostStateSorted`]. pub fn into_sorted(self) -> HashedPostStateSorted { - let mut accounts = Vec::new(); + let mut updated_accounts = Vec::new(); let mut destroyed_accounts = HashSet::default(); for (hashed_address, info) in self.accounts { if let Some(info) = info { - accounts.push((hashed_address, info)); + updated_accounts.push((hashed_address, info)); } else { destroyed_accounts.insert(hashed_address); } } - accounts.sort_unstable_by_key(|(address, _)| *address); + updated_accounts.sort_unstable_by_key(|(address, _)| *address); + let accounts = HashedAccountsSorted { accounts: updated_accounts, destroyed_accounts }; let storages = self .storages @@ -166,7 +167,7 @@ impl HashedPostState { .map(|(hashed_address, storage)| (hashed_address, storage.into_sorted())) .collect(); - HashedPostStateSorted { accounts, destroyed_accounts, storages } + HashedPostStateSorted { accounts, storages } } /// Construct [`TriePrefixSets`] from hashed post state. @@ -309,12 +310,19 @@ impl HashedStorage { /// Sorted hashed post state optimized for iterating during state trie calculation. #[derive(PartialEq, Eq, Clone, Debug)] pub struct HashedPostStateSorted { + /// Updated state of accounts. + pub(crate) accounts: HashedAccountsSorted, + /// Map of hashed addresses to hashed storage. + pub(crate) storages: HashMap, +} + +/// Sorted account state optimized for iterating during state trie calculation. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct HashedAccountsSorted { /// Sorted collection of hashed addresses and their account info. pub(crate) accounts: Vec<(B256, Account)>, /// Set of destroyed account keys. pub(crate) destroyed_accounts: HashSet, - /// Map of hashed addresses to hashed storage. - pub(crate) storages: HashMap, } /// Sorted hashed storage optimized for iterating during state trie calculation. diff --git a/crates/trie/trie/src/trie.rs b/crates/trie/trie/src/trie.rs index 25ae616584d7..0ae43cdf849a 100644 --- a/crates/trie/trie/src/trie.rs +++ b/crates/trie/trie/src/trie.rs @@ -491,7 +491,7 @@ where } let mut tracker = TrieTracker::default(); - let trie_cursor = self.trie_cursor_factory.storage_tries_cursor(self.hashed_address)?; + let trie_cursor = self.trie_cursor_factory.storage_trie_cursor(self.hashed_address)?; let walker = TrieWalker::new(trie_cursor, self.prefix_set).with_updates(retain_updates); let mut hash_builder = HashBuilder::default().with_updates(retain_updates); @@ -546,9 +546,11 @@ where mod tests { use super::*; use crate::{ + hashed_cursor::HashedPostStateCursorFactory, prefix_set::PrefixSetMut, test_utils::{state_root, state_root_prehashed, storage_root, storage_root_prehashed}, - BranchNodeCompact, TrieMask, + trie_cursor::InMemoryTrieCursorFactory, + BranchNodeCompact, HashedPostState, HashedStorage, TrieMask, }; use proptest::{prelude::ProptestConfig, proptest}; use proptest_arbitrary_interop::arb; @@ -562,6 +564,7 @@ mod tests { use reth_trie_common::triehash::KeccakHasher; use std::{ collections::{BTreeMap, HashMap}, + iter, ops::Mul, str::FromStr, sync::Arc, @@ -1205,7 +1208,7 @@ mod tests { .iter() .filter_map(|entry| match entry { (TrieKey::AccountNode(nibbles), TrieOp::Update(node)) => { - Some((nibbles.0.clone(), node.clone())) + Some((nibbles.clone(), node.clone())) } _ => None, }) @@ -1292,7 +1295,7 @@ mod tests { .iter() .filter_map(|entry| match entry { (TrieKey::StorageNode(_, nibbles), TrieOp::Update(node)) => { - Some((nibbles.0.clone(), node.clone())) + Some((nibbles.clone(), node.clone())) } _ => None, }) @@ -1369,4 +1372,126 @@ mod tests { assert_eq!(node.root_hash, None); assert_eq!(node.hashes.len(), 1); } + + #[test] + fn trie_updates_across_multiple_iterations() { + let address = Address::ZERO; + let hashed_address = keccak256(address); + + let factory = create_test_provider_factory(); + + let mut hashed_storage = BTreeMap::default(); + let mut post_state = HashedPostState::default(); + + // Block #1 + // Update specific storage slots + let mut modified_storage = BTreeMap::default(); + + // 0x0f.. + let modified_key_prefix = Nibbles::from_nibbles( + [0x0, 0xf].into_iter().chain(iter::repeat(0).take(62)).collect::>(), + ); + + // 0x0faa0.. + let mut modified_entry1 = modified_key_prefix.clone(); + modified_entry1.set_at(2, 0xa); + modified_entry1.set_at(3, 0xa); + + // 0x0faaa.. + let mut modified_entry2 = modified_key_prefix.clone(); + modified_entry2.set_at(2, 0xa); + modified_entry2.set_at(3, 0xa); + modified_entry2.set_at(4, 0xa); + + // 0x0fab0.. + let mut modified_entry3 = modified_key_prefix.clone(); + modified_entry3.set_at(2, 0xa); + modified_entry3.set_at(3, 0xb); + + // 0x0fba0.. + let mut modified_entry4 = modified_key_prefix; + modified_entry4.set_at(2, 0xb); + modified_entry4.set_at(3, 0xa); + + [modified_entry1, modified_entry2, modified_entry3.clone(), modified_entry4] + .into_iter() + .for_each(|key| { + modified_storage.insert(B256::from_slice(&key.pack()), U256::from(1)); + }); + + // Update main hashed storage. + hashed_storage.extend(modified_storage.clone()); + post_state.extend(HashedPostState::default().with_storages([( + hashed_address, + HashedStorage::from_iter(false, modified_storage.clone()), + )])); + + let (storage_root, block1_updates) = compute_storage_root( + address, + factory.provider().unwrap().tx_ref(), + &post_state, + &TrieUpdates::default(), + ); + assert_eq!(storage_root, storage_root_prehashed(hashed_storage.clone())); + + // Block #2 + // Set 0x0fab0.. hashed slot to 0 + modified_storage.insert(B256::from_slice(&modified_entry3.pack()), U256::ZERO); + + // Update main hashed storage. + hashed_storage.remove(&B256::from_slice(&modified_entry3.pack())); + post_state.extend(HashedPostState::default().with_storages([( + hashed_address, + HashedStorage::from_iter(false, modified_storage.clone()), + )])); + + let (storage_root, block2_updates) = compute_storage_root( + address, + factory.provider().unwrap().tx_ref(), + &post_state, + &block1_updates, + ); + assert_eq!(storage_root, storage_root_prehashed(hashed_storage.clone())); + + // Commit trie updates + { + let mut updates = block1_updates; + updates.extend(block2_updates); + + let provider_rw = factory.provider_rw().unwrap(); + let mut hashed_storage_cursor = + provider_rw.tx_ref().cursor_dup_write::().unwrap(); + for (hashed_slot, value) in &hashed_storage { + hashed_storage_cursor + .upsert(hashed_address, StorageEntry { key: *hashed_slot, value: *value }) + .unwrap(); + } + updates.flush(provider_rw.tx_ref()).unwrap(); + provider_rw.commit().unwrap(); + } + + // Recompute storage root for block #3 + let storage_root = + StorageRoot::from_tx(factory.provider().unwrap().tx_ref(), address).root().unwrap(); + assert_eq!(storage_root, storage_root_prehashed(hashed_storage.clone())); + } + + fn compute_storage_root( + address: Address, + tx: &TX, + post_state: &HashedPostState, + update: &TrieUpdates, + ) -> (B256, TrieUpdates) { + let mut prefix_sets = post_state.construct_prefix_sets(); + let (root, _, updates) = StorageRoot::from_tx(tx, address) + .with_hashed_cursor_factory(HashedPostStateCursorFactory::new( + tx, + &post_state.clone().into_sorted(), + )) + .with_trie_cursor_factory(InMemoryTrieCursorFactory::new(tx, &update.sorted())) + .with_prefix_set(prefix_sets.storage_prefix_sets.remove(&keccak256(address)).unwrap()) + .root_with_updates() + .unwrap(); + (root, updates) + } } diff --git a/crates/trie/trie/src/trie_cursor/database_cursors.rs b/crates/trie/trie/src/trie_cursor/database_cursors.rs index 910ae61b4648..61e43c19b12c 100644 --- a/crates/trie/trie/src/trie_cursor/database_cursors.rs +++ b/crates/trie/trie/src/trie_cursor/database_cursors.rs @@ -9,18 +9,22 @@ use reth_primitives::B256; /// Implementation of the trie cursor factory for a database transaction. impl<'a, TX: DbTx> TrieCursorFactory for &'a TX { - fn account_trie_cursor(&self) -> Result, DatabaseError> { - Ok(Box::new(DatabaseAccountTrieCursor::new(self.cursor_read::()?))) + type AccountTrieCursor = DatabaseAccountTrieCursor<::Cursor>; + type StorageTrieCursor = + DatabaseStorageTrieCursor<::DupCursor>; + + fn account_trie_cursor(&self) -> Result { + Ok(DatabaseAccountTrieCursor::new(self.cursor_read::()?)) } - fn storage_tries_cursor( + fn storage_trie_cursor( &self, hashed_address: B256, - ) -> Result, DatabaseError> { - Ok(Box::new(DatabaseStorageTrieCursor::new( + ) -> Result { + Ok(DatabaseStorageTrieCursor::new( self.cursor_dup_read::()?, hashed_address, - ))) + )) } } @@ -57,7 +61,7 @@ where /// Retrieves the current key in the cursor. fn current(&mut self) -> Result, DatabaseError> { - Ok(self.0.current()?.map(|(k, _)| TrieKey::AccountNode(k))) + Ok(self.0.current()?.map(|(k, _)| TrieKey::AccountNode(k.0))) } } @@ -106,7 +110,7 @@ where /// Retrieves the current value in the storage trie cursor. fn current(&mut self) -> Result, DatabaseError> { - Ok(self.cursor.current()?.map(|(k, v)| TrieKey::StorageNode(k, v.nibbles))) + Ok(self.cursor.current()?.map(|(k, v)| TrieKey::StorageNode(k, v.nibbles.0))) } } diff --git a/crates/trie/trie/src/trie_cursor/in_memory.rs b/crates/trie/trie/src/trie_cursor/in_memory.rs new file mode 100644 index 000000000000..5f607f314db0 --- /dev/null +++ b/crates/trie/trie/src/trie_cursor/in_memory.rs @@ -0,0 +1,186 @@ +use super::{TrieCursor, TrieCursorFactory}; +use crate::updates::{TrieKey, TrieOp, TrieUpdatesSorted}; +use reth_db::DatabaseError; +use reth_primitives::B256; +use reth_trie_common::{BranchNodeCompact, Nibbles}; + +/// The trie cursor factory for the trie updates. +#[derive(Debug, Clone)] +pub struct InMemoryTrieCursorFactory<'a, CF> { + cursor_factory: CF, + trie_updates: &'a TrieUpdatesSorted, +} + +impl<'a, CF> InMemoryTrieCursorFactory<'a, CF> { + /// Create a new trie cursor factory. + pub const fn new(cursor_factory: CF, trie_updates: &'a TrieUpdatesSorted) -> Self { + Self { cursor_factory, trie_updates } + } +} + +impl<'a, CF: TrieCursorFactory> TrieCursorFactory for InMemoryTrieCursorFactory<'a, CF> { + type AccountTrieCursor = InMemoryAccountTrieCursor<'a, CF::AccountTrieCursor>; + type StorageTrieCursor = InMemoryStorageTrieCursor<'a, CF::StorageTrieCursor>; + + fn account_trie_cursor(&self) -> Result { + let cursor = self.cursor_factory.account_trie_cursor()?; + Ok(InMemoryAccountTrieCursor::new(cursor, self.trie_updates)) + } + + fn storage_trie_cursor( + &self, + hashed_address: B256, + ) -> Result { + let cursor = self.cursor_factory.storage_trie_cursor(hashed_address)?; + Ok(InMemoryStorageTrieCursor::new(cursor, hashed_address, self.trie_updates)) + } +} + +/// The cursor to iterate over account trie updates and corresponding database entries. +/// It will always give precedence to the data from the trie updates. +#[derive(Debug)] +pub struct InMemoryAccountTrieCursor<'a, C> { + cursor: C, + trie_updates: &'a TrieUpdatesSorted, + last_key: Option, +} + +impl<'a, C> InMemoryAccountTrieCursor<'a, C> { + const fn new(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self { + Self { cursor, trie_updates, last_key: None } + } +} + +impl<'a, C: TrieCursor> TrieCursor for InMemoryAccountTrieCursor<'a, C> { + fn seek_exact( + &mut self, + key: Nibbles, + ) -> Result, DatabaseError> { + if let Some((trie_key, trie_op)) = self.trie_updates.find_account_node(&key) { + self.last_key = Some(trie_key); + match trie_op { + TrieOp::Update(node) => Ok(Some((key, node))), + TrieOp::Delete => Ok(None), + } + } else { + let result = self.cursor.seek_exact(key)?; + self.last_key = result.as_ref().map(|(k, _)| TrieKey::AccountNode(k.clone())); + Ok(result) + } + } + + fn seek( + &mut self, + key: Nibbles, + ) -> Result, DatabaseError> { + let trie_update_entry = self + .trie_updates + .trie_operations + .iter() + .find(|(k, _)| matches!(k, TrieKey::AccountNode(nibbles) if nibbles <= &key)) + .cloned(); + + if let Some((trie_key, trie_op)) = trie_update_entry { + let nibbles = match &trie_key { + TrieKey::AccountNode(nibbles) => nibbles.clone(), + _ => panic!("Invalid trie key"), + }; + self.last_key = Some(trie_key); + match trie_op { + TrieOp::Update(node) => return Ok(Some((nibbles, node))), + TrieOp::Delete => return Ok(None), + } + } + + let result = self.cursor.seek(key)?; + self.last_key = result.as_ref().map(|(k, _)| TrieKey::AccountNode(k.clone())); + Ok(result) + } + + fn current(&mut self) -> Result, DatabaseError> { + if self.last_key.is_some() { + Ok(self.last_key.clone()) + } else { + self.cursor.current() + } + } +} + +/// The cursor to iterate over storage trie updates and corresponding database entries. +/// It will always give precedence to the data from the trie updates. +#[derive(Debug)] +pub struct InMemoryStorageTrieCursor<'a, C> { + cursor: C, + trie_update_index: usize, + trie_updates: &'a TrieUpdatesSorted, + hashed_address: B256, + last_key: Option, +} + +impl<'a, C> InMemoryStorageTrieCursor<'a, C> { + const fn new(cursor: C, hashed_address: B256, trie_updates: &'a TrieUpdatesSorted) -> Self { + Self { cursor, trie_updates, trie_update_index: 0, hashed_address, last_key: None } + } +} + +impl<'a, C: TrieCursor> TrieCursor for InMemoryStorageTrieCursor<'a, C> { + fn seek_exact( + &mut self, + key: Nibbles, + ) -> Result, DatabaseError> { + if let Some((trie_key, trie_op)) = + self.trie_updates.find_storage_node(&self.hashed_address, &key) + { + self.last_key = Some(trie_key); + match trie_op { + TrieOp::Update(node) => Ok(Some((key, node))), + TrieOp::Delete => Ok(None), + } + } else { + let result = self.cursor.seek_exact(key)?; + self.last_key = + result.as_ref().map(|(k, _)| TrieKey::StorageNode(self.hashed_address, k.clone())); + Ok(result) + } + } + + fn seek( + &mut self, + key: Nibbles, + ) -> Result, DatabaseError> { + let mut trie_update_entry = self.trie_updates.trie_operations.get(self.trie_update_index); + while trie_update_entry + .filter(|(k, _)| matches!(k, TrieKey::StorageNode(address, nibbles) if address == &self.hashed_address && nibbles < &key)).is_some() + { + self.trie_update_index += 1; + trie_update_entry = self.trie_updates.trie_operations.get(self.trie_update_index); + } + + if let Some((trie_key, trie_op)) = + trie_update_entry.filter(|(k, _)| matches!(k, TrieKey::StorageNode(_, _))) + { + let nibbles = match trie_key { + TrieKey::StorageNode(_, nibbles) => nibbles.clone(), + _ => panic!("this should not happen!"), + }; + self.last_key = Some(trie_key.clone()); + match trie_op { + TrieOp::Update(node) => return Ok(Some((nibbles, node.clone()))), + TrieOp::Delete => return Ok(None), + } + } + + let result = self.cursor.seek(key)?; + self.last_key = + result.as_ref().map(|(k, _)| TrieKey::StorageNode(self.hashed_address, k.clone())); + Ok(result) + } + + fn current(&mut self) -> Result, DatabaseError> { + if self.last_key.is_some() { + Ok(self.last_key.clone()) + } else { + self.cursor.current() + } + } +} diff --git a/crates/trie/trie/src/trie_cursor/mod.rs b/crates/trie/trie/src/trie_cursor/mod.rs index aae7e773c690..a8e0a01cf093 100644 --- a/crates/trie/trie/src/trie_cursor/mod.rs +++ b/crates/trie/trie/src/trie_cursor/mod.rs @@ -1,7 +1,14 @@ use crate::{updates::TrieKey, BranchNodeCompact, Nibbles}; use reth_db::DatabaseError; use reth_primitives::B256; + +/// Database implementations of trie cursors. mod database_cursors; + +/// In-memory implementations of trie cursors. +mod in_memory; + +/// Cursor for iterating over a subtrie. mod subnode; /// Noop trie cursor implementations. @@ -9,19 +16,25 @@ pub mod noop; pub use self::{ database_cursors::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor}, + in_memory::*, subnode::CursorSubNode, }; /// Factory for creating trie cursors. pub trait TrieCursorFactory { + /// The account trie cursor type. + type AccountTrieCursor: TrieCursor; + /// The storage trie cursor type. + type StorageTrieCursor: TrieCursor; + /// Create an account trie cursor. - fn account_trie_cursor(&self) -> Result, DatabaseError>; + fn account_trie_cursor(&self) -> Result; /// Create a storage tries cursor. - fn storage_tries_cursor( + fn storage_trie_cursor( &self, hashed_address: B256, - ) -> Result, DatabaseError>; + ) -> Result; } /// A cursor for navigating a trie that works with both Tables and DupSort tables. diff --git a/crates/trie/trie/src/trie_cursor/noop.rs b/crates/trie/trie/src/trie_cursor/noop.rs index 46163180b8b9..c55bdb80f2c5 100644 --- a/crates/trie/trie/src/trie_cursor/noop.rs +++ b/crates/trie/trie/src/trie_cursor/noop.rs @@ -1,6 +1,7 @@ use super::{TrieCursor, TrieCursorFactory}; use crate::{updates::TrieKey, BranchNodeCompact, Nibbles}; use reth_db::DatabaseError; +use reth_primitives::B256; /// Noop trie cursor factory. #[derive(Default, Debug)] @@ -8,17 +9,20 @@ use reth_db::DatabaseError; pub struct NoopTrieCursorFactory; impl TrieCursorFactory for NoopTrieCursorFactory { + type AccountTrieCursor = NoopAccountTrieCursor; + type StorageTrieCursor = NoopStorageTrieCursor; + /// Generates a Noop account trie cursor. - fn account_trie_cursor(&self) -> Result, DatabaseError> { - Ok(Box::::default()) + fn account_trie_cursor(&self) -> Result { + Ok(NoopAccountTrieCursor::default()) } /// Generates a Noop storage trie cursor. - fn storage_tries_cursor( + fn storage_trie_cursor( &self, - _hashed_address: reth_primitives::B256, - ) -> Result, DatabaseError> { - Ok(Box::::default()) + _hashed_address: B256, + ) -> Result { + Ok(NoopStorageTrieCursor::default()) } } diff --git a/crates/trie/trie/src/updates.rs b/crates/trie/trie/src/updates.rs index 39628e6d5272..4ae4eb309089 100644 --- a/crates/trie/trie/src/updates.rs +++ b/crates/trie/trie/src/updates.rs @@ -16,13 +16,42 @@ use std::collections::{hash_map::IntoIter, HashMap, HashSet}; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TrieKey { /// A node in the account trie. - AccountNode(StoredNibbles), + AccountNode(Nibbles), /// A node in the storage trie. - StorageNode(B256, StoredNibblesSubKey), + StorageNode(B256, Nibbles), /// Storage trie of an account. StorageTrie(B256), } +impl TrieKey { + /// Returns reference to account node key if the key is for [`Self::AccountNode`]. + pub const fn as_account_node_key(&self) -> Option<&Nibbles> { + if let Self::AccountNode(nibbles) = &self { + Some(nibbles) + } else { + None + } + } + + /// Returns reference to storage node key if the key is for [`Self::StorageNode`]. + pub const fn as_storage_node_key(&self) -> Option<(&B256, &Nibbles)> { + if let Self::StorageNode(key, subkey) = &self { + Some((key, subkey)) + } else { + None + } + } + + /// Returns reference to storage trie key if the key is for [`Self::StorageTrie`]. + pub const fn as_storage_trie_key(&self) -> Option<&B256> { + if let Self::StorageTrie(key) = &self { + Some(key) + } else { + None + } + } +} + /// The operation to perform on the trie. #[derive(PartialEq, Eq, Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -38,6 +67,15 @@ impl TrieOp { pub const fn is_update(&self) -> bool { matches!(self, Self::Update(..)) } + + /// Returns reference to updated branch node if operation is [`Self::Update`]. + pub const fn as_update(&self) -> Option<&BranchNodeCompact> { + if let Self::Update(node) = &self { + Some(node) + } else { + None + } + } } /// The aggregation of trie updates. @@ -83,9 +121,9 @@ impl TrieUpdates { /// Extend the updates with account trie updates. pub fn extend_with_account_updates(&mut self, updates: HashMap) { self.extend( - updates.into_iter().map(|(nibbles, node)| { - (TrieKey::AccountNode(nibbles.into()), TrieOp::Update(node)) - }), + updates + .into_iter() + .map(|(nibbles, node)| (TrieKey::AccountNode(nibbles), TrieOp::Update(node))), ); } @@ -124,7 +162,7 @@ impl TrieUpdates { // Add storage node updates from hash builder. let (_, hash_builder_updates) = hash_builder.split(); self.extend(hash_builder_updates.into_iter().map(|(nibbles, node)| { - (TrieKey::StorageNode(hashed_address, nibbles.into()), TrieOp::Update(node)) + (TrieKey::StorageNode(hashed_address, nibbles), TrieOp::Update(node)) })); } @@ -141,18 +179,21 @@ impl TrieUpdates { trie_operations.sort_unstable_by(|a, b| a.0.cmp(&b.0)); for (key, operation) in trie_operations { match key { - TrieKey::AccountNode(nibbles) => match operation { - TrieOp::Delete => { - if account_trie_cursor.seek_exact(nibbles)?.is_some() { - account_trie_cursor.delete_current()?; + TrieKey::AccountNode(nibbles) => { + let nibbles = StoredNibbles(nibbles); + match operation { + TrieOp::Delete => { + if account_trie_cursor.seek_exact(nibbles)?.is_some() { + account_trie_cursor.delete_current()?; + } } - } - TrieOp::Update(node) => { - if !nibbles.0.is_empty() { - account_trie_cursor.upsert(nibbles, StoredBranchNode(node))?; + TrieOp::Update(node) => { + if !nibbles.0.is_empty() { + account_trie_cursor.upsert(nibbles, StoredBranchNode(node))?; + } } } - }, + } TrieKey::StorageTrie(hashed_address) => match operation { TrieOp::Delete => { if storage_trie_cursor.seek_exact(hashed_address)?.is_some() { @@ -163,6 +204,7 @@ impl TrieUpdates { }, TrieKey::StorageNode(hashed_address, nibbles) => { if !nibbles.is_empty() { + let nibbles = StoredNibblesSubKey(nibbles); // Delete the old entry if it exists. if storage_trie_cursor .seek_by_key_subkey(hashed_address, nibbles.clone())? @@ -184,4 +226,46 @@ impl TrieUpdates { Ok(()) } + + /// creates [`TrieUpdatesSorted`] by sorting the `trie_operations`. + pub fn sorted(&self) -> TrieUpdatesSorted { + let mut trie_operations = Vec::from_iter(self.trie_operations.clone()); + trie_operations.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + TrieUpdatesSorted { trie_operations } + } + + /// converts trie updates into [`TrieUpdatesSorted`]. + pub fn into_sorted(self) -> TrieUpdatesSorted { + let mut trie_operations = Vec::from_iter(self.trie_operations); + trie_operations.sort_unstable_by(|a, b| a.0.cmp(&b.0)); + TrieUpdatesSorted { trie_operations } + } +} + +/// The aggregation of trie updates. +#[derive(Debug, Default, Clone, PartialEq, Eq, Deref)] +pub struct TrieUpdatesSorted { + /// Sorted collection of trie operations. + pub(crate) trie_operations: Vec<(TrieKey, TrieOp)>, +} + +impl TrieUpdatesSorted { + /// Find the account node with the given nibbles. + pub fn find_account_node(&self, key: &Nibbles) -> Option<(TrieKey, TrieOp)> { + self.trie_operations + .iter() + .find(|(k, _)| matches!(k, TrieKey::AccountNode(nibbles) if nibbles == key)) + .cloned() + } + + /// Find the storage node with the given hashed address and key. + pub fn find_storage_node( + &self, + hashed_address: &B256, + key: &Nibbles, + ) -> Option<(TrieKey, TrieOp)> { + self.trie_operations.iter().find(|(k, _)| { + matches!(k, TrieKey::StorageNode(address, nibbles) if address == hashed_address && nibbles == key) + }).cloned() + } } diff --git a/deny.toml b/deny.toml index 4dff1b9ce250..431698495969 100644 --- a/deny.toml +++ b/deny.toml @@ -43,6 +43,7 @@ allow = [ "Unicode-DFS-2016", "Unlicense", "Unicode-3.0", + "Zlib", # https://github.com/briansmith/ring/issues/902 "LicenseRef-ring", # https://github.com/rustls/webpki/blob/main/LICENSE ISC Style @@ -63,7 +64,6 @@ exceptions = [ { allow = ["CC0-1.0"], name = "aurora-engine-modexp" }, # TODO: decide on MPL-2.0 handling # These dependencies are grandfathered in in https://github.com/paradigmxyz/reth/pull/6980 - { allow = ["MPL-2.0"], name = "attohttpc" }, { allow = ["MPL-2.0"], name = "option-ext" }, { allow = ["MPL-2.0"], name = "webpki-roots" }, ] diff --git a/docs/crates/discv4.md b/docs/crates/discv4.md index 5abe7c439b99..348c68e06b13 100644 --- a/docs/crates/discv4.md +++ b/docs/crates/discv4.md @@ -126,7 +126,7 @@ The `NodeRecord::from_secret_key()` takes the socket address used for discovery If the `discv4_config` supplied to the `Discovery::new()` function is `None`, the discv4 service will not be spawned. In this case, no new peers will be discovered across the network. The node will have to rely on manually added peers. However, if the `discv4_config` contains a `Some(Discv4Config)` value, then the `Discv4::bind()` function is called to bind to a new UdpSocket and create the disc_v4 service. -[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/main/crates/net/discv4/src/lib.rs#L188) +[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/530e7e8961b8f82ae2c675d16c368dd266ceba7d/crates/net/discv4/src/lib.rs#L178) ```rust ignore impl Discv4 { //--snip-- @@ -155,7 +155,7 @@ impl Discv4 { To better understand what is actually happening when the disc_v4 service is created, lets take a deeper look at the `Discv4Service::new()` function. -[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/main/crates/net/discv4/src/lib.rs#L392) +[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/530e7e8961b8f82ae2c675d16c368dd266ceba7d/crates/net/discv4/src/lib.rs#L495) ```rust ignore impl Discv4Service { /// Create a new instance for a bound [`UdpSocket`]. @@ -216,7 +216,7 @@ In Rust, the owner of a [`Future`](https://doc.rust-lang.org/std/future/trait.Fu Lets take a detailed look at how `Discv4Service::poll` works under the hood. This function has many moving parts, so we will break it up into smaller sections. -[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/main/crates/net/discv4/src/lib.rs#L1302) +[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/530e7e8961b8f82ae2c675d16c368dd266ceba7d/crates/net/discv4/src/lib.rs#L495) ```rust ignore impl Discv4Service { //--snip-- @@ -259,7 +259,7 @@ impl Discv4Service { As the function starts, a `loop` is entered and the `Discv4Service.queued_events` are evaluated to see if there are any events ready to be processed. If there is an event ready, the function immediately returns the event wrapped in `Poll::Ready()`. The `queued_events` field is a `VecDeque` where `Discv4Event` is an enum containing one of the following variants. -[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/main/crates/net/discv4/src/lib.rs#L1455) +[File: crates/net/discv4/src/lib.rs](https://github.com/paradigmxyz/reth/blob/530e7e8961b8f82ae2c675d16c368dd266ceba7d/crates/net/discv4/src/lib.rs#L1770) ```rust ignore pub enum Discv4Event { /// A `Ping` message was handled. @@ -285,7 +285,7 @@ Next, the Discv4Service handles all incoming `Discv4Command`s until there are no In Reth, once a new `NetworkState` is initialized as the node starts up and a new task is spawned to handle the network, the `poll()` function is used to advance the state of the network. -[File: crates/net/network/src/state.rs](https://github.com/paradigmxyz/reth/blob/main/crates/net/network/src/state.rs#L377) +[File: crates/net/network/src/state.rs](https://github.com/paradigmxyz/reth/blob/530e7e8961b8f82ae2c675d16c368dd266ceba7d/crates/net/network/src/state.rs#L396) ```rust ignore impl NetworkState where diff --git a/etc/grafana/dashboards/reth-mempool.json b/etc/grafana/dashboards/reth-mempool.json index 092faaccb878..90fe5ba8d2d3 100644 --- a/etc/grafana/dashboards/reth-mempool.json +++ b/etc/grafana/dashboards/reth-mempool.json @@ -1719,6 +1719,23 @@ "range": true, "refId": "C", "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "reth_transaction_pool_blob_transactions_nonce_gaps{instance=~\"$instance\"}", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Blob transactions nonce gaps", + "range": true, + "refId": "D", + "useBackend": false } ], "title": "All Transactions metrics", diff --git a/examples/README.md b/examples/README.md index c5f20f21c881..b24b7387f32d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,26 +10,27 @@ to make a PR! ## Node Builder -| Example | Description | -| -------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -| [Additional RPC namespace](./node-custom-rpc) | Illustrates how to add custom CLI parameters and set up a custom RPC namespace | -| [Custom event hooks](./node-event-hooks) | Illustrates how to hook to various node lifecycle events | -| [Custom dev node](./custom-dev-node) | Illustrates how to run a custom dev node programmatically and submit a transaction to it via RPC | -| [Custom EVM](./custom-evm) | Illustrates how to implement a node with a custom EVM | -| [Custom Stateful Precompile](./stateful-precompile)| Illustrates how to implement a node with a stateful precompile | -| [Custom inspector](./custom-inspector) | Illustrates how to use a custom EVM inspector to trace new transactions | -| [Custom engine types](./custom-engine-types) | Illustrates how to create a node with custom engine types | -| [Custom node components](./custom-node-components) | Illustrates how to configure custom node components | -| [Custom payload builder](./custom-payload-builder) | Illustrates how to use a custom payload builder | +| Example | Description | +| --------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| [Additional RPC namespace](./node-custom-rpc) | Illustrates how to add custom CLI parameters and set up a custom RPC namespace | +| [Custom event hooks](./node-event-hooks) | Illustrates how to hook to various node lifecycle events | +| [Custom dev node](./custom-dev-node) | Illustrates how to run a custom dev node programmatically and submit a transaction to it via RPC | +| [Custom EVM](./custom-evm) | Illustrates how to implement a node with a custom EVM | +| [Custom Stateful Precompile](./stateful-precompile) | Illustrates how to implement a node with a stateful precompile | +| [Custom inspector](./custom-inspector) | Illustrates how to use a custom EVM inspector to trace new transactions | +| [Custom engine types](./custom-engine-types) | Illustrates how to create a node with custom engine types | +| [Custom node components](./custom-node-components) | Illustrates how to configure custom node components | +| [Custom payload builder](./custom-payload-builder) | Illustrates how to use a custom payload builder | ## ExEx -| Example | Description | -|-------------------------------------------|-----------------------------------------------------------------------------------| -| [Minimal ExEx](./exex/minimal) | Illustrates how to build a simple ExEx | -| [OP Bridge ExEx](./exex/op-bridge) | Illustrates an ExEx that decodes Optimism deposit and withdrawal receipts from L1 | -| [Rollup](./exex/rollup) | Illustrates a rollup ExEx that derives the state from L1 | -| [In Memory State](./exex/in-memory-state) | Illustrates an ExEx that tracks the plain state in memory | +| Example | Description | +| ----------------------------------------- | --------------------------------------------------------------------------------------------------- | +| [In Memory State](./exex/in-memory-state) | Illustrates an ExEx that tracks the plain state in memory | +| [Minimal](./exex/minimal) | Illustrates how to build a simple ExEx | +| [OP Bridge](./exex/op-bridge) | Illustrates an ExEx that decodes Optimism deposit and withdrawal receipts from L1 | +| [Rollup](./exex/rollup) | Illustrates a rollup ExEx that derives the state from L1 | +| [Discv5 as ExEx](./exex/discv5) | Illustrates an ExEx that runs discv5 discovery stack | ## RPC @@ -58,11 +59,11 @@ to make a PR! ## P2P -| Example | Description | -| --------------------------- | ----------------------------------------------------------------- | -| [Manual P2P](./manual-p2p) | Illustrates how to connect and communicate with a peer | -| [Polygon P2P](./polygon-p2p) | Illustrates how to connect and communicate with a peer on Polygon | -| [BSC P2P](./bsc-p2p) | Illustrates how to connect and communicate with a peer on Binance Smart Chain | +| Example | Description | +| ---------------------------- | ----------------------------------------------------------------------------- | +| [Manual P2P](./manual-p2p) | Illustrates how to connect and communicate with a peer | +| [Polygon P2P](./polygon-p2p) | Illustrates how to connect and communicate with a peer on Polygon | +| [BSC P2P](./bsc-p2p) | Illustrates how to connect and communicate with a peer on Binance Smart Chain | ## Misc diff --git a/examples/bsc-p2p/Cargo.toml b/examples/bsc-p2p/Cargo.toml index c4d1dbf77032..dde02080d135 100644 --- a/examples/bsc-p2p/Cargo.toml +++ b/examples/bsc-p2p/Cargo.toml @@ -12,6 +12,7 @@ reth-chainspec.workspace = true reth-discv4 = { workspace = true, features = ["test-utils"] } reth-network = { workspace = true, features = ["test-utils"] } reth-network-api.workspace = true +reth-network-peers.workspace = true reth-primitives.workspace = true reth-tracing.workspace = true diff --git a/examples/bsc-p2p/src/chainspec.rs b/examples/bsc-p2p/src/chainspec.rs index d9c3a868297a..0c4cbe1ed961 100644 --- a/examples/bsc-p2p/src/chainspec.rs +++ b/examples/bsc-p2p/src/chainspec.rs @@ -1,7 +1,10 @@ -use reth_chainspec::{net::NodeRecord, BaseFeeParams, Chain, ChainSpec, ForkCondition, Hardfork}; +use reth_chainspec::{ + BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition, +}; +use reth_network_peers::NodeRecord; use reth_primitives::{b256, B256}; -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; pub const SHANGHAI_TIME: u64 = 1705996800; @@ -13,7 +16,10 @@ pub(crate) fn bsc_chain_spec() -> Arc { genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), genesis_hash: Some(GENESIS), paris_block_and_final_difficulty: None, - hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Timestamp(SHANGHAI_TIME))]), + hardforks: ChainHardforks::new(vec![( + EthereumHardfork::Shanghai.boxed(), + ForkCondition::Timestamp(SHANGHAI_TIME), + )]), deposit_contract: None, base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), prune_delete_limit: 0, diff --git a/examples/custom-dev-node/src/main.rs b/examples/custom-dev-node/src/main.rs index 498971dbd1b6..24e7b229f54b 100644 --- a/examples/custom-dev-node/src/main.rs +++ b/examples/custom-dev-node/src/main.rs @@ -3,18 +3,19 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] +use std::sync::Arc; + use futures_util::StreamExt; use reth::{ builder::{NodeBuilder, NodeHandle}, providers::CanonStateSubscriptions, - rpc::eth::EthTransactions, + rpc::api::eth::helpers::EthTransactions, tasks::TaskManager, }; use reth_chainspec::ChainSpec; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; use reth_node_ethereum::EthereumNode; use reth_primitives::{b256, hex, Genesis}; -use std::sync::Arc; #[tokio::main] async fn main() -> eyre::Result<()> { diff --git a/examples/custom-evm/Cargo.toml b/examples/custom-evm/Cargo.toml index 5822bcb22790..a85b6ce8aadb 100644 --- a/examples/custom-evm/Cargo.toml +++ b/examples/custom-evm/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true [dependencies] reth.workspace = true reth-chainspec.workspace = true +reth-evm-ethereum.workspace = true reth-node-api.workspace = true reth-node-core.workspace = true reth-primitives.workspace = true diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index 9d394126fde2..968f0beff1a7 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -7,8 +7,8 @@ use reth::{ builder::{components::ExecutorBuilder, BuilderContext, NodeBuilder}, primitives::{ address, - revm_primitives::{CfgEnvWithHandlerCfg, Env, PrecompileResult, TxEnv}, - Address, Bytes, U256, + revm_primitives::{Env, PrecompileResult}, + Bytes, }, revm::{ handler::register::EvmHandler, @@ -18,11 +18,14 @@ use reth::{ }, tasks::TaskManager, }; -use reth_chainspec::{Chain, ChainSpec}; +use reth_chainspec::{Chain, ChainSpec, Head}; use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, FullNodeTypes}; use reth_node_core::{args::RpcServerArgs, node_config::NodeConfig}; -use reth_node_ethereum::{EthEvmConfig, EthExecutorProvider, EthereumNode}; -use reth_primitives::{Header, TransactionSigned}; +use reth_node_ethereum::{EthExecutorProvider, EthereumNode}; +use reth_primitives::{ + revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg}, + Header, U256, +}; use reth_tracing::{RethTracer, Tracer}; use std::sync::Arc; @@ -63,17 +66,27 @@ impl MyEvmConfig { } impl ConfigureEvmEnv for MyEvmConfig { - fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { - EthEvmConfig::fill_tx_env(tx_env, transaction, sender) - } - fn fill_cfg_env( cfg_env: &mut CfgEnvWithHandlerCfg, chain_spec: &ChainSpec, header: &Header, total_difficulty: U256, ) { - EthEvmConfig::fill_cfg_env(cfg_env, chain_spec, header, total_difficulty) + let spec_id = reth_evm_ethereum::revm_spec( + chain_spec, + &Head { + number: header.number, + timestamp: header.timestamp, + difficulty: header.difficulty, + total_difficulty, + hash: Default::default(), + }, + ); + + cfg_env.chain_id = chain_spec.chain().id(); + cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; + + cfg_env.handler_cfg.spec_id = spec_id; } } diff --git a/examples/custom-inspector/src/main.rs b/examples/custom-inspector/src/main.rs index c1aae0227fc0..fd1d82b59338 100644 --- a/examples/custom-inspector/src/main.rs +++ b/examples/custom-inspector/src/main.rs @@ -21,7 +21,7 @@ use reth::{ interpreter::{Interpreter, OpCode}, Database, Evm, EvmContext, Inspector, }, - rpc::{compat::transaction::transaction_to_call_request, eth::EthTransactions}, + rpc::{api::eth::helpers::Call, compat::transaction::transaction_to_call_request}, transaction_pool::TransactionPool, }; use reth_node_ethereum::node::EthereumNode; diff --git a/examples/custom-node-components/src/main.rs b/examples/custom-node-components/src/main.rs index 19bc9777bea8..842627797ef4 100644 --- a/examples/custom-node-components/src/main.rs +++ b/examples/custom-node-components/src/main.rs @@ -39,7 +39,7 @@ pub struct CustomPoolBuilder { pool_config: PoolConfig, } -/// Implement the `PoolBuilder` trait for the custom pool builder +/// Implement the [`PoolBuilder`] trait for the custom pool builder /// /// This will be used to build the transaction pool and its maintenance tasks during launch. impl PoolBuilder for CustomPoolBuilder diff --git a/examples/custom-rlpx-subprotocol/Cargo.toml b/examples/custom-rlpx-subprotocol/Cargo.toml new file mode 100644 index 000000000000..ae3a7c088c04 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "example-custom-rlpx-subprotocol" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true + + +[dependencies] +tokio = { workspace = true, features = ["full"] } +futures.workspace = true +reth-eth-wire.workspace = true +reth-network.workspace = true +reth-network-api.workspace = true +reth-node-ethereum.workspace = true +reth-provider.workspace = true +reth-primitives.workspace = true +reth-rpc-types.workspace = true +reth.workspace = true +tokio-stream.workspace = true +eyre.workspace = true +rand.workspace = true +tracing.workspace = true diff --git a/examples/custom-rlpx-subprotocol/src/main.rs b/examples/custom-rlpx-subprotocol/src/main.rs new file mode 100644 index 000000000000..3a198c38d285 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/main.rs @@ -0,0 +1,104 @@ +//! Example for how to customize the network layer by adding a custom rlpx subprotocol. +//! +//! Run with +//! +//! ```not_rust +//! cargo run -p example-custom-rlpx-subprotocol -- node +//! ``` +//! +//! This launch a regular reth node with a custom rlpx subprotocol. +use reth::builder::NodeHandle; +use reth_network::{ + config::SecretKey, protocol::IntoRlpxSubProtocol, NetworkConfig, NetworkManager, + NetworkProtocols, +}; +use reth_network_api::NetworkInfo; +use reth_node_ethereum::EthereumNode; +use reth_provider::test_utils::NoopProvider; +use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; +use subprotocol::{ + connection::CustomCommand, + protocol::{ + event::ProtocolEvent, + handler::{CustomRlpxProtoHandler, ProtocolState}, + }, +}; +use tokio::sync::{mpsc, oneshot}; +use tracing::info; + +mod subprotocol; + +fn main() -> eyre::Result<()> { + reth::cli::Cli::parse_args().run(|builder, _args| async move { + // launch the node + let NodeHandle { node, node_exit_future } = + builder.node(EthereumNode::default()).launch().await?; + let peer_id = node.network.peer_id(); + let peer_addr = node.network.local_addr(); + + // add the custom network subprotocol to the launched node + let (tx, mut from_peer0) = mpsc::unbounded_channel(); + let custom_rlpx_handler = CustomRlpxProtoHandler { state: ProtocolState { events: tx } }; + node.network.add_rlpx_sub_protocol(custom_rlpx_handler.into_rlpx_sub_protocol()); + + // creates a separate network instance and adds the custom network subprotocol + let secret_key = SecretKey::new(&mut rand::thread_rng()); + let (tx, mut from_peer1) = mpsc::unbounded_channel(); + let custom_rlpx_handler_2 = CustomRlpxProtoHandler { state: ProtocolState { events: tx } }; + let net_cfg = NetworkConfig::builder(secret_key) + .listener_addr(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))) + .disable_discovery() + .add_rlpx_sub_protocol(custom_rlpx_handler_2.into_rlpx_sub_protocol()) + .build(NoopProvider::default()); + + // spawn the second network instance + let subnetwork = NetworkManager::new(net_cfg).await?; + let subnetwork_peer_id = *subnetwork.peer_id(); + let subnetwork_peer_addr = subnetwork.local_addr(); + let subnetwork_handle = subnetwork.peers_handle(); + node.task_executor.spawn(subnetwork); + + // connect the launched node to the subnetwork + node.network.peers_handle().add_peer(subnetwork_peer_id, subnetwork_peer_addr); + + // connect the subnetwork to the launched node + subnetwork_handle.add_peer(*peer_id, peer_addr); + + // establish connection between peer0 and peer1 + let peer0_to_peer1 = from_peer0.recv().await.expect("peer0 connecting to peer1"); + let peer0_conn = match peer0_to_peer1 { + ProtocolEvent::Established { direction: _, peer_id, to_connection } => { + assert_eq!(peer_id, subnetwork_peer_id); + to_connection + } + }; + + // establish connection between peer1 and peer0 + let peer1_to_peer0 = from_peer1.recv().await.expect("peer1 connecting to peer0"); + let peer1_conn = match peer1_to_peer0 { + ProtocolEvent::Established { direction: _, peer_id: peer1_id, to_connection } => { + assert_eq!(peer1_id, *peer_id); + to_connection + } + }; + info!(target:"rlpx-subprotocol", "Connection established!"); + + // send a ping message from peer0 to peer1 + let (tx, rx) = oneshot::channel(); + peer0_conn.send(CustomCommand::Message { msg: "hello!".to_string(), response: tx })?; + let response = rx.await?; + assert_eq!(response, "hello!"); + info!(target:"rlpx-subprotocol", ?response, "New message received"); + + // send a ping message from peer1 to peer0 + let (tx, rx) = oneshot::channel(); + peer1_conn.send(CustomCommand::Message { msg: "world!".to_string(), response: tx })?; + let response = rx.await?; + assert_eq!(response, "world!"); + info!(target:"rlpx-subprotocol", ?response, "New message received"); + + info!(target:"rlpx-subprotocol", "Peers connected via custom rlpx subprotocol!"); + + node_exit_future.await + }) +} diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/connection/handler.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/connection/handler.rs new file mode 100644 index 000000000000..dae2d5c8679e --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/connection/handler.rs @@ -0,0 +1,53 @@ +use super::CustomRlpxConnection; +use crate::subprotocol::protocol::{ + event::ProtocolEvent, handler::ProtocolState, proto::CustomRlpxProtoMessage, +}; +use reth_eth_wire::{ + capability::SharedCapabilities, multiplex::ProtocolConnection, protocol::Protocol, +}; +use reth_network::protocol::{ConnectionHandler, OnNotSupported}; +use reth_network_api::Direction; +use reth_rpc_types::PeerId; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; + +/// The connection handler for the custom RLPx protocol. +pub(crate) struct CustomRlpxConnectionHandler { + pub(crate) state: ProtocolState, +} + +impl ConnectionHandler for CustomRlpxConnectionHandler { + type Connection = CustomRlpxConnection; + + fn protocol(&self) -> Protocol { + CustomRlpxProtoMessage::protocol() + } + + fn on_unsupported_by_peer( + self, + _supported: &SharedCapabilities, + _direction: Direction, + _peer_id: PeerId, + ) -> OnNotSupported { + OnNotSupported::KeepAlive + } + + fn into_connection( + self, + direction: Direction, + peer_id: PeerId, + conn: ProtocolConnection, + ) -> Self::Connection { + let (tx, rx) = mpsc::unbounded_channel(); + self.state + .events + .send(ProtocolEvent::Established { direction, peer_id, to_connection: tx }) + .ok(); + CustomRlpxConnection { + conn, + initial_ping: direction.is_outgoing().then(CustomRlpxProtoMessage::ping), + commands: UnboundedReceiverStream::new(rx), + pending_pong: None, + } + } +} diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/connection/mod.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/connection/mod.rs new file mode 100644 index 000000000000..a6d835b70c26 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/connection/mod.rs @@ -0,0 +1,76 @@ +use super::protocol::proto::{CustomRlpxProtoMessage, CustomRlpxProtoMessageKind}; +use futures::{Stream, StreamExt}; +use reth_eth_wire::multiplex::ProtocolConnection; +use reth_primitives::BytesMut; +use std::{ + pin::Pin, + task::{ready, Context, Poll}, +}; +use tokio::sync::oneshot; +use tokio_stream::wrappers::UnboundedReceiverStream; + +pub(crate) mod handler; + +/// We define some custom commands that the subprotocol supports. +pub(crate) enum CustomCommand { + /// Sends a message to the peer + Message { + msg: String, + /// The response will be sent to this channel. + response: oneshot::Sender, + }, +} + +/// The connection handler for the custom RLPx protocol. +pub(crate) struct CustomRlpxConnection { + conn: ProtocolConnection, + initial_ping: Option, + commands: UnboundedReceiverStream, + pending_pong: Option>, +} + +impl Stream for CustomRlpxConnection { + type Item = BytesMut; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let this = self.get_mut(); + if let Some(initial_ping) = this.initial_ping.take() { + return Poll::Ready(Some(initial_ping.encoded())) + } + + loop { + if let Poll::Ready(Some(cmd)) = this.commands.poll_next_unpin(cx) { + return match cmd { + CustomCommand::Message { msg, response } => { + this.pending_pong = Some(response); + Poll::Ready(Some(CustomRlpxProtoMessage::ping_message(msg).encoded())) + } + } + } + + let Some(msg) = ready!(this.conn.poll_next_unpin(cx)) else { return Poll::Ready(None) }; + + let Some(msg) = CustomRlpxProtoMessage::decode_message(&mut &msg[..]) else { + return Poll::Ready(None) + }; + + match msg.message { + CustomRlpxProtoMessageKind::Ping => { + return Poll::Ready(Some(CustomRlpxProtoMessage::pong().encoded())) + } + CustomRlpxProtoMessageKind::Pong => {} + CustomRlpxProtoMessageKind::PingMessage(msg) => { + return Poll::Ready(Some(CustomRlpxProtoMessage::pong_message(msg).encoded())) + } + CustomRlpxProtoMessageKind::PongMessage(msg) => { + if let Some(sender) = this.pending_pong.take() { + sender.send(msg).ok(); + } + continue + } + } + + return Poll::Pending + } + } +} diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/mod.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/mod.rs new file mode 100644 index 000000000000..53ec0dc1d4e7 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod connection; +pub(crate) mod protocol; diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/event.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/event.rs new file mode 100644 index 000000000000..ea9e588e592b --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/event.rs @@ -0,0 +1,15 @@ +use crate::subprotocol::connection::CustomCommand; +use reth_network::Direction; +use reth_network_api::PeerId; +use tokio::sync::mpsc; + +/// The events that can be emitted by our custom protocol. +#[derive(Debug)] +pub(crate) enum ProtocolEvent { + Established { + #[allow(dead_code)] + direction: Direction, + peer_id: PeerId, + to_connection: mpsc::UnboundedSender, + }, +} diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/handler.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/handler.rs new file mode 100644 index 000000000000..d5a35398dae1 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/handler.rs @@ -0,0 +1,34 @@ +use super::event::ProtocolEvent; +use crate::subprotocol::connection::handler::CustomRlpxConnectionHandler; +use reth_network::protocol::ProtocolHandler; +use reth_network_api::PeerId; +use std::net::SocketAddr; +use tokio::sync::mpsc; + +/// Protocol state is an helper struct to store the protocol events. +#[derive(Clone, Debug)] +pub(crate) struct ProtocolState { + pub(crate) events: mpsc::UnboundedSender, +} + +/// The protocol handler takes care of incoming and outgoing connections. +#[derive(Debug)] +pub(crate) struct CustomRlpxProtoHandler { + pub state: ProtocolState, +} + +impl ProtocolHandler for CustomRlpxProtoHandler { + type ConnectionHandler = CustomRlpxConnectionHandler; + + fn on_incoming(&self, _socket_addr: SocketAddr) -> Option { + Some(CustomRlpxConnectionHandler { state: self.state.clone() }) + } + + fn on_outgoing( + &self, + _socket_addr: SocketAddr, + _peer_id: PeerId, + ) -> Option { + Some(CustomRlpxConnectionHandler { state: self.state.clone() }) + } +} diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/mod.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/mod.rs new file mode 100644 index 000000000000..8aba9a4e3506 --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod event; +pub(crate) mod handler; +pub(crate) mod proto; diff --git a/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/proto.rs b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/proto.rs new file mode 100644 index 000000000000..8b179a447d9f --- /dev/null +++ b/examples/custom-rlpx-subprotocol/src/subprotocol/protocol/proto.rs @@ -0,0 +1,113 @@ +//! Simple RLPx Ping Pong protocol that also support sending messages, +//! following [RLPx specs](https://github.com/ethereum/devp2p/blob/master/rlpx.md) + +use reth_eth_wire::{protocol::Protocol, Capability}; +use reth_primitives::{Buf, BufMut, BytesMut}; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum CustomRlpxProtoMessageId { + Ping = 0x00, + Pong = 0x01, + PingMessage = 0x02, + PongMessage = 0x03, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) enum CustomRlpxProtoMessageKind { + Ping, + Pong, + PingMessage(String), + PongMessage(String), +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct CustomRlpxProtoMessage { + pub message_type: CustomRlpxProtoMessageId, + pub message: CustomRlpxProtoMessageKind, +} + +impl CustomRlpxProtoMessage { + /// Returns the capability for the `custom_rlpx` protocol. + pub fn capability() -> Capability { + Capability::new_static("custom_rlpx", 1) + } + + /// Returns the protocol for the `custom_rlpx` protocol. + pub fn protocol() -> Protocol { + Protocol::new(Self::capability(), 4) + } + + /// Creates a ping message + pub fn ping_message(msg: impl Into) -> Self { + Self { + message_type: CustomRlpxProtoMessageId::PingMessage, + message: CustomRlpxProtoMessageKind::PingMessage(msg.into()), + } + } + /// Creates a ping message + pub fn pong_message(msg: impl Into) -> Self { + Self { + message_type: CustomRlpxProtoMessageId::PongMessage, + message: CustomRlpxProtoMessageKind::PongMessage(msg.into()), + } + } + + /// Creates a ping message + pub fn ping() -> Self { + Self { + message_type: CustomRlpxProtoMessageId::Ping, + message: CustomRlpxProtoMessageKind::Ping, + } + } + + /// Creates a pong message + pub fn pong() -> Self { + Self { + message_type: CustomRlpxProtoMessageId::Pong, + message: CustomRlpxProtoMessageKind::Pong, + } + } + + /// Creates a new `CustomRlpxProtoMessage` with the given message ID and payload. + pub fn encoded(&self) -> BytesMut { + let mut buf = BytesMut::new(); + buf.put_u8(self.message_type as u8); + match &self.message { + CustomRlpxProtoMessageKind::Ping | CustomRlpxProtoMessageKind::Pong => {} + CustomRlpxProtoMessageKind::PingMessage(msg) | + CustomRlpxProtoMessageKind::PongMessage(msg) => { + buf.put(msg.as_bytes()); + } + } + buf + } + + /// Decodes a `CustomRlpxProtoMessage` from the given message buffer. + pub fn decode_message(buf: &mut &[u8]) -> Option { + if buf.is_empty() { + return None; + } + let id = buf[0]; + buf.advance(1); + let message_type = match id { + 0x00 => CustomRlpxProtoMessageId::Ping, + 0x01 => CustomRlpxProtoMessageId::Pong, + 0x02 => CustomRlpxProtoMessageId::PingMessage, + 0x03 => CustomRlpxProtoMessageId::PongMessage, + _ => return None, + }; + let message = match message_type { + CustomRlpxProtoMessageId::Ping => CustomRlpxProtoMessageKind::Ping, + CustomRlpxProtoMessageId::Pong => CustomRlpxProtoMessageKind::Pong, + CustomRlpxProtoMessageId::PingMessage => CustomRlpxProtoMessageKind::PingMessage( + String::from_utf8_lossy(&buf[..]).into_owned(), + ), + CustomRlpxProtoMessageId::PongMessage => CustomRlpxProtoMessageKind::PongMessage( + String::from_utf8_lossy(&buf[..]).into_owned(), + ), + }; + + Some(Self { message_type, message }) + } +} diff --git a/examples/exex/discv5/Cargo.toml b/examples/exex/discv5/Cargo.toml new file mode 100644 index 000000000000..b1777cfa1516 --- /dev/null +++ b/examples/exex/discv5/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "example-exex-discv5" +version = "0.0.0" +publish = false +edition.workspace = true +license.workspace = true + +[dependencies] +discv5.workspace = true +enr.workspace = true + +reth-discv5.workspace = true +reth.workspace = true +reth-exex.workspace = true +reth-node-api.workspace = true +reth-node-ethereum.workspace = true +reth-network-peers.workspace = true +reth-tracing.workspace = true +futures.workspace = true + +clap.workspace = true +reth-chainspec.workspace = true +serde_json.workspace = true +tokio.workspace = true +tokio-stream.workspace = true +futures-util.workspace = true + +tracing.workspace = true +eyre.workspace = true + +[dev-dependencies] +reth-exex-test-utils.workspace = true +reth-testing-utils.workspace = true diff --git a/examples/exex/discv5/src/exex/mod.rs b/examples/exex/discv5/src/exex/mod.rs new file mode 100644 index 000000000000..4631f392979c --- /dev/null +++ b/examples/exex/discv5/src/exex/mod.rs @@ -0,0 +1,70 @@ +use eyre::Result; +use futures::{Future, FutureExt}; +use reth_exex::{ExExContext, ExExEvent, ExExNotification}; +use reth_node_api::FullNodeComponents; +use reth_tracing::tracing::info; +use std::{ + pin::Pin, + task::{ready, Context, Poll}, +}; +use tracing::error; + +use crate::network::DiscV5ExEx; + +/// The ExEx struct, representing the initialization and execution of the ExEx. +pub struct ExEx { + exex: ExExContext, + disc_v5: DiscV5ExEx, +} + +impl ExEx { + pub fn new(exex: ExExContext, disc_v5: DiscV5ExEx) -> Self { + Self { exex, disc_v5 } + } +} + +impl Future for ExEx { + type Output = Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Poll the Discv5 future until its drained + loop { + match self.disc_v5.poll_unpin(cx) { + Poll::Ready(Ok(())) => { + info!("Discv5 task completed successfully"); + } + Poll::Ready(Err(e)) => { + error!(?e, "Discv5 task encountered an error"); + return Poll::Ready(Err(e)); + } + Poll::Pending => { + // Exit match and continue to poll notifications + break; + } + } + } + + // Continuously poll the ExExContext notifications + loop { + if let Some(notification) = ready!(self.exex.notifications.poll_recv(cx)) { + match ¬ification { + ExExNotification::ChainCommitted { new } => { + info!(committed_chain = ?new.range(), "Received commit"); + } + ExExNotification::ChainReorged { old, new } => { + info!(from_chain = ?old.range(), to_chain = ?new.range(), "Received reorg"); + } + ExExNotification::ChainReverted { old } => { + info!(reverted_chain = ?old.range(), "Received revert"); + } + } + + if let Some(committed_chain) = notification.committed_chain() { + self.exex + .events + .send(ExExEvent::FinishedHeight(committed_chain.tip().number))?; + } + } + } + } +} diff --git a/examples/exex/discv5/src/main.rs b/examples/exex/discv5/src/main.rs new file mode 100644 index 000000000000..2374326050b7 --- /dev/null +++ b/examples/exex/discv5/src/main.rs @@ -0,0 +1,29 @@ +use clap::Parser; + +use exex::ExEx; +use network::{cli_ext::Discv5ArgsExt, DiscV5ExEx}; +use reth_node_ethereum::EthereumNode; + +mod exex; +mod network; + +fn main() -> eyre::Result<()> { + reth::cli::Cli::::parse().run(|builder, args| async move { + let tcp_port = args.tcp_port; + let udp_port = args.udp_port; + + let handle = builder + .node(EthereumNode::default()) + .install_exex("exex-discv5", move |ctx| async move { + // start Discv5 task + let disc_v5 = DiscV5ExEx::new(tcp_port, udp_port).await?; + + // start exex task with discv5 + Ok(ExEx::new(ctx, disc_v5)) + }) + .launch() + .await?; + + handle.wait_for_node_exit().await + }) +} diff --git a/examples/exex/discv5/src/network/cli_ext.rs b/examples/exex/discv5/src/network/cli_ext.rs new file mode 100644 index 000000000000..1eb864de3611 --- /dev/null +++ b/examples/exex/discv5/src/network/cli_ext.rs @@ -0,0 +1,15 @@ +use clap::Args; + +pub const DEFAULT_DISCOVERY_PORT: u16 = 30304; +pub const DEFAULT_RLPX_PORT: u16 = 30303; + +#[derive(Debug, Clone, Args)] +pub(crate) struct Discv5ArgsExt { + /// TCP port used by RLPx + #[clap(long = "exex-discv5.tcp-port", default_value_t = DEFAULT_RLPX_PORT)] + pub tcp_port: u16, + + /// UDP port used for discovery + #[clap(long = "exex-discv5.udp-port", default_value_t = DEFAULT_DISCOVERY_PORT)] + pub udp_port: u16, +} diff --git a/examples/exex/discv5/src/network/mod.rs b/examples/exex/discv5/src/network/mod.rs new file mode 100644 index 000000000000..ebab28342d88 --- /dev/null +++ b/examples/exex/discv5/src/network/mod.rs @@ -0,0 +1,123 @@ +#![allow(dead_code)] + +use discv5::{enr::secp256k1::rand, Enr, Event, ListenConfig}; +use reth::network::config::SecretKey; +use reth_discv5::{enr::EnrCombinedKeyWrapper, Config, Discv5}; +use reth_network_peers::NodeRecord; +use reth_tracing::tracing::info; +use std::{ + future::Future, + net::SocketAddr, + pin::Pin, + task::{ready, Context, Poll}, +}; +use tokio::sync::mpsc; + +pub(crate) mod cli_ext; + +/// Helper struct to manage a discovery node using discv5. +pub(crate) struct DiscV5ExEx { + /// The inner discv5 instance. + inner: Discv5, + /// The node record of the discv5 instance. + node_record: NodeRecord, + /// The events stream of the discv5 instance. + events: mpsc::Receiver, +} + +impl DiscV5ExEx { + /// Starts a new discv5 node. + pub async fn new(udp_port: u16, tcp_port: u16) -> eyre::Result { + let secret_key = SecretKey::new(&mut rand::thread_rng()); + + let discv5_addr: SocketAddr = format!("127.0.0.1:{udp_port}").parse()?; + let rlpx_addr: SocketAddr = format!("127.0.0.1:{tcp_port}").parse()?; + + let discv5_listen_config = ListenConfig::from(discv5_addr); + let discv5_config = Config::builder(rlpx_addr) + .discv5_config(discv5::ConfigBuilder::new(discv5_listen_config).build()) + .build(); + + let (discv5, events, node_record) = Discv5::start(&secret_key, discv5_config).await?; + Ok(Self { inner: discv5, events, node_record }) + } + + /// Adds a node to the table if its not already present. + pub fn add_node(&mut self, enr: Enr) -> eyre::Result<()> { + let reth_enr: enr::Enr = EnrCombinedKeyWrapper(enr.clone()).into(); + self.inner.add_node(reth_enr)?; + Ok(()) + } + + /// Returns the local ENR of the discv5 node. + pub fn local_enr(&self) -> Enr { + self.inner.with_discv5(|discv5| discv5.local_enr()) + } +} + +impl Future for DiscV5ExEx { + type Output = eyre::Result<()>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut this = self.as_mut(); + loop { + match ready!(this.events.poll_recv(cx)) { + Some(evt) => { + if let Event::SessionEstablished(enr, socket_addr) = evt { + info!(?enr, ?socket_addr, "Session established with a new peer."); + } + } + None => return Poll::Ready(Ok(())), + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::network::DiscV5ExEx; + use tracing::info; + + #[tokio::test] + async fn can_establish_discv5_session_with_peer() { + reth_tracing::init_test_tracing(); + let mut node_1 = DiscV5ExEx::new(30301, 30303).await.unwrap(); + let node_1_enr = node_1.local_enr(); + + let mut node_2 = DiscV5ExEx::new(30302, 30303).await.unwrap(); + + let node_2_enr = node_2.local_enr(); + + info!(?node_1_enr, ?node_2_enr, "Started discovery nodes."); + + // add node_2 to node_1 table + node_1.add_node(node_2_enr.clone()).unwrap(); + + // verify node_2 is in node_1 table + assert!(node_1 + .inner + .with_discv5(|discv5| discv5.table_entries_id().contains(&node_2_enr.node_id()))); + + // send ping from node_1 to node_2 + node_1.inner.with_discv5(|discv5| discv5.send_ping(node_2_enr.clone())).await.unwrap(); + + // verify they both established a session + let event_2_v5 = node_2.events.recv().await.unwrap(); + let event_1_v5 = node_1.events.recv().await.unwrap(); + assert!(matches!( + event_1_v5, + discv5::Event::SessionEstablished(node, socket) if node == node_2_enr && socket == node_2_enr.udp4_socket().unwrap().into() + )); + assert!(matches!( + event_2_v5, + discv5::Event::SessionEstablished(node, socket) if node == node_1_enr && socket == node_1_enr.udp4_socket().unwrap().into() + )); + + // verify node_1 is in + let event_2_v5 = node_2.events.recv().await.unwrap(); + assert!(matches!( + event_2_v5, + discv5::Event::NodeInserted { node_id, replaced } if node_id == node_1_enr.node_id() && replaced.is_none() + )); + } +} diff --git a/examples/exex/remote/Cargo.toml b/examples/exex/remote/Cargo.toml deleted file mode 100644 index 634b9a7fef7e..000000000000 --- a/examples/exex/remote/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "example-exex-remote" -version = "0.0.0" -publish = false -edition.workspace = true -license.workspace = true - -[dependencies] -reth.workspace = true -reth-exex = { workspace = true, features = ["serde"] } -reth-node-api.workspace = true -reth-node-ethereum.workspace = true -reth-tracing.workspace = true - -eyre.workspace = true - -tonic = "0.11" -prost = "0.12" -tokio = { version = "1.0", features = ["full"] } -tokio-stream = "0.1" - -bincode = "1.3" - -[build-dependencies] -tonic-build = "0.11" - -[dev-dependencies] -reth-exex-test-utils.workspace = true - -tokio.workspace = true - -[features] -default = [] -optimism = ["reth/optimism"] - -[[bin]] -name = "exex" -path = "bin/exex.rs" - -[[bin]] -name = "consumer" -path = "bin/consumer.rs" diff --git a/examples/exex/remote/bin/consumer.rs b/examples/exex/remote/bin/consumer.rs deleted file mode 100644 index 71d4ebbe6ed6..000000000000 --- a/examples/exex/remote/bin/consumer.rs +++ /dev/null @@ -1,32 +0,0 @@ -use example_exex_remote::proto::{remote_ex_ex_client::RemoteExExClient, SubscribeRequest}; -use reth_exex::ExExNotification; -use reth_tracing::{tracing::info, RethTracer, Tracer}; - -#[tokio::main] -async fn main() -> eyre::Result<()> { - let _ = RethTracer::new().init()?; - - let mut client = RemoteExExClient::connect("http://[::1]:10000") - .await? - .max_encoding_message_size(usize::MAX) - .max_decoding_message_size(usize::MAX); - - let mut stream = client.subscribe(SubscribeRequest {}).await?.into_inner(); - while let Some(notification) = stream.message().await? { - let notification = ExExNotification::try_from(¬ification)?; - - match notification { - ExExNotification::ChainCommitted { new } => { - info!(committed_chain = ?new.range(), "Received commit"); - } - ExExNotification::ChainReorged { old, new } => { - info!(from_chain = ?old.range(), to_chain = ?new.range(), "Received reorg"); - } - ExExNotification::ChainReverted { old } => { - info!(reverted_chain = ?old.range(), "Received revert"); - } - }; - } - - Ok(()) -} diff --git a/examples/exex/remote/bin/exex.rs b/examples/exex/remote/bin/exex.rs deleted file mode 100644 index ed1e5ec1e8c4..000000000000 --- a/examples/exex/remote/bin/exex.rs +++ /dev/null @@ -1,77 +0,0 @@ -use example_exex_remote::proto::{ - remote_ex_ex_server::{RemoteExEx, RemoteExExServer}, - ExExNotification as ProtoExExNotification, SubscribeRequest as ProtoSubscribeRequest, -}; -use reth_exex::{ExExContext, ExExEvent, ExExNotification}; -use reth_node_api::FullNodeComponents; -use reth_node_ethereum::EthereumNode; -use tokio::sync::{broadcast, mpsc}; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{transport::Server, Request, Response, Status}; - -#[derive(Debug)] -struct ExExService { - notifications: broadcast::Sender, -} - -#[tonic::async_trait] -impl RemoteExEx for ExExService { - type SubscribeStream = ReceiverStream>; - - async fn subscribe( - &self, - _request: Request, - ) -> Result, Status> { - let (tx, rx) = mpsc::channel(1); - - let mut notifications = self.notifications.subscribe(); - tokio::spawn(async move { - while let Ok(notification) = notifications.recv().await { - tx.send(Ok((¬ification).try_into().expect("failed to encode"))) - .await - .expect("failed to send notification to client"); - } - }); - - Ok(Response::new(ReceiverStream::new(rx))) - } -} - -async fn exex( - mut ctx: ExExContext, - notifications: broadcast::Sender, -) -> eyre::Result<()> { - while let Some(notification) = ctx.notifications.recv().await { - if let Some(committed_chain) = notification.committed_chain() { - ctx.events.send(ExExEvent::FinishedHeight(committed_chain.tip().number))?; - } - - let _ = notifications.send(notification); - } - - Ok(()) -} - -fn main() -> eyre::Result<()> { - reth::cli::Cli::parse_args().run(|builder, _| async move { - let notifications = broadcast::channel(1).0; - - let server = Server::builder() - .add_service(RemoteExExServer::new(ExExService { - notifications: notifications.clone(), - })) - .serve("[::1]:10000".parse().unwrap()); - - let handle = builder - .node(EthereumNode::default()) - .install_exex("Remote", |ctx| async move { Ok(exex(ctx, notifications)) }) - .launch() - .await?; - - handle.node.task_executor.spawn_critical("gRPC server", async move { - server.await.expect("gRPC server crashed") - }); - - handle.wait_for_node_exit().await - }) -} diff --git a/examples/exex/remote/build.rs b/examples/exex/remote/build.rs deleted file mode 100644 index 9e70bbe9b31f..000000000000 --- a/examples/exex/remote/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - tonic_build::compile_protos("proto/exex.proto") - .unwrap_or_else(|e| panic!("Failed to compile protos {:?}", e)); -} diff --git a/examples/exex/remote/proto/exex.proto b/examples/exex/remote/proto/exex.proto deleted file mode 100644 index 17620b6802ab..000000000000 --- a/examples/exex/remote/proto/exex.proto +++ /dev/null @@ -1,279 +0,0 @@ -syntax = "proto3"; - -package exex; - -import "google/protobuf/empty.proto"; - -service RemoteExEx { - rpc Subscribe(SubscribeRequest) returns (stream ExExNotification) {} -} - -message SubscribeRequest {} - -message ExExNotification { - oneof notification { - ChainCommitted chain_committed = 1; - ChainReorged chain_reorged = 2; - ChainReverted chain_reverted = 3; - } -} - -message ChainCommitted { - Chain new = 1; -} - -message ChainReorged { - Chain old = 1; - Chain new = 2; -} - -message ChainReverted { - Chain old = 1; -} - -message Chain { - repeated Block blocks = 1; - ExecutionOutcome execution_outcome = 2; -} - -message Block { - SealedHeader header = 1; - repeated Transaction body = 2; - repeated Header ommers = 3; - repeated bytes senders = 4; - // TODO: add withdrawals and requests -} - -message SealedHeader { - bytes hash = 1; - Header header = 2; -} - -message Header { - bytes parent_hash = 1; - bytes ommers_hash = 2; - bytes beneficiary = 3; - bytes state_root = 4; - bytes transactions_root = 5; - bytes receipts_root = 6; - optional bytes withdrawals_root = 7; - bytes logs_bloom = 8; - bytes difficulty = 9; - uint64 number = 10; - uint64 gas_limit = 11; - uint64 gas_used = 12; - uint64 timestamp = 13; - bytes mix_hash = 14; - uint64 nonce = 15; - optional uint64 base_fee_per_gas = 16; - optional uint64 blob_gas_used = 17; - optional uint64 excess_blob_gas = 18; - optional bytes parent_beacon_block_root = 19; - // TODO: add requests_root - bytes extra_data = 20; -} - -message Transaction { - bytes hash = 1; - Signature signature = 2; - oneof transaction { - TransactionLegacy legacy = 3; - TransactionEip2930 eip2930 = 4; - TransactionEip1559 eip1559 = 5; - TransactionEip4844 eip4844 = 6; - } -} - -message Signature { - bytes r = 1; - bytes s = 2; - bool odd_y_parity = 3; -} - -message TransactionLegacy { - optional uint64 chain_id = 1; - uint64 nonce = 2; - bytes gas_price = 3; - uint64 gas_limit = 4; - TxKind to = 5; - bytes value = 6; - bytes input = 7; -} - -message TransactionEip2930 { - uint64 chain_id = 1; - uint64 nonce = 2; - bytes gas_price = 3; - uint64 gas_limit = 4; - TxKind to = 5; - bytes value = 6; - repeated AccessListItem access_list = 7; - bytes input = 8; -} - -message TransactionEip1559 { - uint64 chain_id = 1; - uint64 nonce = 2; - uint64 gas_limit = 3; - bytes max_fee_per_gas = 4; - bytes max_priority_fee_per_gas = 5; - TxKind to = 6; - bytes value = 7; - repeated AccessListItem access_list = 8; - bytes input = 9; -} - -message TransactionEip4844 { - uint64 chain_id = 1; - uint64 nonce = 2; - uint64 gas_limit = 3; - bytes max_fee_per_gas = 4; - bytes max_priority_fee_per_gas = 5; - bytes to = 6; - bytes value = 7; - repeated AccessListItem access_list = 8; - repeated bytes blob_versioned_hashes = 9; - bytes max_fee_per_blob_gas = 10; - bytes input = 11; -} - -message TxKind { - oneof kind { - google.protobuf.Empty create = 1; - bytes call = 2; - } -} - -message AccessListItem { - bytes address = 1; - repeated bytes storage_keys = 2; -} - -message ExecutionOutcome { - BundleState bundle = 1; - repeated BlockReceipts receipts = 2; - uint64 first_block = 3; - // TODO: add requests -} - -message BundleState { - repeated BundleAccount state = 1; - repeated ContractBytecode contracts = 2; - repeated BlockReverts reverts = 3; - uint64 state_size = 4; - uint64 reverts_size = 5; -} - -message BundleAccount { - bytes address = 1; - AccountInfo info = 2; - AccountInfo original_info = 3; - repeated StorageSlot storage = 4; - AccountStatus status = 5; -} - -message AccountInfo { - bytes balance = 1; - uint64 nonce = 2; - bytes code_hash = 3; - Bytecode code = 4; -} - -message StorageSlot { - bytes key = 1; - bytes previous_or_original_value = 2; - bytes present_value = 3; -} - -enum AccountStatus { - LOADED_NOT_EXISTING = 0; - LOADED = 1; - LOADED_EMPTY_EIP161 = 2; - IN_MEMORY_CHANGE = 3; - CHANGED = 4; - DESTROYED = 5; - DESTROYED_CHANGED = 6; - DESTROYED_AGAIN = 7; -} - -message ContractBytecode { - bytes hash = 1; - Bytecode bytecode = 2; -} - -message Bytecode { - oneof bytecode { - bytes legacy_raw = 1; - LegacyAnalyzedBytecode legacy_analyzed = 2; - // TODO: add EOF - } -} - -message LegacyAnalyzedBytecode { - bytes bytecode = 1; - uint64 original_len = 2; - repeated uint32 jump_table = 3; -} - -message BlockReverts { - repeated Revert reverts = 1; -} - -message Revert { - bytes address = 1; - AccountInfoRevert account = 2; - repeated RevertToSlot storage = 3; - AccountStatus previous_status = 4; - bool wipe_storage = 5; -} - -message AccountInfoRevert { - oneof revert { - google.protobuf.Empty do_nothing = 1; - google.protobuf.Empty delete_it = 2; - AccountInfo revert_to = 3; - } -} - -message RevertToSlot { - bytes key = 1; - oneof revert { - bytes some = 2; - google.protobuf.Empty destroyed = 3; - } -} - -message BlockReceipts { - repeated Receipt receipts = 1; -} - -message Receipt { - oneof receipt { - google.protobuf.Empty empty = 1; - NonEmptyReceipt non_empty = 2; - } -} - -message NonEmptyReceipt { - TxType tx_type = 1; - bool success = 2; - uint64 cumulative_gas_used = 3; - repeated Log logs = 4; -} - -enum TxType { - LEGACY = 0; - EIP2930 = 1; - EIP1559 = 2; - EIP4844 = 3; -} - -message Log { - bytes address = 1; - LogData data = 2; -} - -message LogData { - repeated bytes topics = 1; - bytes data = 2; -} diff --git a/examples/exex/remote/src/codec.rs b/examples/exex/remote/src/codec.rs deleted file mode 100644 index d36b60b92a5c..000000000000 --- a/examples/exex/remote/src/codec.rs +++ /dev/null @@ -1,961 +0,0 @@ -use std::sync::Arc; - -use eyre::OptionExt; -use reth::primitives::{Address, BlockHash, Bloom, TxHash, B256, U256}; - -use crate::proto; - -impl TryFrom<&reth_exex::ExExNotification> for proto::ExExNotification { - type Error = eyre::Error; - - fn try_from(notification: &reth_exex::ExExNotification) -> Result { - let notification = match notification { - reth_exex::ExExNotification::ChainCommitted { new } => { - proto::ex_ex_notification::Notification::ChainCommitted(proto::ChainCommitted { - new: Some(new.as_ref().try_into()?), - }) - } - reth_exex::ExExNotification::ChainReorged { old, new } => { - proto::ex_ex_notification::Notification::ChainReorged(proto::ChainReorged { - old: Some(old.as_ref().try_into()?), - new: Some(new.as_ref().try_into()?), - }) - } - reth_exex::ExExNotification::ChainReverted { old } => { - proto::ex_ex_notification::Notification::ChainReverted(proto::ChainReverted { - old: Some(old.as_ref().try_into()?), - }) - } - }; - - Ok(proto::ExExNotification { notification: Some(notification) }) - } -} - -impl TryFrom<&reth::providers::Chain> for proto::Chain { - type Error = eyre::Error; - - fn try_from(chain: &reth::providers::Chain) -> Result { - let bundle_state = chain.execution_outcome().state(); - Ok(proto::Chain { - blocks: chain - .blocks_iter() - .map(|block| { - Ok(proto::Block { - header: Some(proto::SealedHeader { - hash: block.header.hash().to_vec(), - header: Some(block.header.header().into()), - }), - body: block - .transactions() - .map(TryInto::try_into) - .collect::>()?, - ommers: block.ommers.iter().map(Into::into).collect(), - senders: block.senders.iter().map(|sender| sender.to_vec()).collect(), - }) - }) - .collect::>()?, - execution_outcome: Some(proto::ExecutionOutcome { - bundle: Some(proto::BundleState { - state: bundle_state - .state - .iter() - .map(|(address, account)| (*address, account).try_into()) - .collect::>()?, - contracts: bundle_state - .contracts - .iter() - .map(|(hash, bytecode)| { - Ok(proto::ContractBytecode { - hash: hash.to_vec(), - bytecode: Some(bytecode.try_into()?), - }) - }) - .collect::>()?, - reverts: bundle_state - .reverts - .iter() - .map(|block_reverts| { - Ok(proto::BlockReverts { - reverts: block_reverts - .iter() - .map(|(address, revert)| (*address, revert).try_into()) - .collect::>()?, - }) - }) - .collect::>()?, - state_size: bundle_state.state_size as u64, - reverts_size: bundle_state.reverts_size as u64, - }), - receipts: chain - .execution_outcome() - .receipts() - .iter() - .map(|block_receipts| { - Ok(proto::BlockReceipts { - receipts: block_receipts - .iter() - .map(TryInto::try_into) - .collect::>()?, - }) - }) - .collect::>()?, - first_block: chain.execution_outcome().first_block, - }), - }) - } -} - -impl From<&reth::primitives::Header> for proto::Header { - fn from(header: &reth::primitives::Header) -> Self { - proto::Header { - parent_hash: header.parent_hash.to_vec(), - ommers_hash: header.ommers_hash.to_vec(), - beneficiary: header.beneficiary.to_vec(), - state_root: header.state_root.to_vec(), - transactions_root: header.transactions_root.to_vec(), - receipts_root: header.receipts_root.to_vec(), - withdrawals_root: header.withdrawals_root.map(|root| root.to_vec()), - logs_bloom: header.logs_bloom.to_vec(), - difficulty: header.difficulty.to_le_bytes_vec(), - number: header.number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - mix_hash: header.mix_hash.to_vec(), - nonce: header.nonce, - base_fee_per_gas: header.base_fee_per_gas, - blob_gas_used: header.blob_gas_used, - excess_blob_gas: header.excess_blob_gas, - parent_beacon_block_root: header.parent_beacon_block_root.map(|root| root.to_vec()), - extra_data: header.extra_data.to_vec(), - } - } -} - -impl TryFrom<&reth::primitives::TransactionSigned> for proto::Transaction { - type Error = eyre::Error; - - fn try_from(transaction: &reth::primitives::TransactionSigned) -> Result { - let hash = transaction.hash().to_vec(); - let signature = proto::Signature { - r: transaction.signature.r.to_le_bytes_vec(), - s: transaction.signature.s.to_le_bytes_vec(), - odd_y_parity: transaction.signature.odd_y_parity, - }; - let transaction = match &transaction.transaction { - reth::primitives::Transaction::Legacy(reth::primitives::TxLegacy { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - input, - }) => proto::transaction::Transaction::Legacy(proto::TransactionLegacy { - chain_id: *chain_id, - nonce: *nonce, - gas_price: gas_price.to_le_bytes().to_vec(), - gas_limit: *gas_limit, - to: Some(to.into()), - value: value.to_le_bytes_vec(), - input: input.to_vec(), - }), - reth::primitives::Transaction::Eip2930(reth::primitives::TxEip2930 { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - access_list, - input, - }) => proto::transaction::Transaction::Eip2930(proto::TransactionEip2930 { - chain_id: *chain_id, - nonce: *nonce, - gas_price: gas_price.to_le_bytes().to_vec(), - gas_limit: *gas_limit, - to: Some(to.into()), - value: value.to_le_bytes_vec(), - access_list: access_list.iter().map(Into::into).collect(), - input: input.to_vec(), - }), - reth::primitives::Transaction::Eip1559(reth::primitives::TxEip1559 { - chain_id, - nonce, - gas_limit, - max_fee_per_gas, - max_priority_fee_per_gas, - to, - value, - access_list, - input, - }) => proto::transaction::Transaction::Eip1559(proto::TransactionEip1559 { - chain_id: *chain_id, - nonce: *nonce, - gas_limit: *gas_limit, - max_fee_per_gas: max_fee_per_gas.to_le_bytes().to_vec(), - max_priority_fee_per_gas: max_priority_fee_per_gas.to_le_bytes().to_vec(), - to: Some(to.into()), - value: value.to_le_bytes_vec(), - access_list: access_list.iter().map(Into::into).collect(), - input: input.to_vec(), - }), - reth::primitives::Transaction::Eip4844(reth::primitives::TxEip4844 { - chain_id, - nonce, - gas_limit, - max_fee_per_gas, - max_priority_fee_per_gas, - placeholder: _, - to, - value, - access_list, - blob_versioned_hashes, - max_fee_per_blob_gas, - input, - }) => proto::transaction::Transaction::Eip4844(proto::TransactionEip4844 { - chain_id: *chain_id, - nonce: *nonce, - gas_limit: *gas_limit, - max_fee_per_gas: max_fee_per_gas.to_le_bytes().to_vec(), - max_priority_fee_per_gas: max_priority_fee_per_gas.to_le_bytes().to_vec(), - to: to.to_vec(), - value: value.to_le_bytes_vec(), - access_list: access_list.iter().map(Into::into).collect(), - blob_versioned_hashes: blob_versioned_hashes - .iter() - .map(|hash| hash.to_vec()) - .collect(), - max_fee_per_blob_gas: max_fee_per_blob_gas.to_le_bytes().to_vec(), - input: input.to_vec(), - }), - #[cfg(feature = "optimism")] - reth::primitives::Transaction::Deposit(_) => { - eyre::bail!("deposit transaction not supported") - } - }; - - Ok(proto::Transaction { hash, signature: Some(signature), transaction: Some(transaction) }) - } -} - -impl From<&reth::primitives::TxKind> for proto::TxKind { - fn from(kind: &reth::primitives::TxKind) -> Self { - proto::TxKind { - kind: match kind { - reth::primitives::TxKind::Create => Some(proto::tx_kind::Kind::Create(())), - reth::primitives::TxKind::Call(address) => { - Some(proto::tx_kind::Kind::Call(address.to_vec())) - } - }, - } - } -} - -impl From<&reth::primitives::AccessListItem> for proto::AccessListItem { - fn from(item: &reth::primitives::AccessListItem) -> Self { - proto::AccessListItem { - address: item.address.to_vec(), - storage_keys: item.storage_keys.iter().map(|key| key.to_vec()).collect(), - } - } -} - -impl TryFrom<(Address, &reth::revm::db::BundleAccount)> for proto::BundleAccount { - type Error = eyre::Error; - - fn try_from( - (address, account): (Address, &reth::revm::db::BundleAccount), - ) -> Result { - Ok(proto::BundleAccount { - address: address.to_vec(), - info: account.info.as_ref().map(TryInto::try_into).transpose()?, - original_info: account.original_info.as_ref().map(TryInto::try_into).transpose()?, - storage: account - .storage - .iter() - .map(|(key, slot)| proto::StorageSlot { - key: key.to_le_bytes_vec(), - previous_or_original_value: slot.previous_or_original_value.to_le_bytes_vec(), - present_value: slot.present_value.to_le_bytes_vec(), - }) - .collect(), - status: proto::AccountStatus::from(account.status) as i32, - }) - } -} - -impl TryFrom<&reth::revm::primitives::AccountInfo> for proto::AccountInfo { - type Error = eyre::Error; - - fn try_from(account_info: &reth::revm::primitives::AccountInfo) -> Result { - Ok(proto::AccountInfo { - balance: account_info.balance.to_le_bytes_vec(), - nonce: account_info.nonce, - code_hash: account_info.code_hash.to_vec(), - code: account_info.code.as_ref().map(TryInto::try_into).transpose()?, - }) - } -} - -impl TryFrom<&reth::revm::primitives::Bytecode> for proto::Bytecode { - type Error = eyre::Error; - - fn try_from(bytecode: &reth::revm::primitives::Bytecode) -> Result { - let bytecode = match bytecode { - reth::revm::primitives::Bytecode::LegacyRaw(code) => { - proto::bytecode::Bytecode::LegacyRaw(code.to_vec()) - } - reth::revm::primitives::Bytecode::LegacyAnalyzed(legacy_analyzed) => { - proto::bytecode::Bytecode::LegacyAnalyzed(proto::LegacyAnalyzedBytecode { - bytecode: legacy_analyzed.bytecode().to_vec(), - original_len: legacy_analyzed.original_len() as u64, - jump_table: legacy_analyzed - .jump_table() - .0 - .iter() - .by_vals() - .map(|x| x.into()) - .collect(), - }) - } - reth::revm::primitives::Bytecode::Eof(_) => { - eyre::bail!("EOF bytecode not supported"); - } - }; - Ok(proto::Bytecode { bytecode: Some(bytecode) }) - } -} - -impl From for proto::AccountStatus { - fn from(status: reth::revm::db::AccountStatus) -> Self { - match status { - reth::revm::db::AccountStatus::LoadedNotExisting => { - proto::AccountStatus::LoadedNotExisting - } - reth::revm::db::AccountStatus::Loaded => proto::AccountStatus::Loaded, - reth::revm::db::AccountStatus::LoadedEmptyEIP161 => { - proto::AccountStatus::LoadedEmptyEip161 - } - reth::revm::db::AccountStatus::InMemoryChange => proto::AccountStatus::InMemoryChange, - reth::revm::db::AccountStatus::Changed => proto::AccountStatus::Changed, - reth::revm::db::AccountStatus::Destroyed => proto::AccountStatus::Destroyed, - reth::revm::db::AccountStatus::DestroyedChanged => { - proto::AccountStatus::DestroyedChanged - } - reth::revm::db::AccountStatus::DestroyedAgain => proto::AccountStatus::DestroyedAgain, - } - } -} - -impl TryFrom<(Address, &reth::revm::db::states::reverts::AccountRevert)> for proto::Revert { - type Error = eyre::Error; - - fn try_from( - (address, revert): (Address, &reth::revm::db::states::reverts::AccountRevert), - ) -> Result { - Ok(proto::Revert { - address: address.to_vec(), - account: Some(proto::AccountInfoRevert { - revert: Some(match &revert.account { - reth::revm::db::states::reverts::AccountInfoRevert::DoNothing => { - proto::account_info_revert::Revert::DoNothing(()) - } - reth::revm::db::states::reverts::AccountInfoRevert::DeleteIt => { - proto::account_info_revert::Revert::DeleteIt(()) - } - reth::revm::db::states::reverts::AccountInfoRevert::RevertTo(account_info) => { - proto::account_info_revert::Revert::RevertTo(account_info.try_into()?) - } - }), - }), - storage: revert - .storage - .iter() - .map(|(key, slot)| { - Ok(proto::RevertToSlot { - key: key.to_le_bytes_vec(), - revert: Some(match slot { - reth::revm::db::RevertToSlot::Some(value) => { - proto::revert_to_slot::Revert::Some(value.to_le_bytes_vec()) - } - reth::revm::db::RevertToSlot::Destroyed => { - proto::revert_to_slot::Revert::Destroyed(()) - } - }), - }) - }) - .collect::>()?, - previous_status: proto::AccountStatus::from(revert.previous_status) as i32, - wipe_storage: revert.wipe_storage, - }) - } -} - -impl TryFrom<&Option> for proto::Receipt { - type Error = eyre::Error; - - fn try_from(receipt: &Option) -> Result { - Ok(proto::Receipt { - receipt: Some( - receipt - .as_ref() - .map_or(eyre::Ok(proto::receipt::Receipt::Empty(())), |receipt| { - Ok(proto::receipt::Receipt::NonEmpty(receipt.try_into()?)) - })?, - ), - }) - } -} - -impl TryFrom<&reth::primitives::Receipt> for proto::NonEmptyReceipt { - type Error = eyre::Error; - - fn try_from(receipt: &reth::primitives::Receipt) -> Result { - Ok(proto::NonEmptyReceipt { - tx_type: match receipt.tx_type { - reth::primitives::TxType::Legacy => proto::TxType::Legacy, - reth::primitives::TxType::Eip2930 => proto::TxType::Eip2930, - reth::primitives::TxType::Eip1559 => proto::TxType::Eip1559, - reth::primitives::TxType::Eip4844 => proto::TxType::Eip4844, - #[cfg(feature = "optimism")] - reth::primitives::TxType::Deposit => { - eyre::bail!("deposit transaction not supported") - } - } as i32, - success: receipt.success, - cumulative_gas_used: receipt.cumulative_gas_used, - logs: receipt - .logs - .iter() - .map(|log| proto::Log { - address: log.address.to_vec(), - data: Some(proto::LogData { - topics: log.data.topics().iter().map(|topic| topic.to_vec()).collect(), - data: log.data.data.to_vec(), - }), - }) - .collect(), - }) - } -} - -impl TryFrom<&proto::ExExNotification> for reth_exex::ExExNotification { - type Error = eyre::Error; - - fn try_from(notification: &proto::ExExNotification) -> Result { - Ok(match notification.notification.as_ref().ok_or_eyre("no notification")? { - proto::ex_ex_notification::Notification::ChainCommitted(proto::ChainCommitted { - new, - }) => reth_exex::ExExNotification::ChainCommitted { - new: Arc::new(new.as_ref().ok_or_eyre("no new chain")?.try_into()?), - }, - proto::ex_ex_notification::Notification::ChainReorged(proto::ChainReorged { - old, - new, - }) => reth_exex::ExExNotification::ChainReorged { - old: Arc::new(old.as_ref().ok_or_eyre("no old chain")?.try_into()?), - new: Arc::new(new.as_ref().ok_or_eyre("no new chain")?.try_into()?), - }, - proto::ex_ex_notification::Notification::ChainReverted(proto::ChainReverted { - old, - }) => reth_exex::ExExNotification::ChainReverted { - old: Arc::new(old.as_ref().ok_or_eyre("no old chain")?.try_into()?), - }, - }) - } -} - -impl TryFrom<&proto::Chain> for reth::providers::Chain { - type Error = eyre::Error; - - fn try_from(chain: &proto::Chain) -> Result { - let execution_outcome = - chain.execution_outcome.as_ref().ok_or_eyre("no execution outcome")?; - let bundle = execution_outcome.bundle.as_ref().ok_or_eyre("no bundle")?; - Ok(reth::providers::Chain::new( - chain.blocks.iter().map(TryInto::try_into).collect::>>()?, - reth::providers::ExecutionOutcome { - bundle: reth::revm::db::BundleState { - state: bundle - .state - .iter() - .map(TryInto::try_into) - .collect::>()?, - contracts: bundle - .contracts - .iter() - .map(|contract| { - Ok(( - B256::try_from(contract.hash.as_slice())?, - contract.bytecode.as_ref().ok_or_eyre("no bytecode")?.try_into()?, - )) - }) - .collect::>()?, - reverts: reth::revm::db::states::reverts::Reverts::new( - bundle - .reverts - .iter() - .map(|block_reverts| { - block_reverts - .reverts - .iter() - .map(TryInto::try_into) - .collect::>() - }) - .collect::>()?, - ), - state_size: bundle.state_size as usize, - reverts_size: bundle.reverts_size as usize, - }, - receipts: reth::primitives::Receipts::from_iter( - execution_outcome - .receipts - .iter() - .map(|block_receipts| { - block_receipts - .receipts - .iter() - .map(TryInto::try_into) - .collect::>() - }) - .collect::>>()?, - ), - first_block: execution_outcome.first_block, - requests: Default::default(), - }, - None, - )) - } -} - -impl TryFrom<&proto::Block> for reth::primitives::SealedBlockWithSenders { - type Error = eyre::Error; - - fn try_from(block: &proto::Block) -> Result { - let sealed_header = block.header.as_ref().ok_or_eyre("no sealed header")?; - let header = sealed_header.header.as_ref().ok_or_eyre("no header")?.try_into()?; - let sealed_header = reth::primitives::SealedHeader::new( - header, - BlockHash::try_from(sealed_header.hash.as_slice())?, - ); - - let transactions = block.body.iter().map(TryInto::try_into).collect::>()?; - let ommers = block.ommers.iter().map(TryInto::try_into).collect::>()?; - let senders = block - .senders - .iter() - .map(|sender| Address::try_from(sender.as_slice())) - .collect::>()?; - - reth::primitives::SealedBlockWithSenders::new( - reth::primitives::SealedBlock::new( - sealed_header, - reth::primitives::BlockBody { - transactions, - ommers, - withdrawals: Default::default(), - requests: Default::default(), - }, - ), - senders, - ) - .ok_or_eyre("senders do not match transactions") - } -} - -impl TryFrom<&proto::Header> for reth::primitives::Header { - type Error = eyre::Error; - - fn try_from(header: &proto::Header) -> Result { - Ok(reth::primitives::Header { - parent_hash: B256::try_from(header.parent_hash.as_slice())?, - ommers_hash: B256::try_from(header.ommers_hash.as_slice())?, - beneficiary: Address::try_from(header.beneficiary.as_slice())?, - state_root: B256::try_from(header.state_root.as_slice())?, - transactions_root: B256::try_from(header.transactions_root.as_slice())?, - receipts_root: B256::try_from(header.receipts_root.as_slice())?, - withdrawals_root: header - .withdrawals_root - .as_ref() - .map(|root| B256::try_from(root.as_slice())) - .transpose()?, - logs_bloom: Bloom::try_from(header.logs_bloom.as_slice())?, - difficulty: U256::try_from_le_slice(&header.difficulty) - .ok_or_eyre("failed to parse difficulty")?, - number: header.number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - mix_hash: B256::try_from(header.mix_hash.as_slice())?, - nonce: header.nonce, - base_fee_per_gas: header.base_fee_per_gas, - blob_gas_used: header.blob_gas_used, - excess_blob_gas: header.excess_blob_gas, - parent_beacon_block_root: header - .parent_beacon_block_root - .as_ref() - .map(|root| B256::try_from(root.as_slice())) - .transpose()?, - requests_root: None, - extra_data: header.extra_data.as_slice().to_vec().into(), - }) - } -} - -impl TryFrom<&proto::Transaction> for reth::primitives::TransactionSigned { - type Error = eyre::Error; - - fn try_from(transaction: &proto::Transaction) -> Result { - let hash = TxHash::try_from(transaction.hash.as_slice())?; - let signature = transaction.signature.as_ref().ok_or_eyre("no signature")?; - let signature = reth::primitives::Signature { - r: U256::try_from_le_slice(signature.r.as_slice()).ok_or_eyre("failed to parse r")?, - s: U256::try_from_le_slice(signature.s.as_slice()).ok_or_eyre("failed to parse s")?, - odd_y_parity: signature.odd_y_parity, - }; - let transaction = match transaction.transaction.as_ref().ok_or_eyre("no transaction")? { - proto::transaction::Transaction::Legacy(proto::TransactionLegacy { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - input, - }) => reth::primitives::Transaction::Legacy(reth::primitives::TxLegacy { - chain_id: *chain_id, - nonce: *nonce, - gas_price: u128::from_le_bytes(gas_price.as_slice().try_into()?), - gas_limit: *gas_limit, - to: to.as_ref().ok_or_eyre("no to")?.try_into()?, - value: U256::try_from_le_slice(value.as_slice()) - .ok_or_eyre("failed to parse value")?, - input: input.to_vec().into(), - }), - proto::transaction::Transaction::Eip2930(proto::TransactionEip2930 { - chain_id, - nonce, - gas_price, - gas_limit, - to, - value, - access_list, - input, - }) => reth::primitives::Transaction::Eip2930(reth::primitives::TxEip2930 { - chain_id: *chain_id, - nonce: *nonce, - gas_price: u128::from_le_bytes(gas_price.as_slice().try_into()?), - gas_limit: *gas_limit, - to: to.as_ref().ok_or_eyre("no to")?.try_into()?, - value: U256::try_from_le_slice(value.as_slice()) - .ok_or_eyre("failed to parse value")?, - access_list: access_list - .iter() - .map(TryInto::try_into) - .collect::>>()? - .into(), - input: input.to_vec().into(), - }), - proto::transaction::Transaction::Eip1559(proto::TransactionEip1559 { - chain_id, - nonce, - gas_limit, - max_fee_per_gas, - max_priority_fee_per_gas, - to, - value, - access_list, - input, - }) => reth::primitives::Transaction::Eip1559(reth::primitives::TxEip1559 { - chain_id: *chain_id, - nonce: *nonce, - gas_limit: *gas_limit, - max_fee_per_gas: u128::from_le_bytes(max_fee_per_gas.as_slice().try_into()?), - max_priority_fee_per_gas: u128::from_le_bytes( - max_priority_fee_per_gas.as_slice().try_into()?, - ), - to: to.as_ref().ok_or_eyre("no to")?.try_into()?, - value: U256::try_from_le_slice(value.as_slice()) - .ok_or_eyre("failed to parse value")?, - access_list: access_list - .iter() - .map(TryInto::try_into) - .collect::>>()? - .into(), - input: input.to_vec().into(), - }), - proto::transaction::Transaction::Eip4844(proto::TransactionEip4844 { - chain_id, - nonce, - gas_limit, - max_fee_per_gas, - max_priority_fee_per_gas, - to, - value, - access_list, - blob_versioned_hashes, - max_fee_per_blob_gas, - input, - }) => reth::primitives::Transaction::Eip4844(reth::primitives::TxEip4844 { - chain_id: *chain_id, - nonce: *nonce, - gas_limit: *gas_limit, - max_fee_per_gas: u128::from_le_bytes(max_fee_per_gas.as_slice().try_into()?), - max_priority_fee_per_gas: u128::from_le_bytes( - max_priority_fee_per_gas.as_slice().try_into()?, - ), - placeholder: None, - to: Address::try_from(to.as_slice())?, - value: U256::try_from_le_slice(value.as_slice()) - .ok_or_eyre("failed to parse value")?, - access_list: access_list - .iter() - .map(TryInto::try_into) - .collect::>>()? - .into(), - blob_versioned_hashes: blob_versioned_hashes - .iter() - .map(|hash| B256::try_from(hash.as_slice())) - .collect::>()?, - max_fee_per_blob_gas: u128::from_le_bytes( - max_fee_per_blob_gas.as_slice().try_into()?, - ), - input: input.to_vec().into(), - }), - }; - - Ok(reth::primitives::TransactionSigned { hash, signature, transaction }) - } -} - -impl TryFrom<&proto::TxKind> for reth::primitives::TxKind { - type Error = eyre::Error; - - fn try_from(tx_kind: &proto::TxKind) -> Result { - Ok(match tx_kind.kind.as_ref().ok_or_eyre("no kind")? { - proto::tx_kind::Kind::Create(()) => reth::primitives::TxKind::Create, - proto::tx_kind::Kind::Call(address) => { - reth::primitives::TxKind::Call(Address::try_from(address.as_slice())?) - } - }) - } -} - -impl TryFrom<&proto::AccessListItem> for reth::primitives::AccessListItem { - type Error = eyre::Error; - - fn try_from(item: &proto::AccessListItem) -> Result { - Ok(reth::primitives::AccessListItem { - address: Address::try_from(item.address.as_slice())?, - storage_keys: item - .storage_keys - .iter() - .map(|key| B256::try_from(key.as_slice())) - .collect::>()?, - }) - } -} - -impl TryFrom<&proto::AccountInfo> for reth::revm::primitives::AccountInfo { - type Error = eyre::Error; - - fn try_from(account_info: &proto::AccountInfo) -> Result { - Ok(reth::revm::primitives::AccountInfo { - balance: U256::try_from_le_slice(account_info.balance.as_slice()) - .ok_or_eyre("failed to parse balance")?, - nonce: account_info.nonce, - code_hash: B256::try_from(account_info.code_hash.as_slice())?, - code: account_info.code.as_ref().map(TryInto::try_into).transpose()?, - }) - } -} - -impl TryFrom<&proto::Bytecode> for reth::revm::primitives::Bytecode { - type Error = eyre::Error; - - fn try_from(bytecode: &proto::Bytecode) -> Result { - Ok(match bytecode.bytecode.as_ref().ok_or_eyre("no bytecode")? { - proto::bytecode::Bytecode::LegacyRaw(code) => { - reth::revm::primitives::Bytecode::LegacyRaw(code.clone().into()) - } - proto::bytecode::Bytecode::LegacyAnalyzed(legacy_analyzed) => { - reth::revm::primitives::Bytecode::LegacyAnalyzed( - reth::revm::primitives::LegacyAnalyzedBytecode::new( - legacy_analyzed.bytecode.clone().into(), - legacy_analyzed.original_len as usize, - reth::revm::primitives::JumpTable::from_slice( - legacy_analyzed - .jump_table - .iter() - .map(|dest| *dest as u8) - .collect::>() - .as_slice(), - ), - ), - ) - } - }) - } -} - -impl From for reth::revm::db::AccountStatus { - fn from(status: proto::AccountStatus) -> Self { - match status { - proto::AccountStatus::LoadedNotExisting => { - reth::revm::db::AccountStatus::LoadedNotExisting - } - proto::AccountStatus::Loaded => reth::revm::db::AccountStatus::Loaded, - proto::AccountStatus::LoadedEmptyEip161 => { - reth::revm::db::AccountStatus::LoadedEmptyEIP161 - } - proto::AccountStatus::InMemoryChange => reth::revm::db::AccountStatus::InMemoryChange, - proto::AccountStatus::Changed => reth::revm::db::AccountStatus::Changed, - proto::AccountStatus::Destroyed => reth::revm::db::AccountStatus::Destroyed, - proto::AccountStatus::DestroyedChanged => { - reth::revm::db::AccountStatus::DestroyedChanged - } - proto::AccountStatus::DestroyedAgain => reth::revm::db::AccountStatus::DestroyedAgain, - } - } -} - -impl TryFrom<&proto::BundleAccount> for (Address, reth::revm::db::BundleAccount) { - type Error = eyre::Error; - - fn try_from(account: &proto::BundleAccount) -> Result { - Ok(( - Address::try_from(account.address.as_slice())?, - reth::revm::db::BundleAccount { - info: account.info.as_ref().map(TryInto::try_into).transpose()?, - original_info: account.original_info.as_ref().map(TryInto::try_into).transpose()?, - storage: account - .storage - .iter() - .map(|slot| { - Ok(( - U256::try_from_le_slice(slot.key.as_slice()) - .ok_or_eyre("failed to parse key")?, - reth::revm::db::states::StorageSlot { - previous_or_original_value: U256::try_from_le_slice( - slot.previous_or_original_value.as_slice(), - ) - .ok_or_eyre("failed to parse previous or original value")?, - present_value: U256::try_from_le_slice( - slot.present_value.as_slice(), - ) - .ok_or_eyre("failed to parse present value")?, - }, - )) - }) - .collect::>()?, - status: proto::AccountStatus::try_from(account.status)?.into(), - }, - )) - } -} - -impl TryFrom<&proto::Revert> for (Address, reth::revm::db::states::reverts::AccountRevert) { - type Error = eyre::Error; - - fn try_from(revert: &proto::Revert) -> Result { - Ok(( - Address::try_from(revert.address.as_slice())?, - reth::revm::db::states::reverts::AccountRevert { - account: match revert - .account - .as_ref() - .ok_or_eyre("no revert account")? - .revert - .as_ref() - .ok_or_eyre("no revert account revert")? - { - proto::account_info_revert::Revert::DoNothing(()) => { - reth::revm::db::states::reverts::AccountInfoRevert::DoNothing - } - proto::account_info_revert::Revert::DeleteIt(()) => { - reth::revm::db::states::reverts::AccountInfoRevert::DeleteIt - } - proto::account_info_revert::Revert::RevertTo(account_info) => { - reth::revm::db::states::reverts::AccountInfoRevert::RevertTo( - account_info.try_into()?, - ) - } - }, - storage: revert - .storage - .iter() - .map(|slot| { - Ok(( - U256::try_from_le_slice(slot.key.as_slice()) - .ok_or_eyre("failed to parse slot key")?, - match slot.revert.as_ref().ok_or_eyre("no slot revert")? { - proto::revert_to_slot::Revert::Some(value) => { - reth::revm::db::states::reverts::RevertToSlot::Some( - U256::try_from_le_slice(value.as_slice()) - .ok_or_eyre("failed to parse slot revert")?, - ) - } - proto::revert_to_slot::Revert::Destroyed(()) => { - reth::revm::db::states::reverts::RevertToSlot::Destroyed - } - }, - )) - }) - .collect::>()?, - previous_status: proto::AccountStatus::try_from(revert.previous_status)?.into(), - wipe_storage: revert.wipe_storage, - }, - )) - } -} - -impl TryFrom<&proto::Receipt> for Option { - type Error = eyre::Error; - - fn try_from(receipt: &proto::Receipt) -> Result { - Ok(match receipt.receipt.as_ref().ok_or_eyre("no receipt")? { - proto::receipt::Receipt::Empty(()) => None, - proto::receipt::Receipt::NonEmpty(receipt) => Some(receipt.try_into()?), - }) - } -} - -impl TryFrom<&proto::NonEmptyReceipt> for reth::primitives::Receipt { - type Error = eyre::Error; - - fn try_from(receipt: &proto::NonEmptyReceipt) -> Result { - Ok(reth::primitives::Receipt { - tx_type: match proto::TxType::try_from(receipt.tx_type)? { - proto::TxType::Legacy => reth::primitives::TxType::Legacy, - proto::TxType::Eip2930 => reth::primitives::TxType::Eip2930, - proto::TxType::Eip1559 => reth::primitives::TxType::Eip1559, - proto::TxType::Eip4844 => reth::primitives::TxType::Eip4844, - }, - success: receipt.success, - cumulative_gas_used: receipt.cumulative_gas_used, - logs: receipt - .logs - .iter() - .map(|log| { - let data = log.data.as_ref().ok_or_eyre("no log data")?; - Ok(reth::primitives::Log { - address: Address::try_from(log.address.as_slice())?, - data: reth::primitives::LogData::new_unchecked( - data.topics - .iter() - .map(|topic| Ok(B256::try_from(topic.as_slice())?)) - .collect::>()?, - data.data.clone().into(), - ), - }) - }) - .collect::>()?, - #[cfg(feature = "optimism")] - deposit_nonce: None, - #[cfg(feature = "optimism")] - deposit_receipt_version: None, - }) - } -} diff --git a/examples/exex/remote/src/lib.rs b/examples/exex/remote/src/lib.rs deleted file mode 100644 index 9b8aa5781a8f..000000000000 --- a/examples/exex/remote/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod codec; -pub mod proto { - tonic::include_proto!("exex"); -} diff --git a/examples/exex/rollup/src/execution.rs b/examples/exex/rollup/src/execution.rs index cc5b716bdc09..2f755183fab4 100644 --- a/examples/exex/rollup/src/execution.rs +++ b/examples/exex/rollup/src/execution.rs @@ -12,8 +12,8 @@ use reth_primitives::{ keccak256, revm::env::fill_tx_env, revm_primitives::{CfgEnvWithHandlerCfg, EVMError, ExecutionResult, ResultAndState}, - Address, Block, BlockWithSenders, Bytes, Hardfork, Header, Receipt, TransactionSigned, TxType, - B256, U256, + Address, Block, BlockWithSenders, Bytes, EthereumHardfork, Header, Receipt, TransactionSigned, + TxType, B256, U256, }; use reth_revm::{ db::{states::bundle_state::BundleRetention, BundleState}, @@ -69,16 +69,17 @@ fn construct_header(db: &Database, header: &RollupContract::BlockHeader) -> eyre let block_number = u64::try_from(header.sequence)?; // Calculate base fee per gas for EIP-1559 transactions - let base_fee_per_gas = if CHAIN_SPEC.fork(Hardfork::London).transitions_at_block(block_number) { - constants::EIP1559_INITIAL_BASE_FEE - } else { - parent_block - .as_ref() - .ok_or(eyre::eyre!("parent block not found"))? - .header - .next_block_base_fee(CHAIN_SPEC.base_fee_params_at_block(block_number)) - .ok_or(eyre::eyre!("failed to calculate base fee"))? - }; + let base_fee_per_gas = + if CHAIN_SPEC.fork(EthereumHardfork::London).transitions_at_block(block_number) { + constants::EIP1559_INITIAL_BASE_FEE + } else { + parent_block + .as_ref() + .ok_or(eyre::eyre!("parent block not found"))? + .header + .next_block_base_fee(CHAIN_SPEC.base_fee_params_at_block(block_number)) + .ok_or(eyre::eyre!("failed to calculate base fee"))? + }; // Construct header Ok(Header { @@ -103,7 +104,7 @@ fn configure_evm<'a>( .build(), ); evm.db_mut().set_state_clear_flag( - CHAIN_SPEC.fork(Hardfork::SpuriousDragon).active_at_block(header.number), + CHAIN_SPEC.fork(EthereumHardfork::SpuriousDragon).active_at_block(header.number), ); let mut cfg = CfgEnvWithHandlerCfg::new_with_spec_id(evm.cfg().clone(), evm.spec_id()); diff --git a/examples/manual-p2p/src/main.rs b/examples/manual-p2p/src/main.rs index 2b89b5539d4f..c23802d26e51 100644 --- a/examples/manual-p2p/src/main.rs +++ b/examples/manual-p2p/src/main.rs @@ -10,15 +10,15 @@ use std::time::Duration; use futures::StreamExt; use once_cell::sync::Lazy; -use reth_chainspec::{net::mainnet_nodes, Chain, MAINNET}; +use reth_chainspec::{Chain, MAINNET}; use reth_discv4::{DiscoveryUpdate, Discv4, Discv4ConfigBuilder, DEFAULT_DISCOVERY_ADDRESS}; use reth_ecies::stream::ECIESStream; use reth_eth_wire::{ EthMessage, EthStream, HelloMessage, P2PStream, Status, UnauthedEthStream, UnauthedP2PStream, }; use reth_network::config::rng_secret_key; -use reth_network_peers::{pk2id, NodeRecord}; -use reth_primitives::{Hardfork, Head, MAINNET_GENESIS_HASH}; +use reth_network_peers::{mainnet_nodes, pk2id, NodeRecord}; +use reth_primitives::{EthereumHardfork, Head, MAINNET_GENESIS_HASH}; use secp256k1::{SecretKey, SECP256K1}; use tokio::net::TcpStream; @@ -95,14 +95,14 @@ async fn handshake_p2p( // Perform a ETH Wire handshake with a peer async fn handshake_eth(p2p_stream: AuthedP2PStream) -> eyre::Result<(AuthedEthStream, Status)> { let fork_filter = MAINNET.fork_filter(Head { - timestamp: MAINNET.fork(Hardfork::Shanghai).as_timestamp().unwrap(), + timestamp: MAINNET.fork(EthereumHardfork::Shanghai).as_timestamp().unwrap(), ..Default::default() }); let status = Status::builder() .chain(Chain::mainnet()) .genesis(MAINNET_GENESIS_HASH) - .forkid(MAINNET.hardfork_fork_id(Hardfork::Shanghai).unwrap()) + .forkid(MAINNET.hardfork_fork_id(EthereumHardfork::Shanghai).unwrap()) .build(); let status = Status { version: p2p_stream.shared_capabilities().eth()?.version(), ..status }; diff --git a/examples/polygon-p2p/src/chain_cfg.rs b/examples/polygon-p2p/src/chain_cfg.rs index b178d13499d7..92256a1be1c3 100644 --- a/examples/polygon-p2p/src/chain_cfg.rs +++ b/examples/polygon-p2p/src/chain_cfg.rs @@ -1,8 +1,10 @@ -use reth_chainspec::{BaseFeeParams, Chain, ChainSpec, ForkCondition, Hardfork}; +use reth_chainspec::{ + BaseFeeParams, Chain, ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition, +}; use reth_discv4::NodeRecord; use reth_primitives::{b256, Head, B256}; -use std::{collections::BTreeMap, sync::Arc}; +use std::sync::Arc; const SHANGAI_BLOCK: u64 = 50523000; @@ -15,13 +17,13 @@ pub(crate) fn polygon_chain_spec() -> Arc { genesis: serde_json::from_str(include_str!("./genesis.json")).expect("deserialize genesis"), genesis_hash: Some(GENESIS), paris_block_and_final_difficulty: None, - hardforks: BTreeMap::from([ - (Hardfork::Petersburg, ForkCondition::Block(0)), - (Hardfork::Istanbul, ForkCondition::Block(3395000)), - (Hardfork::MuirGlacier, ForkCondition::Block(3395000)), - (Hardfork::Berlin, ForkCondition::Block(14750000)), - (Hardfork::London, ForkCondition::Block(23850000)), - (Hardfork::Shanghai, ForkCondition::Block(SHANGAI_BLOCK)), + hardforks: ChainHardforks::new(vec![ + (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), + (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(3395000)), + (EthereumHardfork::MuirGlacier.boxed(), ForkCondition::Block(3395000)), + (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(14750000)), + (EthereumHardfork::London.boxed(), ForkCondition::Block(23850000)), + (EthereumHardfork::Shanghai.boxed(), ForkCondition::Block(SHANGAI_BLOCK)), ]), deposit_contract: None, base_fee_params: reth_chainspec::BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), diff --git a/examples/rpc-db/src/main.rs b/examples/rpc-db/src/main.rs index 96863d4f009f..90447790561f 100644 --- a/examples/rpc-db/src/main.rs +++ b/examples/rpc-db/src/main.rs @@ -17,7 +17,7 @@ use reth::{ providers::{BlockchainProvider, StaticFileProvider}, ProviderFactory, }, - utils::db::open_db_read_only, + utils::open_db_read_only, }; use reth_chainspec::ChainSpecBuilder; use reth_db::mdbx::DatabaseArguments; diff --git a/examples/rpc-db/src/myrpc_ext.rs b/examples/rpc-db/src/myrpc_ext.rs index d1898b81cb15..e38b6fc24d37 100644 --- a/examples/rpc-db/src/myrpc_ext.rs +++ b/examples/rpc-db/src/myrpc_ext.rs @@ -3,7 +3,7 @@ use reth::{primitives::Block, providers::BlockReaderIdExt}; // Rpc related imports use jsonrpsee::proc_macros::rpc; -use reth::rpc::eth::error::EthResult; +use reth::rpc::server_types::eth::EthResult; /// trait interface for a custom rpc namespace: `MyRpc` /// diff --git a/examples/stateful-precompile/src/main.rs b/examples/stateful-precompile/src/main.rs index 8eaecb29ac73..adca439d764a 100644 --- a/examples/stateful-precompile/src/main.rs +++ b/examples/stateful-precompile/src/main.rs @@ -133,8 +133,8 @@ impl StatefulPrecompileMut for WrappedPrecompile { } impl ConfigureEvmEnv for MyEvmConfig { - fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { - EthEvmConfig::fill_tx_env(tx_env, transaction, sender) + fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { + EthEvmConfig::default().fill_tx_env(tx_env, transaction, sender) } fn fill_cfg_env( diff --git a/testing/ef-tests/src/cases/blockchain_test.rs b/testing/ef-tests/src/cases/blockchain_test.rs index 87c3b8df1d8f..664344a391cc 100644 --- a/testing/ef-tests/src/cases/blockchain_test.rs +++ b/testing/ef-tests/src/cases/blockchain_test.rs @@ -1,9 +1,6 @@ //! Test runners for `BlockchainTests` in -use crate::{ - models::{BlockchainTest, ForkSpec}, - Case, Error, Suite, -}; +use crate::models::BlockchainTest; use alloy_rlp::Decodable; use rayon::iter::{ParallelBridge, ParallelIterator}; use reth_db::test_utils::{create_test_rw_db, create_test_static_files_dir};